/* * wait for all dma is done. * NOTE: caller should reset card->running before call. * If not, the interrupt handler will re-start DMA, * then DMA is never stopped. */ static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card) { int stop_forced; /* * wait for the last dma is done */ /* * expected maximum DMA done time is 5.7ms + something (DMA itself). * 5.7ms is from 16bit/sample 2ch 44.1Khz; the time next * DMA kick event would occur. */ stop_forced = snd_ps3_verify_dma_stop(card, 700, 1); /* * clear outstanding interrupts. */ update_reg(PS3_AUDIO_INTR_0, 0); update_reg(PS3_AUDIO_AX_IS, 0); /* *revert CLEAR bit since it will not reset automatically after DMA stop */ if (stop_forced) update_mask_reg(PS3_AUDIO_CONFIG, ~PS3_AUDIO_CONFIG_CLEAR, 0); /* ensure the hardware sees changes */ wmb(); }
static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card) { int stop_forced; stop_forced = snd_ps3_verify_dma_stop(card, 700, 1); update_reg(PS3_AUDIO_INTR_0, 0); update_reg(PS3_AUDIO_AX_IS, 0); if (stop_forced) update_mask_reg(PS3_AUDIO_CONFIG, ~PS3_AUDIO_CONFIG_CLEAR, 0); wmb(); }
/* * setup dmac to send data to audio and attenuate samples on the ring buffer */ static int snd_ps3_program_dma(struct snd_ps3_card_info *card, enum snd_ps3_dma_filltype filltype) { /* this dmac does not support over 4G */ uint32_t dma_addr; int fill_stages, dma_ch, stage; enum snd_ps3_ch ch; uint32_t ch0_kick_event = 0; /* initialize to mute gcc */ void *start_vaddr; unsigned long irqsave; int silent = 0; switch (filltype) { case SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL: silent = 1; /* intentionally fall thru */ case SND_PS3_DMA_FILLTYPE_FIRSTFILL: ch0_kick_event = PS3_AUDIO_KICK_EVENT_ALWAYS; break; case SND_PS3_DMA_FILLTYPE_SILENT_RUNNING: silent = 1; /* intentionally fall thru */ case SND_PS3_DMA_FILLTYPE_RUNNING: ch0_kick_event = PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY; break; } snd_ps3_verify_dma_stop(card, 700, 0); fill_stages = 4; spin_lock_irqsave(&card->dma_lock, irqsave); for (ch = 0; ch < 2; ch++) { start_vaddr = card->dma_next_transfer_vaddr[0]; for (stage = 0; stage < fill_stages; stage++) { dma_ch = stage * 2 + ch; if (silent) dma_addr = card->null_buffer_start_dma_addr; else dma_addr = v_to_bus(card, card->dma_next_transfer_vaddr[ch], ch); write_reg(PS3_AUDIO_SOURCE(dma_ch), (PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY | dma_addr)); /* dst: fixed to 3wire#0 */ if (ch == 0) write_reg(PS3_AUDIO_DEST(dma_ch), (PS3_AUDIO_DEST_TARGET_AUDIOFIFO | PS3_AUDIO_AO_3W_LDATA(0))); else write_reg(PS3_AUDIO_DEST(dma_ch), (PS3_AUDIO_DEST_TARGET_AUDIOFIFO | PS3_AUDIO_AO_3W_RDATA(0))); /* count always 1 DMA block (1/2 stage = 128 bytes) */ write_reg(PS3_AUDIO_DMASIZE(dma_ch), 0); /* bump pointer if needed */ if (!silent) snd_ps3_bump_buffer(card, ch, PS3_AUDIO_DMAC_BLOCK_SIZE, stage); /* kick event */ if (dma_ch == 0) write_reg(PS3_AUDIO_KICK(dma_ch), ch0_kick_event); else write_reg(PS3_AUDIO_KICK(dma_ch), PS3_AUDIO_KICK_EVENT_AUDIO_DMA(dma_ch - 1) | PS3_AUDIO_KICK_REQUEST); } } /* ensure the hardware sees the change */ wmb(); spin_unlock_irqrestore(&card->dma_lock, irqsave); return 0; }
static int snd_ps3_program_dma(struct snd_ps3_card_info *card, enum snd_ps3_dma_filltype filltype) { uint32_t dma_addr; int fill_stages, dma_ch, stage; enum snd_ps3_ch ch; uint32_t ch0_kick_event = 0; void *start_vaddr; unsigned long irqsave; int silent = 0; switch (filltype) { case SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL: silent = 1; case SND_PS3_DMA_FILLTYPE_FIRSTFILL: ch0_kick_event = PS3_AUDIO_KICK_EVENT_ALWAYS; break; case SND_PS3_DMA_FILLTYPE_SILENT_RUNNING: silent = 1; case SND_PS3_DMA_FILLTYPE_RUNNING: ch0_kick_event = PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY; break; } snd_ps3_verify_dma_stop(card, 700, 0); fill_stages = 4; spin_lock_irqsave(&card->dma_lock, irqsave); for (ch = 0; ch < 2; ch++) { start_vaddr = card->dma_next_transfer_vaddr[0]; for (stage = 0; stage < fill_stages; stage++) { dma_ch = stage * 2 + ch; if (silent) dma_addr = card->null_buffer_start_dma_addr; else dma_addr = v_to_bus(card, card->dma_next_transfer_vaddr[ch], ch); write_reg(PS3_AUDIO_SOURCE(dma_ch), (PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY | dma_addr)); if (ch == 0) write_reg(PS3_AUDIO_DEST(dma_ch), (PS3_AUDIO_DEST_TARGET_AUDIOFIFO | PS3_AUDIO_AO_3W_LDATA(0))); else write_reg(PS3_AUDIO_DEST(dma_ch), (PS3_AUDIO_DEST_TARGET_AUDIOFIFO | PS3_AUDIO_AO_3W_RDATA(0))); write_reg(PS3_AUDIO_DMASIZE(dma_ch), 0); if (!silent) snd_ps3_bump_buffer(card, ch, PS3_AUDIO_DMAC_BLOCK_SIZE, stage); if (dma_ch == 0) write_reg(PS3_AUDIO_KICK(dma_ch), ch0_kick_event); else write_reg(PS3_AUDIO_KICK(dma_ch), PS3_AUDIO_KICK_EVENT_AUDIO_DMA(dma_ch - 1) | PS3_AUDIO_KICK_REQUEST); } } wmb(); spin_unlock_irqrestore(&card->dma_lock, irqsave); return 0; }