Exemplo n.º 1
0
static void snd_ps3_kick_dma(struct snd_ps3_card_info *card)
{

	update_reg(PS3_AUDIO_KICK(0), PS3_AUDIO_KICK_REQUEST);
	/* ensure the hardware sees the change */
	wmb();
}
Exemplo n.º 2
0
static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card,
				   int count, int force_stop)
{
	int dma_ch, done, retries, stop_forced = 0;
	uint32_t status;

	for (dma_ch = 0; dma_ch < 8; dma_ch++) {
		retries = count;
		do {
			status = read_reg(PS3_AUDIO_KICK(dma_ch)) &
				PS3_AUDIO_KICK_STATUS_MASK;
			switch (status) {
			case PS3_AUDIO_KICK_STATUS_DONE:
			case PS3_AUDIO_KICK_STATUS_NOTIFY:
			case PS3_AUDIO_KICK_STATUS_CLEAR:
			case PS3_AUDIO_KICK_STATUS_ERROR:
				done = 1;
				break;
			default:
				done = 0;
				udelay(10);
			}
		} while (!done && --retries);
		if (!retries && force_stop) {
			pr_info("%s: DMA ch %d is not stopped.",
				__func__, dma_ch);
			/* last resort. force to stop dma.
			 *  NOTE: this cause DMA done interrupts
			 */
			update_reg(PS3_AUDIO_CONFIG, PS3_AUDIO_CONFIG_CLEAR);
			stop_forced = 1;
		}
	}
	return stop_forced;
}
Exemplo n.º 3
0
static void snd_ps3_kick_dma(struct snd_ps3_card_info *card)
{

	update_reg(PS3_AUDIO_KICK(0), PS3_AUDIO_KICK_REQUEST);
	
	wmb();
}
Exemplo n.º 4
0
static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
			       int cmd)
{
	struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
	int ret = 0;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
		/* clear outstanding interrupts  */
		update_reg(PS3_AUDIO_AX_IS, 0);

		spin_lock(&card->dma_lock);
		{
			card->running = 1;
		}
		spin_unlock(&card->dma_lock);

		snd_ps3_program_dma(card,
				    SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
		snd_ps3_kick_dma(card);
		while (read_reg(PS3_AUDIO_KICK(7)) &
		       PS3_AUDIO_KICK_STATUS_MASK) {
			udelay(1);
		}
		snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
		snd_ps3_kick_dma(card);
		break;

	case SNDRV_PCM_TRIGGER_STOP:
		spin_lock(&card->dma_lock);
		{
			card->running = 0;
		}
		spin_unlock(&card->dma_lock);
		snd_ps3_wait_for_dma_stop(card);
		break;
	default:
		break;

	}

	return ret;
};
Exemplo n.º 5
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;
}
Exemplo n.º 6
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;
}