paul@206 | 1 | /* |
paul@206 | 2 | * AIC support for the X1600. |
paul@206 | 3 | * |
paul@206 | 4 | * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk> |
paul@206 | 5 | * |
paul@206 | 6 | * This program is free software; you can redistribute it and/or |
paul@206 | 7 | * modify it under the terms of the GNU General Public License as |
paul@206 | 8 | * published by the Free Software Foundation; either version 2 of |
paul@206 | 9 | * the License, or (at your option) any later version. |
paul@206 | 10 | * |
paul@206 | 11 | * This program is distributed in the hope that it will be useful, |
paul@206 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
paul@206 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
paul@206 | 14 | * GNU General Public License for more details. |
paul@206 | 15 | * |
paul@206 | 16 | * You should have received a copy of the GNU General Public License |
paul@206 | 17 | * along with this program; if not, write to the Free Software |
paul@206 | 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
paul@206 | 19 | * Boston, MA 02110-1301, USA |
paul@206 | 20 | */ |
paul@206 | 21 | |
paul@206 | 22 | #include <l4/devices/aic-x1600.h> |
paul@206 | 23 | #include <l4/devices/dma.h> |
paul@206 | 24 | #include <l4/devices/hw_mmio_register_block.h> |
paul@206 | 25 | |
paul@206 | 26 | #include <l4/sys/icu.h> |
paul@206 | 27 | #include <l4/util/util.h> |
paul@206 | 28 | |
paul@206 | 29 | #include <stdio.h> |
paul@206 | 30 | |
paul@206 | 31 | enum Regs |
paul@206 | 32 | { |
paul@206 | 33 | Aic_config = 0x000, // AICFR |
paul@206 | 34 | Aic_control = 0x004, // AICCR |
paul@206 | 35 | Aic_i2s_msb_control = 0x010, // I2SCR |
paul@206 | 36 | Aic_fifo_status = 0x014, // AICSR |
paul@206 | 37 | Aic_i2s_msb_status = 0x01c, // I2SSR |
paul@206 | 38 | Aic_i2s_msb_divider = 0x030, // I2SDIV |
paul@206 | 39 | Aic_fifo_data = 0x034, // AICDR |
paul@206 | 40 | Aic_loop_data = 0x038, // AICLR |
paul@206 | 41 | Aic_tfifo_loop = 0x03c, // AICTFLR |
paul@206 | 42 | }; |
paul@206 | 43 | |
paul@206 | 44 | enum Aic_config_bits : unsigned |
paul@206 | 45 | { |
paul@206 | 46 | Aic_enable_big_endian = 0x1000, // MSB |
paul@206 | 47 | Aic_independent_clock = 0x0100, // DMODE |
paul@206 | 48 | Aic_shared_clock = 0x0000, // DMODE |
paul@206 | 49 | Aic_last_sample_uflow = 0x0040, // LSMP |
paul@206 | 50 | Aic_select_i2s_msb = 0x0010, // AUSEL |
paul@206 | 51 | Aic_reset = 0x0008, // RST |
paul@206 | 52 | Aic_tmaster = 0x0004, // TMASTER |
paul@206 | 53 | Aic_rmaster = 0x0002, // RMASTER |
paul@206 | 54 | Aic_enable = 0x0001, // ENB |
paul@206 | 55 | |
paul@206 | 56 | Aic_rfifo_thold_bit = 24, // RFTH |
paul@206 | 57 | Aic_tfifo_thold_bit = 16, // TFTH |
paul@206 | 58 | }; |
paul@206 | 59 | |
paul@206 | 60 | enum Aic_fifo_limits : unsigned |
paul@206 | 61 | { |
paul@206 | 62 | Aic_rfifo_max = 15, |
paul@206 | 63 | Aic_tfifo_max = 31, |
paul@206 | 64 | }; |
paul@206 | 65 | |
paul@206 | 66 | enum Aic_control_bits : unsigned |
paul@206 | 67 | { |
paul@206 | 68 | Aic_enable_tfifo_loop_overrun = 0x80000000, // ETFLOR |
paul@206 | 69 | Aic_enable_tfifo_loop_request = 0x40000000, // ETFLS |
paul@206 | 70 | Aic_packed_data = 0x10000000, // PACK16 |
paul@206 | 71 | |
paul@206 | 72 | Aic_channel_number_mask = 0x07000000, // CHANNEL |
paul@206 | 73 | Aic_channel_mono = 0x00000000, |
paul@206 | 74 | Aic_channel_stereo = 0x01000000, |
paul@206 | 75 | |
paul@206 | 76 | Aic_enable_tfifo_loop = 0x00800000, // ETFL |
paul@206 | 77 | Aic_enable_tfifo_loop_dma = 0x00400000, // TLDMS |
paul@206 | 78 | |
paul@206 | 79 | Aic_output_size_mask = 0x00380000, // OSS |
paul@206 | 80 | Aic_output_size_8bit = 0x00000000, // 0 |
paul@206 | 81 | Aic_output_size_16bit = 0x00080000, // 1 |
paul@206 | 82 | Aic_output_size_18bit = 0x00100000, // 2 |
paul@206 | 83 | Aic_output_size_20bit = 0x00180000, // 3 |
paul@206 | 84 | Aic_output_size_24bit = 0x00200000, // 4 |
paul@206 | 85 | |
paul@206 | 86 | Aic_input_size_mask = 0x00070000, // ISS |
paul@206 | 87 | Aic_input_size_8bit = 0x00000000, // 0 |
paul@206 | 88 | Aic_input_size_16bit = 0x00010000, // 1 |
paul@206 | 89 | Aic_input_size_18bit = 0x00020000, // 2 |
paul@206 | 90 | Aic_input_size_20bit = 0x00030000, // 3 |
paul@206 | 91 | Aic_input_size_24bit = 0x00040000, // 4 |
paul@206 | 92 | |
paul@206 | 93 | Aic_enable_recv_dma = 0x00008000, // RDMS |
paul@206 | 94 | Aic_enable_trans_dma = 0x00004000, // TDMS |
paul@206 | 95 | |
paul@206 | 96 | Aic_mono_control_mask = 0x00003000, // MONOCTR |
paul@206 | 97 | Aic_mono_control_both = 0x00000000, // 0 |
paul@206 | 98 | Aic_mono_control_right = 0x00001000, // 1 |
paul@206 | 99 | Aic_mono_control_left = 0x00002000, // 2 |
paul@206 | 100 | |
paul@206 | 101 | Aic_trans_byte_swap = 0x00000400, // ENDSW |
paul@206 | 102 | Aic_tfifo_flush = 0x00000100, // TFLUSH |
paul@206 | 103 | Aic_rfifo_flush = 0x00000080, // RFLUSH |
paul@206 | 104 | Aic_enable_rfifo_overrun = 0x00000040, // EROR |
paul@206 | 105 | Aic_enable_tfifo_underrun = 0x00000020, // ETUR |
paul@206 | 106 | Aic_enable_rfifo_request = 0x00000010, // ERFS |
paul@206 | 107 | Aic_enable_tfifo_request = 0x00000008, // ETFS |
paul@206 | 108 | Aic_enable_loopback = 0x00000004, // ENLBF |
paul@206 | 109 | Aic_enable_playback = 0x00000002, // ERPL |
paul@206 | 110 | Aic_enable_record = 0x00000001, // EREC |
paul@206 | 111 | }; |
paul@206 | 112 | |
paul@206 | 113 | enum Aic_i2s_msb_control_bits : unsigned |
paul@206 | 114 | { |
paul@206 | 115 | Aic_i2s_msb_right_first = 0x20000, // RFIRST |
paul@206 | 116 | Aic_i2s_msb_switch_lr = 0x10000, // SWLH |
paul@206 | 117 | Aic_select_msb_justified = 0x00001, // AMSL |
paul@206 | 118 | Aic_select_i2s = 0x00000, // AMSL |
paul@206 | 119 | }; |
paul@206 | 120 | |
paul@206 | 121 | enum Aic_fifo_status_bits : unsigned |
paul@206 | 122 | { |
paul@206 | 123 | Aic_rfifo_overrun = 0x40, // ROR |
paul@206 | 124 | Aic_tfifo_underrun = 0x20, // TUR |
paul@206 | 125 | Aic_rfifo_request = 0x10, // RFS |
paul@206 | 126 | Aic_tfifo_request = 0x08, // TFS |
paul@206 | 127 | Aic_tfifo_loop_overrun = 0x04, // TFLOR |
paul@206 | 128 | Aic_tfifo_loop_request = 0x02, // TFLS |
paul@206 | 129 | |
paul@206 | 130 | Aic_rfifo_level_bit = 24, // RFL |
paul@206 | 131 | Aic_tfifo_loop_level_bit = 15, // TFLL |
paul@206 | 132 | Aic_tfifo_level_bit = 8, // TFL |
paul@206 | 133 | }; |
paul@206 | 134 | |
paul@206 | 135 | enum Aic_i2s_msb_status_bits : unsigned |
paul@206 | 136 | { |
paul@206 | 137 | Aic_trans_channel_busy = 0x20, // CHBSY |
paul@206 | 138 | Aic_trans_busy = 0x10, // TBSY |
paul@206 | 139 | Aic_recv_busy = 0x08, // RBSY |
paul@206 | 140 | Aic_busy = 0x04, // BSY |
paul@206 | 141 | }; |
paul@206 | 142 | |
paul@206 | 143 | enum Aic_i2s_msb_divider_bits : unsigned |
paul@206 | 144 | { |
paul@206 | 145 | Aic_recv_divider_mask = 0x1ff0000, // RDIV |
paul@206 | 146 | Aic_trans_divider_mask = 0x00001ff, // TDIV |
paul@206 | 147 | |
paul@206 | 148 | Aic_recv_divider_bit = 16, // RDIV |
paul@206 | 149 | Aic_trans_divider_bit = 0, // TDIV |
paul@206 | 150 | }; |
paul@206 | 151 | |
paul@206 | 152 | enum Aic_i2s_msb_divider_limits : unsigned |
paul@206 | 153 | { |
paul@206 | 154 | Aic_recv_divider_limit = 0x1ff, // RDIV |
paul@206 | 155 | Aic_trans_divider_limit = 0x1ff, // TDIV |
paul@206 | 156 | }; |
paul@206 | 157 | |
paul@206 | 158 | enum Aic_fifo_data_limits : unsigned |
paul@206 | 159 | { |
paul@206 | 160 | Aic_fifo_data_limit = 0xffffff, // DATA |
paul@206 | 161 | }; |
paul@206 | 162 | |
paul@206 | 163 | enum Aic_loop_data_limits : unsigned |
paul@206 | 164 | { |
paul@206 | 165 | Aic_loop_data_limit = 0xffffff, // DATALP |
paul@206 | 166 | }; |
paul@206 | 167 | |
paul@206 | 168 | enum Aic_tfifo_loop_limits : unsigned |
paul@206 | 169 | { |
paul@206 | 170 | Aic_tfifo_loop_limit = 0xf, // TFLTH |
paul@206 | 171 | }; |
paul@206 | 172 | |
paul@206 | 173 | |
paul@206 | 174 | |
paul@206 | 175 | // Initialise a channel. |
paul@206 | 176 | |
paul@206 | 177 | Aic_x1600_channel::Aic_x1600_channel(l4_addr_t aic_start, l4_addr_t start, |
paul@206 | 178 | enum Clock_identifiers clock_rx, |
paul@206 | 179 | enum Clock_identifiers clock_tx, |
paul@206 | 180 | Cpm_x1600_chip *cpm, |
paul@206 | 181 | Dma_x1600_channel *dma) |
paul@206 | 182 | : _aic_start(aic_start), _clock_rx(clock_rx), _clock_tx(clock_tx), _cpm(cpm), _dma(dma) |
paul@206 | 183 | { |
paul@206 | 184 | _regs = new Hw::Mmio_register_block<32>(start); |
paul@206 | 185 | _cpm->start_clock(clock_rx); |
paul@206 | 186 | _cpm->start_clock(clock_tx); |
paul@206 | 187 | config(); |
paul@206 | 188 | } |
paul@206 | 189 | |
paul@206 | 190 | /* |
paul@206 | 191 | I2S configuration. |
paul@206 | 192 | |
paul@206 | 193 | The system clock (SYS_CLK) for I2S in the X1600 is issued by the X1600 as the |
paul@206 | 194 | master/system clock (MCLK) externally to the DAC/codec. |
paul@206 | 195 | |
paul@206 | 196 | SYS_CLK is divided to obtain BIT_CLK which is issued by the X1600 as BCLK. |
paul@206 | 197 | This is dependent on the actual sample rate. |
paul@206 | 198 | |
paul@206 | 199 | LRCLK indicates the left/right channel for the issued data. |
paul@206 | 200 | |
paul@206 | 201 | Where clocks (MCLK, BCLK, LRCLK) are issued only by the X1600, share mode |
paul@206 | 202 | is used. Otherwise, independent (6-line) mode is used. |
paul@206 | 203 | |
paul@206 | 204 | To drive the MAX9835A, no MCLK is needed. |
paul@206 | 205 | |
paul@206 | 206 | Initialisation involves the following: |
paul@206 | 207 | |
paul@206 | 208 | - Configure MCLK, BCLK, LRCLK as outputs |
paul@206 | 209 | - Select I2S in Aic_i2s_msb_control (deselecting Aic_select_msb_justified) |
paul@206 | 210 | - Set master mode in Aic_config (Aic_tmaster, also Aic_rmaster if independent |
paul@206 | 211 | mode is used) |
paul@206 | 212 | - Set the dividers in Aic_i2s_msb_divider for BCLK using the configured I2S |
paul@206 | 213 | clock frequency |
paul@206 | 214 | - Perform a reset by writing to Aic_reset in Aic_config, if necessary |
paul@206 | 215 | - The MAX9835A may not need any configuration using I2C or some other bus |
paul@206 | 216 | */ |
paul@206 | 217 | |
paul@206 | 218 | void |
paul@206 | 219 | Aic_x1600_channel::config() |
paul@206 | 220 | { |
paul@206 | 221 | // NOTE: Setting transmit request threshold to 31 (15 * 2 + 1). |
paul@206 | 222 | |
paul@206 | 223 | printf("config = %08x\n", (uint32_t) _regs[Aic_config]); |
paul@206 | 224 | |
paul@206 | 225 | _regs[Aic_config] = Aic_shared_clock | Aic_select_i2s_msb | Aic_reset | |
paul@206 | 226 | Aic_tmaster | Aic_enable | (15 << Aic_tfifo_thold_bit); |
paul@206 | 227 | |
paul@206 | 228 | _regs[Aic_i2s_msb_control] = Aic_select_i2s; |
paul@206 | 229 | |
paul@206 | 230 | printf("config = %08x\n", (uint32_t) _regs[Aic_config]); |
paul@206 | 231 | } |
paul@206 | 232 | |
paul@206 | 233 | /* |
paul@206 | 234 | Clock configuration: |
paul@206 | 235 | |
paul@206 | 236 | - SYS_CLK (MCLK) is Clock_i2s0_tx (or Clock_i2s0_rx) |
paul@206 | 237 | - BIT_CLK (BCLK) is MCLK divided by the appropriate AIC/I2S divider |
paul@206 | 238 | - BCLK should be 64 times the sample rate according to the manual |
paul@206 | 239 | |
paul@206 | 240 | This suggests that the X1600 always produces data for two 32-bit channels |
paul@206 | 241 | regardless of the input data characteristics. |
paul@206 | 242 | */ |
paul@206 | 243 | |
paul@206 | 244 | void |
paul@206 | 245 | Aic_x1600_channel::set_divider(uint32_t divider, uint32_t mask, uint32_t limit, |
paul@206 | 246 | int bit) |
paul@206 | 247 | { |
paul@206 | 248 | if (divider <= limit) |
paul@206 | 249 | _regs[Aic_i2s_msb_divider] = (_regs[Aic_i2s_msb_divider] & ~mask) | |
paul@206 | 250 | (divider << bit); |
paul@206 | 251 | } |
paul@206 | 252 | |
paul@206 | 253 | void |
paul@206 | 254 | Aic_x1600_channel::set_recv_frequency(uint32_t sample_rate) |
paul@206 | 255 | { |
paul@206 | 256 | set_divider(_cpm->get_frequency(_clock_rx) / (sample_rate * 32 * 2), |
paul@206 | 257 | Aic_recv_divider_mask, Aic_recv_divider_limit, Aic_recv_divider_bit); |
paul@206 | 258 | } |
paul@206 | 259 | |
paul@206 | 260 | void |
paul@206 | 261 | Aic_x1600_channel::set_trans_frequency(uint32_t sample_rate) |
paul@206 | 262 | { |
paul@206 | 263 | printf("tx %d / (freq %d * %d * 2) = %d vs. %d\n", _cpm->get_frequency(_clock_tx), |
paul@206 | 264 | sample_rate, 32, |
paul@206 | 265 | _cpm->get_frequency(_clock_tx) / (sample_rate * 32 * 2), |
paul@206 | 266 | Aic_trans_divider_limit); |
paul@206 | 267 | |
paul@206 | 268 | set_divider(_cpm->get_frequency(_clock_tx) / (sample_rate * 32 * 2), |
paul@206 | 269 | Aic_trans_divider_mask, Aic_trans_divider_limit, Aic_trans_divider_bit); |
paul@206 | 270 | } |
paul@206 | 271 | |
paul@206 | 272 | uint32_t |
paul@206 | 273 | Aic_x1600_channel::encode_input_size(uint8_t sample_size) |
paul@206 | 274 | { |
paul@206 | 275 | switch (sample_size) |
paul@206 | 276 | { |
paul@206 | 277 | case 16: |
paul@206 | 278 | return Aic_input_size_16bit; |
paul@206 | 279 | |
paul@206 | 280 | case 18: |
paul@206 | 281 | return Aic_input_size_18bit; |
paul@206 | 282 | |
paul@206 | 283 | case 20: |
paul@206 | 284 | return Aic_input_size_20bit; |
paul@206 | 285 | |
paul@206 | 286 | case 24: |
paul@206 | 287 | return Aic_input_size_24bit; |
paul@206 | 288 | |
paul@206 | 289 | default: |
paul@206 | 290 | return Aic_input_size_8bit; |
paul@206 | 291 | } |
paul@206 | 292 | } |
paul@206 | 293 | |
paul@206 | 294 | uint32_t |
paul@206 | 295 | Aic_x1600_channel::encode_output_size(uint8_t sample_size) |
paul@206 | 296 | { |
paul@206 | 297 | switch (sample_size) |
paul@206 | 298 | { |
paul@206 | 299 | case 16: |
paul@206 | 300 | return Aic_output_size_16bit; |
paul@206 | 301 | |
paul@206 | 302 | case 18: |
paul@206 | 303 | return Aic_output_size_18bit; |
paul@206 | 304 | |
paul@206 | 305 | case 20: |
paul@206 | 306 | return Aic_output_size_20bit; |
paul@206 | 307 | |
paul@206 | 308 | case 24: |
paul@206 | 309 | return Aic_output_size_24bit; |
paul@206 | 310 | |
paul@206 | 311 | default: |
paul@206 | 312 | return Aic_output_size_8bit; |
paul@206 | 313 | } |
paul@206 | 314 | } |
paul@206 | 315 | |
paul@206 | 316 | // Obtain a DMA-accessible buffer for sample transfers. |
paul@206 | 317 | |
paul@206 | 318 | long |
paul@206 | 319 | Aic_x1600_channel::get_buffer(uint32_t count, l4_addr_t *addr) |
paul@206 | 320 | { |
paul@206 | 321 | printf("get_buffer(%d)\n", count); |
paul@206 | 322 | long err = get_dma_region(count, 8, &_vaddr, &_paddr, &_mem); |
paul@206 | 323 | |
paul@206 | 324 | if (err) |
paul@206 | 325 | return err; |
paul@206 | 326 | |
paul@206 | 327 | // Set the region size as the requested size, not any allocated size. |
paul@206 | 328 | |
paul@206 | 329 | _size = count; |
paul@206 | 330 | *addr = _vaddr; |
paul@206 | 331 | printf("size = %d\n", _size); |
paul@206 | 332 | return L4_EOK; |
paul@206 | 333 | } |
paul@206 | 334 | |
paul@206 | 335 | // Transfer a sample using the given byte count (total sample size), sample rate |
paul@206 | 336 | // (or frequency), sample unit size (or resolution, width). |
paul@206 | 337 | |
paul@206 | 338 | unsigned int |
paul@206 | 339 | Aic_x1600_channel::transfer(uint32_t count, uint32_t sample_rate, uint8_t sample_size) |
paul@206 | 340 | { |
paul@206 | 341 | printf("transfer(%d, %d, %d)\n", count, sample_rate, sample_size); |
paul@206 | 342 | |
paul@206 | 343 | if (count > _size) |
paul@206 | 344 | return 0; |
paul@206 | 345 | |
paul@206 | 346 | /* To play a sample: |
paul@206 | 347 | |
paul@206 | 348 | - Configure the sample size using the Aic_output_size settings in Aic_control |
paul@206 | 349 | - The sample size will be 16- or 24-bit for the MAX9835A, with the X1600 not |
paul@206 | 350 | supporting 32-bit samples |
paul@206 | 351 | - Configure the number of channels in Aic_control (Aic_channel_mono or |
paul@206 | 352 | Aic_channel_stereo) |
paul@206 | 353 | - For 16-bit samples, select Aic_packed_data in Aic_control if appropriate, |
paul@206 | 354 | possibly not for the MAX983A |
paul@206 | 355 | - If two channels are used, select Aic_i2s_msb_right_first in |
paul@206 | 356 | Aic_i2s_msb_control if appropriate, as well as Aic_i2s_msb_switch_lr if |
paul@206 | 357 | switching the channels |
paul@206 | 358 | - Reconfigure the dividers if appropriate |
paul@206 | 359 | - For DMA, set Aic_enable_trans_dma in Aic_control and the transmit FIFO |
paul@206 | 360 | threshold value |
paul@206 | 361 | */ |
paul@206 | 362 | |
paul@206 | 363 | // NOTE: Introduce sample size. |
paul@206 | 364 | |
paul@206 | 365 | set_trans_frequency(sample_rate); |
paul@206 | 366 | |
paul@206 | 367 | /* NOTE: The MAX98357A might require stereo input data, but perhaps the |
paul@206 | 368 | peripheral can generate the appropriate LRCLK to make it accept mono |
paul@206 | 369 | data. */ |
paul@206 | 370 | |
paul@206 | 371 | _regs[Aic_control] = encode_output_size(sample_size) | |
paul@206 | 372 | Aic_channel_mono | |
paul@206 | 373 | Aic_enable_trans_dma | |
paul@206 | 374 | Aic_enable_playback; |
paul@206 | 375 | |
paul@206 | 376 | printf("control = %08x\n", (uint32_t) _regs[Aic_control]); |
paul@206 | 377 | printf("config = %08x\n", (uint32_t) _regs[Aic_config]); |
paul@206 | 378 | printf("divider = %d\n", (uint32_t) _regs[Aic_i2s_msb_divider]); |
paul@206 | 379 | printf("status = %08x\n", (uint32_t) _regs[Aic_i2s_msb_status]); |
paul@206 | 380 | printf("fifo = %08x\n", (uint32_t) _regs[Aic_fifo_status]); |
paul@206 | 381 | |
paul@206 | 382 | // Transfer from the allocated region to the FIFO. Use an incrementing source |
paul@206 | 383 | // address with source width, destination width and transfer unit reflecting |
paul@206 | 384 | // the sample size, and with transfers initiated by an empty AIC transmit |
paul@206 | 385 | // FIFO. |
paul@206 | 386 | |
paul@206 | 387 | printf("transfer from %llx to %lx\n", _paddr, _aic_start + Aic_fifo_data); |
paul@206 | 388 | |
paul@206 | 389 | unsigned int sample_unit = (sample_size == 8) ? 1 : |
paul@206 | 390 | (sample_size == 16) ? 2 : |
paul@206 | 391 | 4; |
paul@206 | 392 | unsigned int unit_count = count / sample_unit; |
paul@206 | 393 | |
paul@206 | 394 | unsigned int to_transfer = _dma->transfer(_paddr, |
paul@206 | 395 | _aic_start + Aic_fifo_data, |
paul@206 | 396 | unit_count, |
paul@206 | 397 | true, |
paul@206 | 398 | false, |
paul@206 | 399 | sample_unit, |
paul@206 | 400 | sample_unit, |
paul@206 | 401 | sample_unit, |
paul@206 | 402 | Dma_request_aic_out); |
paul@206 | 403 | |
paul@206 | 404 | printf("status = %08x\n", (uint32_t) _regs[Aic_i2s_msb_status]); |
paul@206 | 405 | printf("fifo = %08x\n", (uint32_t) _regs[Aic_fifo_status]); |
paul@206 | 406 | |
paul@206 | 407 | unsigned int transferred = 0; |
paul@206 | 408 | |
paul@206 | 409 | if (to_transfer) |
paul@206 | 410 | transferred = to_transfer ? (unit_count - _dma->wait()) * sample_unit : 0; |
paul@206 | 411 | |
paul@206 | 412 | #if 0 |
paul@206 | 413 | if (transferred) |
paul@206 | 414 | while (_regs[Aic_fifo_status]); |
paul@206 | 415 | |
paul@206 | 416 | _regs[Aic_control] = _regs[Aic_control] & ~Aic_enable_playback; |
paul@206 | 417 | #endif |
paul@206 | 418 | |
paul@206 | 419 | return transferred; |
paul@206 | 420 | } |
paul@206 | 421 | |
paul@206 | 422 | |
paul@206 | 423 | |
paul@206 | 424 | // Initialise the AIC/I2S controller. |
paul@206 | 425 | |
paul@206 | 426 | Aic_x1600_chip::Aic_x1600_chip(l4_addr_t aic_start, l4_addr_t start, l4_addr_t end, |
paul@206 | 427 | Cpm_x1600_chip *cpm) |
paul@206 | 428 | : _aic_start(aic_start), _start(start), _end(end), _cpm(cpm) |
paul@206 | 429 | { |
paul@206 | 430 | } |
paul@206 | 431 | |
paul@206 | 432 | // Obtain a channel object. |
paul@206 | 433 | |
paul@206 | 434 | Aic_x1600_channel * |
paul@206 | 435 | Aic_x1600_chip::get_channel(uint8_t channel, Dma_x1600_channel *dma) |
paul@206 | 436 | { |
paul@206 | 437 | if (channel < 1) |
paul@206 | 438 | return new Aic_x1600_channel(_aic_start, _start, Clock_i2s0_rx, Clock_i2s0_tx, _cpm, dma); |
paul@206 | 439 | else |
paul@206 | 440 | throw -L4_EINVAL; |
paul@206 | 441 | } |
paul@206 | 442 | |
paul@206 | 443 | |
paul@206 | 444 | |
paul@206 | 445 | // C language interface functions. |
paul@206 | 446 | |
paul@206 | 447 | void *x1600_aic_init(l4_addr_t aic_start, l4_addr_t start, l4_addr_t end, void *cpm) |
paul@206 | 448 | { |
paul@206 | 449 | return (void *) new Aic_x1600_chip(aic_start, start, end, static_cast<Cpm_x1600_chip *>(cpm)); |
paul@206 | 450 | } |
paul@206 | 451 | |
paul@206 | 452 | void *x1600_aic_get_channel(void *aic, uint8_t channel, void *dma) |
paul@206 | 453 | { |
paul@206 | 454 | return static_cast<Aic_x1600_chip *>(aic)->get_channel(channel, |
paul@206 | 455 | static_cast<Dma_x1600_channel *>(dma)); |
paul@206 | 456 | } |
paul@206 | 457 | |
paul@206 | 458 | long x1600_aic_get_buffer(void *channel, uint32_t count, l4_addr_t *addr) |
paul@206 | 459 | { |
paul@206 | 460 | return static_cast<Aic_x1600_channel *>(channel)->get_buffer(count, addr); |
paul@206 | 461 | } |
paul@206 | 462 | |
paul@206 | 463 | unsigned int x1600_aic_transfer(void *channel, uint32_t count, uint32_t sample_rate, uint8_t sample_size) |
paul@206 | 464 | { |
paul@206 | 465 | return static_cast<Aic_x1600_channel *>(channel)->transfer(count, sample_rate, sample_size); |
paul@206 | 466 | } |