Example #1
0
/*
 * 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();
}
Example #3
0
/*
 * 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;
}