Example #1
0
static int bcm947xx_pcm_close(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	bcm947xx_i2s_info_t *snd_bcm = rtd->dai->cpu_dai->private_data;
	struct bcm947xx_runtime_data *brtd = substream->runtime->private_data;

	DBG("%s %s\n", __FUNCTION__, bcm947xx_direction_str(substream));
	
	DBG("%s: i2s intstatus 0x%x intmask 0x%x\n", __FUNCTION__,
	    R_REG(snd_bcm->osh, &snd_bcm->regs->intstatus),
	    R_REG(snd_bcm->osh, &snd_bcm->regs->intmask));

/* #if required because dma_dump is unavailable in non-debug builds. */
#if BCM947XX_DUMP_RING_BUFFER_ON_PCM_CLOSE_ON
	{
		/* dump dma rings to console */
#if !defined(FIFOERROR_DUMP_SIZE)
#define FIFOERROR_DUMP_SIZE 8192
#endif
		char *tmp;
		struct bcmstrbuf b;
		if (snd_bcm->di[0] && (tmp = MALLOC(snd_bcm->osh, FIFOERROR_DUMP_SIZE))) {
			bcm_binit(&b, tmp, FIFOERROR_DUMP_SIZE);
			dma_dump(snd_bcm->di[0], &b, TRUE);
			printbig(tmp);
			MFREE(snd_bcm->osh, tmp, FIFOERROR_DUMP_SIZE);
		}
	}
#endif /* BCM947XX_DUMP_RING_BUFFER_ON_PCM_CLOSE_ON */

	/* reclaim all descriptors */
	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
		dma_rxreset(snd_bcm->di[0]);
		dma_rxreclaim(snd_bcm->di[0]);
	} else {
		dma_txreset(snd_bcm->di[0]);
		dma_txreclaim(snd_bcm->di[0], HNDDMA_RANGE_ALL);
	}

	if (brtd)
		kfree(brtd);
	else
		DBG("%s: called with brtd == NULL\n", __FUNCTION__);

	return 0;
}
Example #2
0
/* Maybe called from snd_period_elapsed. */
static int bcm947xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	bcm947xx_i2s_info_t *snd_bcm = rtd->dai->cpu_dai->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct bcm947xx_runtime_data *brtd = runtime->private_data;
	uint32 intmask = R_REG(snd_bcm->osh, &snd_bcm->regs->intmask);
	int ret = 0;
	
	DBG("%s %s w/cmd=%d\n", __FUNCTION__, bcm947xx_direction_str(substream), cmd);

	spin_lock(&brtd->lock);

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
	case SNDRV_PCM_TRIGGER_RESUME:
		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
			brtd->bytes_pending = snd_pcm_lib_buffer_bytes(substream);
			bcm947xx_pcm_enqueue(substream);
		} else {
//			dma_txresume(snd_bcm->di[0]);
		}
		break;

	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
//			dma_txsuspend(snd_bcm->di[0]);
			break;
		}
		/* fall-thru */

	case SNDRV_PCM_TRIGGER_STOP:
		/* Reset the disable interrupts, DMA RX/TX channel.
		   Might get here as a result of calling snd_pcm_period_elapsed.
		*/
		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
			intmask &= ~intmask_capture;
			W_REG(snd_bcm->osh, &snd_bcm->regs->intmask, intmask);
			dma_rxreset(snd_bcm->di[0]);
			dma_rxreclaim(snd_bcm->di[0]);
			dma_rxinit(snd_bcm->di[0]);
		} else {
			/* Disable transmit interrupts. */
			intmask &= ~intmask_playback;
			W_REG(snd_bcm->osh, &snd_bcm->regs->intmask, intmask);
			dma_txreset(snd_bcm->di[0]);
			dma_txreclaim(snd_bcm->di[0], HNDDMA_RANGE_ALL);
			dma_txinit(snd_bcm->di[0]);
			if (BCM947XX_DMA_LOOPBACK_ENABLED)
				dma_fifoloopbackenable(snd_bcm->di[0]);
//			dma_txsuspend(snd_bcm->di[0]);
		}
		break;
	default:	
		ret = -EINVAL;
	}

	spin_unlock(&brtd->lock);

	DBG("%s: i2s intstatus 0x%x intmask 0x%x\n", __FUNCTION__,
	    R_REG(snd_bcm->osh, &snd_bcm->regs->intstatus),
	    R_REG(snd_bcm->osh, &snd_bcm->regs->intmask));

	return ret;
}
Example #3
0
static int bcm947xx_pcm_open(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	bcm947xx_i2s_info_t *snd_bcm = rtd->dai->cpu_dai->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct bcm947xx_runtime_data *brtd;
	int ret;

	DBG("%s %s\n", __FUNCTION__, bcm947xx_direction_str(substream));

	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
		snd_soc_set_runtime_hwparams(substream, &bcm947xx_pcm_hardware_capture);
	} else {
		snd_soc_set_runtime_hwparams(substream, &bcm947xx_pcm_hardware_playback);
	}

	if (snd_bcm->in_use & ~(1 << substream->stream)) {
		/* Another stream is in-use; set our constraints to match. */
		if ((ret = bcm947xx_pcm_set_constraints(runtime, snd_bcm)) < 0)
			return ret;
	}
	
	brtd = kzalloc(sizeof(struct bcm947xx_runtime_data), GFP_KERNEL);
	if (brtd == NULL) {
		return -ENOMEM;
	}

	spin_lock_init(&brtd->lock);

	runtime->private_data = brtd;

	/* probably should put this somewhere else, after setting up isr ??? */
	/* Enable appropriate channel. */
	/* Channel dma_XXXinit needs to be called before descriptors can be
	 * posted to the DMA.  Posting currently occurs in the copy operator,
	 * which is called after prepare but before trigger(start).
	*/
	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
		dma_rxreset(snd_bcm->di[0]);
		dma_rxinit(snd_bcm->di[0]);
	} else {
		dma_txreset(snd_bcm->di[0]);
		dma_txinit(snd_bcm->di[0]);
		if (BCM947XX_DMA_LOOPBACK_ENABLED)
			dma_fifoloopbackenable(snd_bcm->di[0]);
//		dma_txsuspend(snd_bcm->di[0]);
	}

	if (BCM947XX_PCM_DEBUG_ON) {
		DBG("%s: i2s devcontrol 0x%x devstatus 0x%x\n", __FUNCTION__,
			R_REG(snd_bcm->osh, &snd_bcm->regs->devcontrol),
			R_REG(snd_bcm->osh, &snd_bcm->regs->devstatus));
		DBG("%s: i2s intstatus 0x%x intmask 0x%x\n", __FUNCTION__,
			R_REG(snd_bcm->osh, &snd_bcm->regs->intstatus),
			R_REG(snd_bcm->osh, &snd_bcm->regs->intmask));
		DBG("%s: i2s control 0x%x\n", __FUNCTION__,
			R_REG(snd_bcm->osh, &snd_bcm->regs->i2scontrol));
		DBG("%s: i2s clkdivider 0x%x txplayth 0x%x\n", __FUNCTION__,
			R_REG(snd_bcm->osh, &snd_bcm->regs->clkdivider),
			R_REG(snd_bcm->osh, &snd_bcm->regs->txplayth));
		DBG("%s: i2s stxctrl 0x%x\n", __FUNCTION__,
			R_REG(snd_bcm->osh, &snd_bcm->regs->stxctrl));

		{
		uint32 temp;
		temp = R_REG(snd_bcm->osh, &snd_bcm->regs->fifocounter);
		DBG("%s: i2s txcnt 0x%x rxcnt 0x%x\n", __FUNCTION__,
			(temp & I2S_FC_TX_CNT_MASK)>> I2S_FC_TX_CNT_SHIFT,
			(temp & I2S_FC_RX_CNT_MASK)>> I2S_FC_RX_CNT_SHIFT);
		}
	}

	return 0;
}
Example #4
0
static void
chipreset(struct bcm4xxx *ch)
{
	bcmenetregs_t *regs;
	uint32 clk, mdc;

	ET_TRACE(("et%d: chipreset\n", ch->etc->unit));

	regs = ch->regs;

	if (!si_iscoreup(ch->sih)) {
		if (!ch->etc->nicmode)
			si_pci_setup(ch->sih, (1 << si_coreidx(ch->sih)));
		/* power on reset: reset the enet core */
		si_core_reset(ch->sih, 0, 0);
		goto chipinreset;
	}

	/* read counters before resetting the chip */
	if (ch->mibgood)
		chipstatsupd(ch);

	/* reset the tx dma engine */
	if (ch->di)
		dma_txreset(ch->di);

	/* set emac into loopback mode to ensure no rx traffic */
	W_REG(ch->osh, &regs->rxconfig, ERC_LE);
	OSL_DELAY(1);

	/* reset the rx dma engine */
	if (ch->di)
		dma_rxreset(ch->di);

	/* reset core */
	si_core_reset(ch->sih, 0, 0);

chipinreset:

	/* must clear mib registers by hand */
	W_REG(ch->osh, &regs->mibcontrol, EMC_RZ);
	(void) R_REG(ch->osh, &regs->mib.tx_broadcast_pkts);
	(void) R_REG(ch->osh, &regs->mib.tx_multicast_pkts);
	(void) R_REG(ch->osh, &regs->mib.tx_len_64);
	(void) R_REG(ch->osh, &regs->mib.tx_len_65_to_127);
	(void) R_REG(ch->osh, &regs->mib.tx_len_128_to_255);
	(void) R_REG(ch->osh, &regs->mib.tx_len_256_to_511);
	(void) R_REG(ch->osh, &regs->mib.tx_len_512_to_1023);
	(void) R_REG(ch->osh, &regs->mib.tx_len_1024_to_max);
	(void) R_REG(ch->osh, &regs->mib.tx_jabber_pkts);
	(void) R_REG(ch->osh, &regs->mib.tx_oversize_pkts);
	(void) R_REG(ch->osh, &regs->mib.tx_fragment_pkts);
	(void) R_REG(ch->osh, &regs->mib.tx_underruns);
	(void) R_REG(ch->osh, &regs->mib.tx_total_cols);
	(void) R_REG(ch->osh, &regs->mib.tx_single_cols);
	(void) R_REG(ch->osh, &regs->mib.tx_multiple_cols);
	(void) R_REG(ch->osh, &regs->mib.tx_excessive_cols);
	(void) R_REG(ch->osh, &regs->mib.tx_late_cols);
	(void) R_REG(ch->osh, &regs->mib.tx_defered);
	(void) R_REG(ch->osh, &regs->mib.tx_carrier_lost);
	(void) R_REG(ch->osh, &regs->mib.tx_pause_pkts);
	(void) R_REG(ch->osh, &regs->mib.rx_broadcast_pkts);
	(void) R_REG(ch->osh, &regs->mib.rx_multicast_pkts);
	(void) R_REG(ch->osh, &regs->mib.rx_len_64);
	(void) R_REG(ch->osh, &regs->mib.rx_len_65_to_127);
	(void) R_REG(ch->osh, &regs->mib.rx_len_128_to_255);
	(void) R_REG(ch->osh, &regs->mib.rx_len_256_to_511);
	(void) R_REG(ch->osh, &regs->mib.rx_len_512_to_1023);
	(void) R_REG(ch->osh, &regs->mib.rx_len_1024_to_max);
	(void) R_REG(ch->osh, &regs->mib.rx_jabber_pkts);
	(void) R_REG(ch->osh, &regs->mib.rx_oversize_pkts);
	(void) R_REG(ch->osh, &regs->mib.rx_fragment_pkts);
	(void) R_REG(ch->osh, &regs->mib.rx_missed_pkts);
	(void) R_REG(ch->osh, &regs->mib.rx_crc_align_errs);
	(void) R_REG(ch->osh, &regs->mib.rx_undersize);
	(void) R_REG(ch->osh, &regs->mib.rx_crc_errs);
	(void) R_REG(ch->osh, &regs->mib.rx_align_errs);
	(void) R_REG(ch->osh, &regs->mib.rx_symbol_errs);
	(void) R_REG(ch->osh, &regs->mib.rx_pause_pkts);
	(void) R_REG(ch->osh, &regs->mib.rx_nonpause_pkts);
	ch->mibgood = TRUE;

	/*
	 * We want the phy registers to be accessible even when
	 * the driver is "downed" so initialize MDC preamble, frequency,
	 * and whether internal or external phy here.
	 */
	/* default:  100Mhz SI clock and external phy */
	W_REG(ch->osh, &regs->mdiocontrol, 0x94);
	if (ch->etc->deviceid == BCM47XX_ENET_ID) {
		/* 47xx chips: find out the clock */
		if ((clk = si_clock(ch->sih)) != 0) {
			mdc = 0x80 | ((clk + (MDC_RATIO / 2)) / MDC_RATIO);
			W_REG(ch->osh, &regs->mdiocontrol, mdc);
		} else {
			ET_ERROR(("et%d: chipreset: Could not figure out backplane clock, "
			          "using 100Mhz\n",
			          ch->etc->unit));
		}
	}

	/* some chips have internal phy, some don't */
	if (!(R_REG(ch->osh, &regs->devcontrol) & DC_IP)) {
		W_REG(ch->osh, &regs->enetcontrol, EC_EP);
	} else if (R_REG(ch->osh, &regs->devcontrol) & DC_ER) {
		AND_REG(ch->osh, &regs->devcontrol, ~DC_ER);
		OSL_DELAY(100);
		chipphyinit(ch, ch->etc->phyaddr);
	}

	/* clear persistent sw intstatus */
	ch->intstatus = 0;
}