Exemple #1
0
static int
at91_aic_attach(device_t dev)
{
	int i, rid, err = 0;

	device_printf(dev, "Attach %d\n", bus_current_pass);

	sc = device_get_softc(dev);
	sc->sc_dev = dev;

	rid = 0;
	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
	    RF_ACTIVE);

	if (sc->mem_res == NULL)
		panic("couldn't allocate register resources");

	/*
	 * Setup the interrupt table.
	 */
	if (soc_info.soc_data == NULL || soc_info.soc_data->soc_irq_prio == NULL)
		panic("Interrupt priority table missing\n");
	for (i = 0; i < 32; i++) {
		WR4(sc, IC_SVR + i * 4, i);
		/* Priority. */
		WR4(sc, IC_SMR + i * 4, soc_info.soc_data->soc_irq_prio[i]);
		if (i < 8)
			WR4(sc, IC_EOICR, 1);
	}

	WR4(sc, IC_SPU, 32);
	/* No debug. */
	WR4(sc, IC_DCR, 0);
	/* Disable and clear all interrupts. */
	WR4(sc, IC_IDCR, 0xffffffff);
	WR4(sc, IC_ICCR, 0xffffffff);
	enable_interrupts(PSR_I | PSR_F);

	return (err);
}
Exemple #2
0
/*
 * Reset the controller, then restore most of the current state.
 *
 * This is called after detecting an error.  It's also called after stopping a
 * multi-block write, to un-wedge the device so that it will handle the NOTBUSY
 * signal correctly.  See comments in at91_mci_stop_done() for more details.
 */
static void at91_mci_reset(struct at91_mci_softc *sc)
{
	uint32_t mr;
	uint32_t sdcr;
	uint32_t dtor;
	uint32_t imr;

	at91_mci_pdc_disable(sc);

	/* save current state */

	imr  = RD4(sc, MCI_IMR);
	mr   = RD4(sc, MCI_MR) & 0x7fff;
	sdcr = RD4(sc, MCI_SDCR);
	dtor = RD4(sc, MCI_DTOR);

	/* reset the controller */

	WR4(sc, MCI_IDR, 0xffffffff);
	WR4(sc, MCI_CR, MCI_CR_MCIDIS | MCI_CR_SWRST);

	/* restore state */

	WR4(sc, MCI_CR, MCI_CR_MCIEN|MCI_CR_PWSEN);
	WR4(sc, MCI_MR, mr);
	WR4(sc, MCI_SDCR, sdcr);
	WR4(sc, MCI_DTOR, dtor);
	WR4(sc, MCI_IER, imr);

	/*
	 * Make sure sdio interrupts will fire.  Not sure why reading
	 * SR ensures that, but this is in the linux driver.
	 */

	RD4(sc, MCI_SR);
}
static void
ixp425_watchdog(void *arg, u_int cmd, int *error)
{
	struct ixpwdog_softc *sc = arg;
	u_int u = cmd & WD_INTERVAL;

	WR4(sc, IXP425_OST_WDOG_KEY, OST_WDOG_KEY_MAJICK);
	if (4 <= u && u <= 35) {
		WR4(sc, IXP425_OST_WDOG_ENAB, 0);
		/* approximate 66.66MHz cycles */
		WR4(sc, IXP425_OST_WDOG, 2<<(u - 4));
		/* NB: reset on timer expiration */
		WR4(sc, IXP425_OST_WDOG_ENAB,
		    OST_WDOG_ENAB_CNT_ENA | OST_WDOG_ENAB_RST_ENA);
		*error = 0;
	} else {
		/* disable watchdog */
		WR4(sc, IXP425_OST_WDOG_ENAB, 0);
	}
	WR4(sc, IXP425_OST_WDOG_KEY, 0);
}
Exemple #4
0
static void
awg_update_link_locked(struct awg_softc *sc)
{
	struct mii_data *mii;
	uint32_t val;

	AWG_ASSERT_LOCKED(sc);

	if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) == 0)
		return;
	mii = device_get_softc(sc->miibus);

	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
	    (IFM_ACTIVE | IFM_AVALID)) {
		switch (IFM_SUBTYPE(mii->mii_media_active)) {
		case IFM_1000_T:
		case IFM_1000_SX:
		case IFM_100_TX:
		case IFM_10_T:
			sc->link = 1;
			break;
		default:
			sc->link = 0;
			break;
		}
	} else
		sc->link = 0;

	if (sc->link == 0)
		return;

	val = RD4(sc, EMAC_BASIC_CTL_0);
	val &= ~(BASIC_CTL_SPEED | BASIC_CTL_DUPLEX);

	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
	    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX)
		val |= BASIC_CTL_SPEED_1000 << BASIC_CTL_SPEED_SHIFT;
	else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
		val |= BASIC_CTL_SPEED_100 << BASIC_CTL_SPEED_SHIFT;
	else
		val |= BASIC_CTL_SPEED_10 << BASIC_CTL_SPEED_SHIFT;

	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
		val |= BASIC_CTL_DUPLEX;

	WR4(sc, EMAC_BASIC_CTL_0, val);

	val = RD4(sc, EMAC_RX_CTL_0);
	val &= ~RX_FLOW_CTL_EN;
	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0)
		val |= RX_FLOW_CTL_EN;
	WR4(sc, EMAC_RX_CTL_0, val);

	val = RD4(sc, EMAC_TX_FLOW_CTL);
	val &= ~(PAUSE_TIME|TX_FLOW_CTL_EN);
	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0)
		val |= TX_FLOW_CTL_EN;
	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
		val |= awg_pause_time << PAUSE_TIME_SHIFT;
	WR4(sc, EMAC_TX_FLOW_CTL, val);
}
static int
at91_spi_attach(device_t dev)
{
	struct at91_spi_softc *sc = device_get_softc(dev);
	int err, i;

	sc->dev = dev;
	err = at91_spi_activate(dev);
	if (err)
		goto out;

	/*
	 * Allocate DMA tags and maps
	 */
	err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 2058, 1,
	    2048, BUS_DMA_ALLOCNOW, NULL, NULL, &sc->dmatag);
	if (err != 0)
		goto out;
	for (i = 0; i < 4; i++) {
		err = bus_dmamap_create(sc->dmatag, 0,  &sc->map[i]);
		if (err != 0)
			goto out;
	}

	// reset the SPI
	WR4(sc, SPI_CR, SPI_CR_SWRST);
	WR4(sc, SPI_IDR, 0xffffffff);

	WR4(sc, SPI_MR, (0xf << 24) | SPI_MR_MSTR | SPI_MR_MODFDIS |
	    (0xE << 16));

	WR4(sc, SPI_CSR0, SPI_CSR_CPOL | (4 << 16) | (2 << 8));
	WR4(sc, SPI_CR, SPI_CR_SPIEN);

	WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS);
	WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS);
	WR4(sc, PDC_RNPR, 0);
	WR4(sc, PDC_RNCR, 0);
	WR4(sc, PDC_TNPR, 0);
	WR4(sc, PDC_TNCR, 0);
	WR4(sc, PDC_RPR, 0);
	WR4(sc, PDC_RCR, 0);
	WR4(sc, PDC_TPR, 0);
	WR4(sc, PDC_TCR, 0);
	RD4(sc, SPI_RDR);
	RD4(sc, SPI_SR);

	device_add_child(dev, "spibus", -1);
	bus_generic_attach(dev);
out:;
	if (err)
		at91_spi_deactivate(dev);
	return (err);
}
Exemple #6
0
static int
at91_usart_param(struct uart_bas *bas, int baudrate, int databits,
    int stopbits, int parity)
{
	uint32_t mr;

	/*
	 * Assume 3-wire RS-232 configuration.
	 * XXX Not sure how uart will present the other modes to us, so
	 * XXX they are unimplemented.  maybe ioctl?
	 */
	mr = USART_MR_MODE_NORMAL;
	mr |= USART_MR_USCLKS_MCK;	/* Assume MCK */

	/*
	 * Or in the databits requested
	 */
	if (databits < 9)
		mr &= ~USART_MR_MODE9;
	switch (databits) {
	case 5:
		mr |= USART_MR_CHRL_5BITS;
		break;
	case 6:
		mr |= USART_MR_CHRL_6BITS;
		break;
	case 7:
		mr |= USART_MR_CHRL_7BITS;
		break;
	case 8:
		mr |= USART_MR_CHRL_8BITS;
		break;
	case 9:
		mr |= USART_MR_CHRL_8BITS | USART_MR_MODE9;
		break;
	default:
		return (EINVAL);
	}

	/*
	 * Or in the parity
	 */
	switch (parity) {
	case UART_PARITY_NONE:
		mr |= USART_MR_PAR_NONE;
		break;
	case UART_PARITY_ODD:
		mr |= USART_MR_PAR_ODD;
		break;
	case UART_PARITY_EVEN:
		mr |= USART_MR_PAR_EVEN;
		break;
	case UART_PARITY_MARK:
		mr |= USART_MR_PAR_MARK;
		break;
	case UART_PARITY_SPACE:
		mr |= USART_MR_PAR_SPACE;
		break;
	default:
		return (EINVAL);
	}

	/*
	 * Or in the stop bits.  Note: The hardware supports 1.5 stop
	 * bits in async mode, but there's no way to specify that
	 * AFAICT.  Instead, rely on the convention documented at
	 * http://www.lammertbies.nl/comm/info/RS-232_specs.html which
	 * states that 1.5 stop bits are used for 5 bit bytes and
	 * 2 stop bits only for longer bytes.
	 */
	if (stopbits == 1)
		mr |= USART_MR_NBSTOP_1;
	else if (databits > 5)
		mr |= USART_MR_NBSTOP_2;
	else
		mr |= USART_MR_NBSTOP_1_5;

	/*
	 * We want normal plumbing mode too, none of this fancy
	 * loopback or echo mode.
	 */
	mr |= USART_MR_CHMODE_NORMAL;

	mr &= ~USART_MR_MSBF;	/* lsb first */
	mr &= ~USART_MR_CKLO_SCK;	/* Don't drive SCK */

	WR4(bas, USART_MR, mr);

	/*
	 * Set the baud rate (only if we know our master clock rate)
	 */
	if (DEFAULT_RCLK != 0)
		WR4(bas, USART_BRGR, BAUD2DIVISOR(baudrate));

	/*
	 * Set the receive timeout based on the baud rate.  The idea is to
	 * compromise between being responsive on an interactive connection and
	 * giving a bulk data sender a bit of time to queue up a new buffer
	 * without mistaking it for a stopping point in the transmission.  For
	 * 19.2kbps and below, use 20 * bit time (2 characters).  For faster
	 * connections use 500 microseconds worth of bits.
	 */
	if (baudrate <= 19200)
		WR4(bas, USART_RTOR, 20);
	else 
		WR4(bas, USART_RTOR, baudrate / 2000);
	WR4(bas, USART_CR, USART_CR_STTTO);

	/* XXX Need to take possible synchronous mode into account */
	return (0);
}
static int
at91_usart_param(struct uart_bas *bas, int baudrate, int databits,
    int stopbits, int parity)
{
	uint32_t mr;

	/*
	 * Assume 3-wire RS-232 configuration.
	 * XXX Not sure how uart will present the other modes to us, so
	 * XXX they are unimplemented.  maybe ioctl?
	 */
	mr = USART_MR_MODE_NORMAL;
	mr |= USART_MR_USCLKS_MCK;	/* Assume MCK */

	/*
	 * Or in the databits requested
	 */
	if (databits < 9)
		mr &= ~USART_MR_MODE9;
	switch (databits) {
	case 5:
		mr |= USART_MR_CHRL_5BITS;
		break;
	case 6:
		mr |= USART_MR_CHRL_6BITS;
		break;
	case 7:
		mr |= USART_MR_CHRL_7BITS;
		break;
	case 8:
		mr |= USART_MR_CHRL_8BITS;
		break;
	case 9:
		mr |= USART_MR_CHRL_8BITS | USART_MR_MODE9;
		break;
	default:
		return (EINVAL);
	}

	/*
	 * Or in the parity
	 */
	switch (parity) {
	case UART_PARITY_NONE:
		mr |= USART_MR_PAR_NONE;
		break;
	case UART_PARITY_ODD:
		mr |= USART_MR_PAR_ODD;
		break;
	case UART_PARITY_EVEN:
		mr |= USART_MR_PAR_EVEN;
		break;
	case UART_PARITY_MARK:
		mr |= USART_MR_PAR_MARK;
		break;
	case UART_PARITY_SPACE:
		mr |= USART_MR_PAR_SPACE;
		break;
	default:
		return (EINVAL);
	}

	/*
	 * Or in the stop bits.  Note: The hardware supports 1.5 stop
	 * bits in async mode, but there's no way to specify that
	 * AFAICT.  Instead, rely on the convention documented at
	 * http://www.lammertbies.nl/comm/info/RS-232_specs.html which
	 * states that 1.5 stop bits are used for 5 bit bytes and
	 * 2 stop bits only for longer bytes.
	 */
	if (stopbits == 1)
		mr |= USART_MR_NBSTOP_1;
	else if (databits > 5)
		mr |= USART_MR_NBSTOP_2;
	else
		mr |= USART_MR_NBSTOP_1_5;

	/*
	 * We want normal plumbing mode too, none of this fancy
	 * loopback or echo mode.
	 */
	mr |= USART_MR_CHMODE_NORMAL;

	mr &= ~USART_MR_MSBF;	/* lsb first */
	mr &= ~USART_MR_CKLO_SCK;	/* Don't drive SCK */

	WR4(bas, USART_MR, mr);

	/*
	 * Set the baud rate (only if we know our master clock rate)
	 */
	if (DEFAULT_RCLK != 0)
		WR4(bas, USART_BRGR, BAUD2DIVISOR(baudrate));

	/* XXX Need to take possible synchronous mode into account */
	return (0);
}
Exemple #8
0
static void ffec_clear_stats(struct ffec_softc *sc)
{

	WR4(sc, FEC_RMON_R_PACKETS, 0);
	WR4(sc, FEC_RMON_R_MC_PKT, 0);
	WR4(sc, FEC_RMON_R_CRC_ALIGN, 0);
	WR4(sc, FEC_RMON_R_UNDERSIZE, 0);
	WR4(sc, FEC_RMON_R_OVERSIZE, 0);
	WR4(sc, FEC_RMON_R_FRAG, 0);
	WR4(sc, FEC_RMON_R_JAB, 0);
	WR4(sc, FEC_RMON_T_PACKETS, 0);
	WR4(sc, FEC_RMON_T_MC_PKT, 0);
	WR4(sc, FEC_RMON_T_CRC_ALIGN, 0);
	WR4(sc, FEC_RMON_T_UNDERSIZE, 0);
	WR4(sc, FEC_RMON_T_OVERSIZE , 0);
	WR4(sc, FEC_RMON_T_FRAG, 0);
	WR4(sc, FEC_RMON_T_JAB, 0);
	WR4(sc, FEC_RMON_T_COL, 0);
}
Exemple #9
0
static void
at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd)
{
	uint32_t cmdr, mr;
	struct mmc_data *data;

	sc->curcmd = cmd;
	data = cmd->data;

	/* XXX Upper layers don't always set this */
	cmd->mrq = sc->req;

	/* Begin setting up command register. */

	cmdr = cmd->opcode;

	if (sc->host.ios.bus_mode == opendrain)
		cmdr |= MCI_CMDR_OPDCMD;

	/* Set up response handling.  Allow max timeout for responses. */

	if (MMC_RSP(cmd->flags) == MMC_RSP_NONE)
		cmdr |= MCI_CMDR_RSPTYP_NO;
	else {
		cmdr |= MCI_CMDR_MAXLAT;
		if (cmd->flags & MMC_RSP_136)
			cmdr |= MCI_CMDR_RSPTYP_136;
		else
			cmdr |= MCI_CMDR_RSPTYP_48;
	}

	/*
	 * If there is no data transfer, just set up the right interrupt mask
	 * and start the command.
	 *
	 * The interrupt mask needs to be CMDRDY plus all non-data-transfer
	 * errors. It's important to leave the transfer-related errors out, to
	 * avoid spurious timeout or crc errors on a STOP command following a
	 * multiblock read.  When a multiblock read is in progress, sending a
	 * STOP in the middle of a block occasionally triggers such errors, but
	 * we're totally disinterested in them because we've already gotten all
	 * the data we wanted without error before sending the STOP command.
	 */

	if (data == NULL) {
		uint32_t ier = MCI_SR_CMDRDY |
		    MCI_SR_RTOE | MCI_SR_RENDE |
		    MCI_SR_RCRCE | MCI_SR_RDIRE | MCI_SR_RINDE;

		at91_mci_pdc_disable(sc);

		if (cmd->opcode == MMC_STOP_TRANSMISSION)
			cmdr |= MCI_CMDR_TRCMD_STOP;

		/* Ignore response CRC on CMD2 and ACMD41, per standard. */

		if (cmd->opcode == MMC_SEND_OP_COND ||
		    cmd->opcode == ACMD_SD_SEND_OP_COND)
			ier &= ~MCI_SR_RCRCE;

		if (mci_debug)
			printf("CMDR %x (opcode %d) ARGR %x no data\n",
			    cmdr, cmd->opcode, cmd->arg);

		WR4(sc, MCI_ARGR, cmd->arg);
		WR4(sc, MCI_CMDR, cmdr);
		WR4(sc, MCI_IDR, 0xffffffff);
		WR4(sc, MCI_IER, ier);
		return;
	}

	/* There is data, set up the transfer-related parts of the command. */

	if (data->flags & MMC_DATA_READ)
		cmdr |= MCI_CMDR_TRDIR;

	if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE))
		cmdr |= MCI_CMDR_TRCMD_START;

	if (data->flags & MMC_DATA_STREAM)
		cmdr |= MCI_CMDR_TRTYP_STREAM;
	else if (data->flags & MMC_DATA_MULTI) {
		cmdr |= MCI_CMDR_TRTYP_MULTIPLE;
		sc->flags |= (data->flags & MMC_DATA_READ) ?
		    CMD_MULTIREAD : CMD_MULTIWRITE;
	}

	/*
	 * Disable PDC until we're ready.
	 *
	 * Set block size and turn on PDC mode for dma xfer.
	 * Note that the block size is the smaller of the amount of data to be
	 * transferred, or 512 bytes.  The 512 size is fixed by the standard;
	 * smaller blocks are possible, but never larger.
	 */

	WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS);

	mr = RD4(sc,MCI_MR) & ~MCI_MR_BLKLEN;
	mr |=  min(data->len, 512) << 16;
	WR4(sc, MCI_MR, mr | MCI_MR_PDCMODE|MCI_MR_PDCPADV);

	/*
	 * Set up DMA.
	 *
	 * Use bounce buffers even if we don't need to byteswap, because doing
	 * multi-block IO with large DMA buffers is way fast (compared to
	 * single-block IO), even after incurring the overhead of also copying
	 * from/to the caller's buffers (which may be in non-contiguous physical
	 * pages).
	 *
	 * In an ideal non-byteswap world we could create a dma tag that allows
	 * for discontiguous segments and do the IO directly from/to the
	 * caller's buffer(s), using ENDRX/ENDTX interrupts to chain the
	 * discontiguous buffers through the PDC. Someday.
	 *
	 * If a read is bigger than 2k, split it in half so that we can start
	 * byte-swapping the first half while the second half is on the wire.
	 * It would be best if we could split it into 8k chunks, but we can't
	 * always keep up with the byte-swapping due to other system activity,
	 * and if an RXBUFF interrupt happens while we're still handling the
	 * byte-swap from the prior buffer (IE, we haven't returned from
	 * handling the prior interrupt yet), then data will get dropped on the
	 * floor and we can't easily recover from that.  The right fix for that
	 * would be to have the interrupt handling only keep the DMA flowing and
	 * enqueue filled buffers to be byte-swapped in a non-interrupt context.
	 * Even that won't work on the write side of things though; in that
	 * context we have to have all the data ready to go before starting the
	 * dma.
	 *
	 * XXX what about stream transfers?
	 */
	sc->xfer_offset = 0;
	sc->bbuf_curidx = 0;

	if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) {
		uint32_t len;
		uint32_t remaining = data->len;
		bus_addr_t paddr;
		int err;

		if (remaining > (BBCOUNT*BBSIZE))
			panic("IO read size exceeds MAXDATA\n");

		if (data->flags & MMC_DATA_READ) {
			if (remaining > 2048) // XXX
				len = remaining / 2;
			else
				len = remaining;
			err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[0],
			    sc->bbuf_vaddr[0], len, at91_mci_getaddr,
			    &paddr, BUS_DMA_NOWAIT);
			if (err != 0)
				panic("IO read dmamap_load failed\n");
			bus_dmamap_sync(sc->dmatag, sc->bbuf_map[0],
			    BUS_DMASYNC_PREREAD);
			WR4(sc, PDC_RPR, paddr);
			WR4(sc, PDC_RCR, len / 4);
			sc->bbuf_len[0] = len;
			remaining -= len;
			if (remaining == 0) {
				sc->bbuf_len[1] = 0;
			} else {
				len = remaining;
				err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[1],
				    sc->bbuf_vaddr[1], len, at91_mci_getaddr,
				    &paddr, BUS_DMA_NOWAIT);
				if (err != 0)
					panic("IO read dmamap_load failed\n");
				bus_dmamap_sync(sc->dmatag, sc->bbuf_map[1],
				    BUS_DMASYNC_PREREAD);
				WR4(sc, PDC_RNPR, paddr);
				WR4(sc, PDC_RNCR, len / 4);
				sc->bbuf_len[1] = len;
				remaining -= len;
			}
			WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN);
		} else {
			len = min(BBSIZE, remaining);
			/*
			 * If this is MCI1 revision 2xx controller, apply
			 * a work-around for the "Data Write Operation and
			 * number of bytes" erratum.
			 */
			if ((sc->sc_cap & CAP_MCI1_REV2XX) && len < 12) {
				len = 12;
				memset(sc->bbuf_vaddr[0], 0, 12);
			}
			at91_bswap_buf(sc, sc->bbuf_vaddr[0], data->data, len);
			err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[0],
			    sc->bbuf_vaddr[0], len, at91_mci_getaddr,
			    &paddr, BUS_DMA_NOWAIT);
			if (err != 0)
				panic("IO write dmamap_load failed\n");
			bus_dmamap_sync(sc->dmatag, sc->bbuf_map[0],
			    BUS_DMASYNC_PREWRITE);
			WR4(sc, PDC_TPR,paddr);
			WR4(sc, PDC_TCR, len / 4);
			sc->bbuf_len[0] = len;
			remaining -= len;
			if (remaining == 0) {
				sc->bbuf_len[1] = 0;
			} else {
				len = remaining;
				at91_bswap_buf(sc, sc->bbuf_vaddr[1],
				    ((char *)data->data)+BBSIZE, len);
				err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[1],
				    sc->bbuf_vaddr[1], len, at91_mci_getaddr,
				    &paddr, BUS_DMA_NOWAIT);
				if (err != 0)
					panic("IO write dmamap_load failed\n");
				bus_dmamap_sync(sc->dmatag, sc->bbuf_map[1],
				    BUS_DMASYNC_PREWRITE);
				WR4(sc, PDC_TNPR, paddr);
				WR4(sc, PDC_TNCR, len / 4);
				sc->bbuf_len[1] = len;
				remaining -= len;
			}
			/* do not enable PDC xfer until CMDRDY asserted */
		}
		data->xfer_len = 0; /* XXX what's this? appears to be unused. */
	}

	if (mci_debug)
		printf("CMDR %x (opcode %d) ARGR %x with data len %d\n",
		       cmdr, cmd->opcode, cmd->arg, cmd->data->len);

	WR4(sc, MCI_ARGR, cmd->arg);
	WR4(sc, MCI_CMDR, cmdr);
	WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_CMDRDY);
}
Exemple #10
0
static int
at91_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
{
	struct at91_spi_softc *sc;
	bus_addr_t addr;
	int err, i, j, mode[4];

	KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
	    ("%s: TX/RX command sizes should be equal", __func__));
	KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
	    ("%s: TX/RX data sizes should be equal", __func__));

	sc = device_get_softc(dev);
	i = 0;

	sx_xlock(&sc->xfer_mtx);

	/*
	 * Disable transfers while we set things up.
	 */
	WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);

#ifdef SPI_CHIPSEL_SUPPORT
	if (cmd->cs < 0 || cmd->cs > 3) {
		device_printf(dev,
		    "Invalid chip select %d requested by %s\n", cmd->cs,
		    device_get_nameunit(child));
		err = EINVAL;
		goto out;
	}
#ifdef SPI_CHIP_SELECT_HIGH_SUPPORT
	if (at91_is_rm92() && cmd->cs == 0 &&
	    (cmd->flags & SPI_CHIP_SELECT_HIGH) != 0) {
		device_printf(dev,
		    "Invalid chip select high requested by %s\n",
		    device_get_nameunit(child));
		err = EINVAL;
		goto out;
	}
#endif
	WR4(sc, SPI_MR, (RD4(sc, SPI_MR) & ~0x000f0000) | CS_TO_MR(cmd->cs));
#endif

	/*
	 * Set up the TX side of the transfer.
	 */
	if ((err = bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_cmd,
	    cmd->tx_cmd_sz, at91_getaddr, &addr, 0)) != 0)
		goto out;
	WR4(sc, PDC_TPR, addr);
	WR4(sc, PDC_TCR, cmd->tx_cmd_sz);
	bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
	mode[i++] = BUS_DMASYNC_POSTWRITE;
	if (cmd->tx_data_sz > 0) {
		if ((err = bus_dmamap_load(sc->dmatag, sc->map[i],
		    cmd->tx_data, cmd->tx_data_sz, at91_getaddr, &addr, 0)) !=
		    0)
			goto out;
		WR4(sc, PDC_TNPR, addr);
		WR4(sc, PDC_TNCR, cmd->tx_data_sz);
		bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
		mode[i++] = BUS_DMASYNC_POSTWRITE;
	}

	/*
	 * Set up the RX side of the transfer.
	 */
	if ((err = bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_cmd,
	    cmd->rx_cmd_sz, at91_getaddr, &addr, 0)) != 0)
		goto out;
	WR4(sc, PDC_RPR, addr);
	WR4(sc, PDC_RCR, cmd->rx_cmd_sz);
	bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
	mode[i++] = BUS_DMASYNC_POSTREAD;
	if (cmd->rx_data_sz > 0) {
		if ((err = bus_dmamap_load(sc->dmatag, sc->map[i],
		    cmd->rx_data, cmd->rx_data_sz, at91_getaddr, &addr, 0)) !=
		    0)
			goto out;
		WR4(sc, PDC_RNPR, addr);
		WR4(sc, PDC_RNCR, cmd->rx_data_sz);
		bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
		mode[i++] = BUS_DMASYNC_POSTREAD;
	}

	/*
	 * Start the transfer, wait for it to complete.
	 */
	sc->xfer_done = 0;
	WR4(sc, SPI_IER, SPI_SR_RXBUFF);
	WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN | PDC_PTCR_RXTEN);
	do
		err = tsleep(&sc->xfer_done, PCATCH | PZERO, "at91_spi", hz);
	while (sc->xfer_done == 0 && err != EINTR);

	/*
	 * Stop the transfer and clean things up.
	 */
	WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
	if (err == 0)
		for (j = 0; j < i; j++)
			bus_dmamap_sync(sc->dmatag, sc->map[j], mode[j]);
out:
	for (j = 0; j < i; j++)
		bus_dmamap_unload(sc->dmatag, sc->map[j]);

	sx_xunlock(&sc->xfer_mtx);

	return (err);
}
Exemple #11
0
static int
at91_spi_attach(device_t dev)
{
	struct at91_spi_softc *sc;
	int err;
	uint32_t csr;

	sc = device_get_softc(dev);

	sc->dev = dev;
	sx_init(&sc->xfer_mtx, device_get_nameunit(dev));

	/*
	 * Allocate resources.
	 */
	err = at91_spi_activate(dev);
	if (err)
		goto out;

	/*
	 * Set up the hardware.
	 */

	WR4(sc, SPI_CR, SPI_CR_SWRST);
	/* "Software Reset must be Written Twice" erratum */
	WR4(sc, SPI_CR, SPI_CR_SWRST);
	WR4(sc, SPI_IDR, 0xffffffff);

	WR4(sc, SPI_MR, (0xf << 24) | SPI_MR_MSTR | SPI_MR_MODFDIS |
	    CS_TO_MR(0));

	/*
	 * For now, run the bus at the slowest speed possible as otherwise we
	 * may encounter data corruption on transmit as seen with ETHERNUT5
	 * and AT45DB321D even though both board and slave device can take
	 * more.
	 * This also serves as a work-around for the "NPCSx rises if no data
	 * data is to be transmitted" erratum.  The ideal workaround for the
	 * latter is to take the chip select control away from the peripheral
	 * and manage it directly as a GPIO line.  The easy solution is to
	 * slow down the bus so dramatically that it just never gets starved
	 * as may be seen when the OCHI controller is running and consuming
	 * memory and APB bandwidth.
	 * Also, currently we lack a way for lettting both the board and the
	 * slave devices take their maximum supported SPI clocks into account.
	 */
	csr = SPI_CSR_CPOL | (4 << 16) | (0xff << 8);
	WR4(sc, SPI_CSR0, csr);
	WR4(sc, SPI_CSR1, csr);
	WR4(sc, SPI_CSR2, csr);
	WR4(sc, SPI_CSR3, csr);

	WR4(sc, SPI_CR, SPI_CR_SPIEN);

	WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS);
	WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS);
	WR4(sc, PDC_RNPR, 0);
	WR4(sc, PDC_RNCR, 0);
	WR4(sc, PDC_TNPR, 0);
	WR4(sc, PDC_TNCR, 0);
	WR4(sc, PDC_RPR, 0);
	WR4(sc, PDC_RCR, 0);
	WR4(sc, PDC_TPR, 0);
	WR4(sc, PDC_TCR, 0);
	RD4(sc, SPI_RDR);
	RD4(sc, SPI_SR);

	device_add_child(dev, "spibus", -1);
	bus_generic_attach(dev);
out:
	if (err)
		at91_spi_deactivate(dev);
	return (err);
}
static void
at91_usart_ungrab(struct uart_bas *bas)
{

	WR4(bas, USART_IER, USART_CSR_RXRDY);
}
Exemple #13
0
void
arm_mask_irq(uintptr_t nb)
{

	WR4(sc, IC_IDCR, 1 << nb);
}
Exemple #14
0
static int
tegra_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
{
    int rv, i;
    struct tegra_i2c_softc *sc;
    enum tegra_i2c_xfer_type xtype;

    sc = device_get_softc(dev);
    LOCK(sc);

    /* Get the bus. */
    while (sc->bus_inuse == 1)
        SLEEP(sc,  0);
    sc->bus_inuse = 1;

    rv = 0;
    for (i = 0; i < nmsgs; i++) {
        sc->msg = &msgs[i];
        sc->msg_idx = 0;
        sc->bus_err = 0;
        sc->done = 0;
        /* Check for valid parameters. */
        if (sc->msg == NULL || sc->msg->buf == NULL ||
                sc->msg->len == 0) {
            rv = EINVAL;
            break;
        }

        /* Get flags for next transfer. */
        if (i == (nmsgs - 1)) {
            if (msgs[i].flags & IIC_M_NOSTOP)
                xtype = XFER_CONTINUE;
            else
                xtype = XFER_STOP;
        } else {
            if (msgs[i + 1].flags & IIC_M_NOSTART)
                xtype = XFER_CONTINUE;
            else
                xtype = XFER_REPEAT_START;
        }
        tegra_i2c_start_msg(sc, sc->msg, xtype);
        if (cold)
            rv = tegra_i2c_poll(sc);
        else
            rv = msleep(&sc->done, &sc->mtx, PZERO, "iic",
                        I2C_REQUEST_TIMEOUT);

        WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0);
        WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, 0xFFFFFFFF);
        if (rv == 0)
            rv = sc->bus_err;
        if (rv != 0)
            break;
    }

    if (rv != 0) {
        tegra_i2c_hw_init(sc);
        tegra_i2c_flush_fifo(sc);
    }

    sc->msg = NULL;
    sc->msg_idx = 0;
    sc->bus_err = 0;
    sc->done = 0;

    /* Wake up the processes that are waiting for the bus. */
    sc->bus_inuse = 0;
    wakeup(sc);
    UNLOCK(sc);

    return (rv);
}
Exemple #15
0
static void
tegra_i2c_intr(void *arg)
{
    struct tegra_i2c_softc *sc;
    uint32_t status, reg;
    int rv;

    sc = (struct tegra_i2c_softc *)arg;

    LOCK(sc);
    status = RD4(sc, I2C_INTERRUPT_SOURCE_REGISTER);
    if (sc->msg == NULL) {
        /* Unexpected interrupt - disable FIFOs, clear reset. */
        reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER);
        reg &= ~I2C_INT_TFIFO_DATA_REQ;
        reg &= ~I2C_INT_RFIFO_DATA_REQ;
        WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0);
        WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, status);
        UNLOCK(sc);
        return;
    }

    if ((status & I2C_ERROR_MASK) != 0) {
        if (status & I2C_INT_NOACK)
            sc->bus_err = IIC_ENOACK;
        if (status & I2C_INT_ARB_LOST)
            sc->bus_err = IIC_EBUSERR;
        if ((status & I2C_INT_TFIFO_OVR) ||
                (status & I2C_INT_RFIFO_UNF))
            sc->bus_err = IIC_EBUSERR;
        sc->done = 1;
    } else if ((status & I2C_INT_RFIFO_DATA_REQ) &&
               (sc->msg != NULL) && (sc->msg->flags & IIC_M_RD)) {
        rv = tegra_i2c_rx(sc);
        if (rv == 0) {
            reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER);
            reg &= ~I2C_INT_RFIFO_DATA_REQ;
            WR4(sc, I2C_INTERRUPT_MASK_REGISTER, reg);
        }
    } else if ((status & I2C_INT_TFIFO_DATA_REQ) &&
               (sc->msg != NULL) && !(sc->msg->flags & IIC_M_RD)) {
        rv = tegra_i2c_tx(sc);
        if (rv == 0) {
            reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER);
            reg &= ~I2C_INT_TFIFO_DATA_REQ;
            WR4(sc, I2C_INTERRUPT_MASK_REGISTER, reg);
        }
    } else if ((status & I2C_INT_RFIFO_DATA_REQ) ||
               (status & I2C_INT_TFIFO_DATA_REQ)) {
        device_printf(sc->dev, "Unexpected data interrupt: 0x%08X\n",
                      status);
        reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER);
        reg &= ~I2C_INT_TFIFO_DATA_REQ;
        reg &= ~I2C_INT_RFIFO_DATA_REQ;
        WR4(sc, I2C_INTERRUPT_MASK_REGISTER, reg);
    }
    if (status & I2C_INT_PACKET_XFER_COMPLETE)
        sc->done = 1;
    WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, status);
    if (sc->done) {
        WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0);
        wakeup(&(sc->done));
    }
    UNLOCK(sc);
}
Exemple #16
0
static void
at91_mci_intr(void *arg)
{
	struct at91_mci_softc *sc = (struct at91_mci_softc*)arg;
	struct mmc_command *cmd = sc->curcmd;
	uint32_t sr, isr;

	AT91_MCI_LOCK(sc);

	sr = RD4(sc, MCI_SR);
	isr = sr & RD4(sc, MCI_IMR);

	if (mci_debug)
		printf("i 0x%x sr 0x%x\n", isr, sr);

	/*
	 * All interrupts are one-shot; disable it now.
	 * The next operation will re-enable whatever interrupts it wants.
	 */
	WR4(sc, MCI_IDR, isr);
	if (isr & MCI_SR_ERROR) {
		if (isr & (MCI_SR_RTOE | MCI_SR_DTOE))
			cmd->error = MMC_ERR_TIMEOUT;
		else if (isr & (MCI_SR_RCRCE | MCI_SR_DCRCE))
			cmd->error = MMC_ERR_BADCRC;
		else if (isr & (MCI_SR_OVRE | MCI_SR_UNRE))
			cmd->error = MMC_ERR_FIFO;
		else
			cmd->error = MMC_ERR_FAILED;
		/*
		 * CMD8 is used to probe for SDHC cards, a standard SD card
		 * will get a response timeout; don't report it because it's a
		 * normal and expected condition.  One might argue that all
		 * error reporting should be left to higher levels, but when
		 * they report at all it's always EIO, which isn't very
		 * helpful. XXX bootverbose?
		 */
		if (cmd->opcode != 8) {
			device_printf(sc->dev,
			    "IO error; status MCI_SR = 0x%x cmd opcode = %d%s\n",
			    sr, cmd->opcode,
			    (cmd->opcode != 12) ? "" :
			    (sc->flags & CMD_MULTIREAD) ? " after read" : " after write");
			at91_mci_reset(sc);
		}
		at91_mci_next_operation(sc);
	} else {
		if (isr & MCI_SR_TXBUFE) {
//			printf("TXBUFE\n");
			/*
			 * We need to wait for a BLKE that follows TXBUFE
			 * (intermediate BLKEs might happen after ENDTXes if
			 * we're chaining multiple buffers).  If BLKE is also
			 * asserted at the time we get TXBUFE, we can avoid
			 * another interrupt and process it right away, below.
			 */
			if (sr & MCI_SR_BLKE)
				isr |= MCI_SR_BLKE;
			else
				WR4(sc, MCI_IER, MCI_SR_BLKE);
		}
		if (isr & MCI_SR_RXBUFF) {
//			printf("RXBUFF\n");
		}
		if (isr & MCI_SR_ENDTX) {
//			printf("ENDTX\n");
		}
		if (isr & MCI_SR_ENDRX) {
//			printf("ENDRX\n");
			at91_mci_read_done(sc, sr);
		}
		if (isr & MCI_SR_NOTBUSY) {
//			printf("NOTBUSY\n");
			at91_mci_notbusy(sc);
		}
		if (isr & MCI_SR_DTIP) {
//			printf("Data transfer in progress\n");
		}
		if (isr & MCI_SR_BLKE) {
//			printf("Block transfer end\n");
			at91_mci_write_done(sc, sr);
		}
		if (isr & MCI_SR_TXRDY) {
//			printf("Ready to transmit\n");
		}
		if (isr & MCI_SR_RXRDY) {
//			printf("Ready to receive\n");
		}
		if (isr & MCI_SR_CMDRDY) {
//			printf("Command ready\n");
			at91_mci_cmdrdy(sc, sr);
		}
	}
	AT91_MCI_UNLOCK(sc);
}
Exemple #17
0
static int
tegra124_pmc_attach(device_t dev)
{
	struct tegra124_pmc_softc *sc;
	int rid, rv;
	uint32_t reg;
	phandle_t node;

	sc = device_get_softc(dev);
	sc->dev = dev;
	node = ofw_bus_get_node(dev);

	rv = tegra124_pmc_parse_fdt(sc, node);
	if (rv != 0) {
		device_printf(sc->dev, "Cannot parse FDT data\n");
		return (rv);
	}

	rv = clk_get_by_ofw_name(sc->dev, 0, "pclk", &sc->clk);
	if (rv != 0) {
		device_printf(sc->dev, "Cannot get \"pclk\" clock\n");
		return (ENXIO);
	}

	rid = 0;
	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
	    RF_ACTIVE);
	if (sc->mem_res == NULL) {
		device_printf(dev, "Cannot allocate memory resources\n");
		return (ENXIO);
	}

	PMC_LOCK_INIT(sc);

	/* Enable CPU power request. */
	reg = RD4(sc, PMC_CNTRL);
	reg |= PMC_CNTRL_CPU_PWRREQ_OE;
	WR4(sc, PMC_CNTRL, reg);

	/* Set sysclk output polarity */
	reg = RD4(sc, PMC_CNTRL);
	if (sc->sysclkreq_high)
		reg &= ~PMC_CNTRL_SYSCLK_POLARITY;
	else
		reg |= PMC_CNTRL_SYSCLK_POLARITY;
	WR4(sc, PMC_CNTRL, reg);

	/* Enable sysclk request. */
	reg = RD4(sc, PMC_CNTRL);
	reg |= PMC_CNTRL_SYSCLK_OE;
	WR4(sc, PMC_CNTRL, reg);

	/*
	 * Remove HDMI from deep power down mode.
	 * XXX mote this to HDMI driver
	 */
	reg = RD4(sc, PMC_IO_DPD_STATUS);
	reg &= ~ PMC_IO_DPD_STATUS_HDMI;
	WR4(sc, PMC_IO_DPD_STATUS, reg);

	reg = RD4(sc, PMC_IO_DPD2_STATUS);
	reg &= ~ PMC_IO_DPD2_STATUS_HV;
	WR4(sc, PMC_IO_DPD2_STATUS, reg);

	if (pmc_sc != NULL)
		panic("tegra124_pmc: double driver attach");
	pmc_sc = sc;
	return (0);
}
Exemple #18
0
static int
tegra_rtc_attach(device_t dev)
{
	int rv, rid;
	struct tegra_rtc_softc *sc;

	sc = device_get_softc(dev);
	sc->dev = dev;

	LOCK_INIT(sc);

	/* Get the memory resource for the register mapping. */
	rid = 0;
	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
	    RF_ACTIVE);
	if (sc->mem_res == NULL) {
		device_printf(dev, "Cannot map registers.\n");
		rv = ENXIO;
		goto fail;
	}

	/* Allocate our IRQ resource. */
	rid = 0;
	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
	    RF_ACTIVE);
	if (sc->irq_res == NULL) {
		device_printf(dev, "Cannot allocate interrupt.\n");
		rv = ENXIO;
		goto fail;
	}

	/* OFW resources. */
	rv = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
	if (rv != 0) {
		device_printf(dev, "Cannot get i2c clock: %d\n", rv);
		goto fail;
	}
	rv = clk_enable(sc->clk);
	if (rv != 0) {
		device_printf(dev, "Cannot enable clock: %d\n", rv);
		goto fail;
	}

	/* Init hardware. */
	WR4(sc, RTC_SECONDS_ALARM0, 0);
	WR4(sc, RTC_SECONDS_ALARM1, 0);
	WR4(sc, RTC_INTR_STATUS, 0xFFFFFFFF);
	WR4(sc, RTC_INTR_MASK, 0);

	/* Setup  interrupt */
	rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
	    NULL, tegra_rtc_intr, sc, &sc->irq_h);
	if (rv) {
		device_printf(dev, "Cannot setup interrupt.\n");
		goto fail;
	}

	/*
	 * Register as a time of day clock with 1-second resolution.
	 *
	 * XXXX Not yet, we don't have support for multiple RTCs
	 */
	/* clock_register(dev, 1000000); */

	return (bus_generic_attach(dev));

fail:
	if (sc->clk != NULL)
		clk_release(sc->clk);
	if (sc->irq_h != NULL)
		bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
	if (sc->irq_res != NULL)
		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
	if (sc->mem_res != NULL)
		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
	LOCK_DESTROY(sc);

	return (rv);
}
Exemple #19
0
static void
at91_mci_stop_done(struct at91_mci_softc *sc, uint32_t sr)
{
	struct mmc_command *cmd = sc->curcmd;

	/*
	 * We arrive here after receiving CMDRDY for a MMC_STOP_TRANSMISSION
	 * command.  Depending on the operation being stopped, we may have to
	 * do some unusual things to work around hardware bugs.
	 */

	/*
	 * This is known to be true of at91rm9200 hardware; it may or may not
	 * apply to more recent chips:
	 *
	 * After stopping a multi-block write, the NOTBUSY bit in MCI_SR does
	 * not properly reflect the actual busy state of the card as signaled
	 * on the DAT0 line; it always claims the card is not-busy.  If we
	 * believe that and let operations continue, following commands will
	 * fail with response timeouts (except of course MMC_SEND_STATUS -- it
	 * indicates the card is busy in the PRG state, which was the smoking
	 * gun that showed MCI_SR NOTBUSY was not tracking DAT0 correctly).
	 *
	 * The atmel docs are emphatic: "This flag [NOTBUSY] must be used only
	 * for Write Operations."  I guess technically since we sent a stop
	 * it's not a write operation anymore.  But then just what did they
	 * think it meant for the stop command to have "...an optional busy
	 * signal transmitted on the data line" according to the SD spec?
	 *
	 * I tried a variety of things to un-wedge the MCI and get the status
	 * register to reflect NOTBUSY correctly again, but the only thing
	 * that worked was a full device reset.  It feels like an awfully big
	 * hammer, but doing a full reset after every multiblock write is
	 * still faster than doing single-block IO (by almost two orders of
	 * magnitude: 20KB/sec improves to about 1.8MB/sec best case).
	 *
	 * After doing the reset, wait for a NOTBUSY interrupt before
	 * continuing with the next operation.
	 *
	 * This workaround breaks multiwrite on the rev2xx parts, but some other
	 * workaround is needed.
	 */
	if ((sc->flags & CMD_MULTIWRITE) && (sc->sc_cap & CAP_NEEDS_BYTESWAP)) {
		at91_mci_reset(sc);
		WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_NOTBUSY);
		return;
	}

	/*
	 * This is known to be true of at91rm9200 hardware; it may or may not
	 * apply to more recent chips:
	 *
	 * After stopping a multi-block read, loop to read and discard any
	 * data that coasts in after we sent the stop command.  The docs don't
	 * say anything about it, but empirical testing shows that 1-3
	 * additional words of data get buffered up in some unmentioned
	 * internal fifo and if we don't read and discard them here they end
	 * up on the front of the next read DMA transfer we do.
	 *
	 * This appears to be unnecessary for rev2xx parts.
	 */
	if ((sc->flags & CMD_MULTIREAD) && (sc->sc_cap & CAP_NEEDS_BYTESWAP)) {
		uint32_t sr;
		int count = 0;

		do {
			sr = RD4(sc, MCI_SR);
			if (sr & MCI_SR_RXRDY) {
				RD4(sc,  MCI_RDR);
				++count;
			}
		} while (sr & MCI_SR_RXRDY);
		at91_mci_reset(sc);
	}

	cmd->error = MMC_ERR_NONE;
	at91_mci_next_operation(sc);

}
Exemple #20
0
/* Clear previous configuration of the PL by asserting PROG_B. */
static int
zy7_devcfg_reset_pl(struct zy7_devcfg_softc *sc)
{
	uint32_t devcfg_ctl;
	int tries, err;

	DEVCFG_SC_ASSERT_LOCKED(sc);

	devcfg_ctl = RD4(sc, ZY7_DEVCFG_CTRL);

	/* Clear sticky bits and set up INIT signal positive edge interrupt. */
	WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);
	WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE);

	/* Deassert PROG_B (active low). */
	devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B;
	WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl);

	/*
	 * Wait for INIT to assert.  If it is already asserted, we may not get
	 * an edge interrupt so cancel it and continue.
	 */
	if ((RD4(sc, ZY7_DEVCFG_STATUS) &
	     ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) {
		/* Already asserted.  Cancel interrupt. */
		WR4(sc, ZY7_DEVCFG_INT_MASK, ~0);
	}
	else {
		/* Wait for positive edge interrupt. */
		err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i1", hz);
		if (err != 0)
			return (err);
	}
	
	/* Reassert PROG_B (active low). */
	devcfg_ctl &= ~ZY7_DEVCFG_CTRL_PCFG_PROG_B;
	WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl);

	/* Wait for INIT deasserted.  This happens almost instantly. */
	tries = 0;
	while ((RD4(sc, ZY7_DEVCFG_STATUS) &
		ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) {
		if (++tries >= 100)
			return (EIO);
		DELAY(5);
	}

	/* Clear sticky bits and set up INIT positive edge interrupt. */
	WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);
	WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE);

	/* Deassert PROG_B again. */
	devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B;
	WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl);

	/*
	 * Wait for INIT asserted indicating FPGA internal initialization
	 * is complete.
	 */
	err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i2", hz);
	if (err != 0)
		return (err);

	/* Clear sticky DONE bit in interrupt status. */
	WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);

	return (0);
}
Exemple #21
0
static void
ffec_miibus_statchg(device_t dev)
{
	struct ffec_softc *sc;
	struct mii_data *mii;
	uint32_t ecr, rcr, tcr;

	/*
	 * Called by the MII bus driver when the PHY establishes link to set the
	 * MAC interface registers.
	 */

	sc = device_get_softc(dev);

	FFEC_ASSERT_LOCKED(sc);

	mii = sc->mii_softc;

	if (mii->mii_media_status & IFM_ACTIVE)
		sc->link_is_up = true;
	else
		sc->link_is_up = false;

	ecr = RD4(sc, FEC_ECR_REG) & ~FEC_ECR_SPEED;
	rcr = RD4(sc, FEC_RCR_REG) & ~(FEC_RCR_RMII_10T | FEC_RCR_RMII_MODE |
	    FEC_RCR_RGMII_EN | FEC_RCR_DRT | FEC_RCR_FCE);
	tcr = RD4(sc, FEC_TCR_REG) & ~FEC_TCR_FDEN;

	rcr |= FEC_RCR_MII_MODE; /* Must always be on even for R[G]MII. */
	switch (sc->phy_conn_type) {
	case PHY_CONN_MII:
		break;
	case PHY_CONN_RMII:
		rcr |= FEC_RCR_RMII_MODE;
		break;
	case PHY_CONN_RGMII:
		rcr |= FEC_RCR_RGMII_EN;
		break;
	}

	switch (IFM_SUBTYPE(mii->mii_media_active)) {
	case IFM_1000_T:
	case IFM_1000_SX:
		ecr |= FEC_ECR_SPEED;
		break;
	case IFM_100_TX:
		/* Not-FEC_ECR_SPEED + not-FEC_RCR_RMII_10T means 100TX */
		break;
	case IFM_10_T:
		rcr |= FEC_RCR_RMII_10T;
		break;
	case IFM_NONE:
		sc->link_is_up = false;
		return;
	default:
		sc->link_is_up = false;
		device_printf(dev, "Unsupported media %u\n",
		    IFM_SUBTYPE(mii->mii_media_active));
		return;
	}

	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
		tcr |= FEC_TCR_FDEN;
	else
		rcr |= FEC_RCR_DRT;

	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FLOW) != 0)
		rcr |= FEC_RCR_FCE;

	WR4(sc, FEC_RCR_REG, rcr);
	WR4(sc, FEC_TCR_REG, tcr);
	WR4(sc, FEC_ECR_REG, ecr);
}
Exemple #22
0
static int
zy7_devcfg_write(struct cdev *dev, struct uio *uio, int ioflag)
{
	struct zy7_devcfg_softc *sc = dev->si_drv1;
	void *dma_mem;
	bus_addr_t dma_physaddr;
	int segsz, err;

	DEVCFG_SC_LOCK(sc);

	/* First write?  Reset PL. */
	if (uio->uio_offset == 0 && uio->uio_resid > 0)	{
		zy7_devcfg_init_hw(sc);
		zy7_slcr_preload_pl();
		err = zy7_devcfg_reset_pl(sc);
		if (err != 0) {
			DEVCFG_SC_UNLOCK(sc);
			return (err);
		}
	}

	/* Allocate dma memory and load. */
	err = bus_dmamem_alloc(sc->dma_tag, &dma_mem, BUS_DMA_NOWAIT,
			       &sc->dma_map);
	if (err != 0) {
		DEVCFG_SC_UNLOCK(sc);
		return (err);
	}
	err = bus_dmamap_load(sc->dma_tag, sc->dma_map, dma_mem, PAGE_SIZE,
			      zy7_dma_cb2, &dma_physaddr, 0);
	if (err != 0) {
		bus_dmamem_free(sc->dma_tag, dma_mem, sc->dma_map);
		DEVCFG_SC_UNLOCK(sc);
		return (err);
	}

	while (uio->uio_resid > 0) {
		/* If DONE signal has been set, we shouldn't write anymore. */
		if ((RD4(sc, ZY7_DEVCFG_INT_STATUS) &
		     ZY7_DEVCFG_INT_PCFG_DONE) != 0) {
			err = EIO;
			break;
		}

		/* uiomove the data from user buffer to our dma map. */
		segsz = MIN(PAGE_SIZE, uio->uio_resid);
		DEVCFG_SC_UNLOCK(sc);
		err = uiomove(dma_mem, segsz, uio);
		DEVCFG_SC_LOCK(sc);
		if (err != 0)
			break;

		/* Flush the cache to memory. */
		bus_dmamap_sync(sc->dma_tag, sc->dma_map,
				BUS_DMASYNC_PREWRITE);

		/* Program devcfg's DMA engine.  The ordering of these
		 * register writes is critical.
		 */
		if (uio->uio_resid > segsz)
			WR4(sc, ZY7_DEVCFG_DMA_SRC_ADDR,
			    (uint32_t) dma_physaddr);
		else
			WR4(sc, ZY7_DEVCFG_DMA_SRC_ADDR,
			    (uint32_t) dma_physaddr |
			    ZY7_DEVCFG_DMA_ADDR_WAIT_PCAP);
		WR4(sc, ZY7_DEVCFG_DMA_DST_ADDR, ZY7_DEVCFG_DMA_ADDR_ILLEGAL);
		WR4(sc, ZY7_DEVCFG_DMA_SRC_LEN, (segsz+3)/4);
		WR4(sc, ZY7_DEVCFG_DMA_DST_LEN, 0);

		/* Now clear done bit and set up DMA done interrupt. */
		WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);
		WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_DMA_DONE);

		/* Wait for DMA done interrupt. */
		err = mtx_sleep(sc->dma_map, &sc->sc_mtx, PCATCH,
				"zy7dma", hz);
		if (err != 0)
			break;

		bus_dmamap_sync(sc->dma_tag, sc->dma_map,
				BUS_DMASYNC_POSTWRITE);

		/* Check DONE signal. */
		if ((RD4(sc, ZY7_DEVCFG_INT_STATUS) &
		     ZY7_DEVCFG_INT_PCFG_DONE) != 0)
			zy7_slcr_postload_pl(zy7_en_level_shifters);
	}

	bus_dmamap_unload(sc->dma_tag, sc->dma_map);
	bus_dmamem_free(sc->dma_tag, dma_mem, sc->dma_map);
	DEVCFG_SC_UNLOCK(sc);
	return (err);
}
Exemple #23
0
static void
ffec_rxfinish_locked(struct ffec_softc *sc)
{
	struct ffec_hwdesc *desc;
	int len;
	boolean_t produced_empty_buffer;

	FFEC_ASSERT_LOCKED(sc);

	/* XXX Can't set PRE|POST right now, but we need both. */
	bus_dmamap_sync(sc->rxdesc_tag, sc->rxdesc_map, BUS_DMASYNC_PREREAD);
	bus_dmamap_sync(sc->rxdesc_tag, sc->rxdesc_map, BUS_DMASYNC_POSTREAD);
	produced_empty_buffer = false;
	for (;;) {
		desc = &sc->rxdesc_ring[sc->rx_idx];
		if (desc->flags_len & FEC_RXDESC_EMPTY)
			break;
		produced_empty_buffer = true;
		len = (desc->flags_len & FEC_RXDESC_LEN_MASK);
		if (len < 64) {
			/*
			 * Just recycle the descriptor and continue.           .
			 */
			ffec_setup_rxdesc(sc, sc->rx_idx,
			    sc->rxdesc_ring[sc->rx_idx].buf_paddr);
		} else if ((desc->flags_len & FEC_RXDESC_L) == 0) {
			/*
			 * The entire frame is not in this buffer.  Impossible.
			 * Recycle the descriptor and continue.
			 *
			 * XXX what's the right way to handle this? Probably we
			 * should stop/init the hardware because this should
			 * just really never happen when we have buffers bigger
			 * than the maximum frame size.
			 */
			device_printf(sc->dev, 
			    "fec_rxfinish: received frame without LAST bit set");
			ffec_setup_rxdesc(sc, sc->rx_idx, 
			    sc->rxdesc_ring[sc->rx_idx].buf_paddr);
		} else if (desc->flags_len & FEC_RXDESC_ERROR_BITS) {
			/*
			 *  Something went wrong with receiving the frame, we
			 *  don't care what (the hardware has counted the error
			 *  in the stats registers already), we just reuse the
			 *  same mbuf, which is still dma-mapped, by resetting
			 *  the rx descriptor.
			 */
			ffec_setup_rxdesc(sc, sc->rx_idx, 
			    sc->rxdesc_ring[sc->rx_idx].buf_paddr);
		} else {
			/*
			 *  Normal case: a good frame all in one buffer.
			 */
			ffec_rxfinish_onebuf(sc, len);
		}
		sc->rx_idx = next_rxidx(sc, sc->rx_idx);
	}

	if (produced_empty_buffer) {
		bus_dmamap_sync(sc->rxdesc_tag, sc->txdesc_map, BUS_DMASYNC_PREWRITE);
		WR4(sc, FEC_RDAR_REG, FEC_RDAR_RDAR);
		bus_dmamap_sync(sc->rxdesc_tag, sc->txdesc_map, BUS_DMASYNC_POSTWRITE);
	}
}
Exemple #24
0
static int
zy7_devcfg_attach(device_t dev)
{
	struct zy7_devcfg_softc *sc = device_get_softc(dev);
	int i;
	int rid, err;

	/* Allow only one attach. */
	if (zy7_devcfg_softc_p != NULL)
		return (ENXIO);

	sc->dev = dev;

	DEVCFG_SC_LOCK_INIT(sc);

	/* Get memory resource. */
	rid = 0;
	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
					     RF_ACTIVE);
	if (sc->mem_res == NULL) {
		device_printf(dev, "could not allocate memory resources.\n");
		zy7_devcfg_detach(dev);
		return (ENOMEM);
	}

	/* Allocate IRQ. */
	rid = 0;
	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
					     RF_ACTIVE);
	if (sc->irq_res == NULL) {
		device_printf(dev, "cannot allocate IRQ\n");
		zy7_devcfg_detach(dev);
		return (ENOMEM);
	}

	/* Activate the interrupt. */
	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
			     NULL, zy7_devcfg_intr, sc, &sc->intrhandle);
	if (err) {
		device_printf(dev, "cannot setup IRQ\n");
		zy7_devcfg_detach(dev);
		return (err);
	}

	/* Create /dev/devcfg */
	sc->sc_ctl_dev = make_dev(&zy7_devcfg_cdevsw, 0,
			  UID_ROOT, GID_WHEEL, 0600, "devcfg");
	if (sc->sc_ctl_dev == NULL) {
		device_printf(dev, "failed to create /dev/devcfg");
		zy7_devcfg_detach(dev);
		return (ENXIO);
	}
	sc->sc_ctl_dev->si_drv1 = sc;

	zy7_devcfg_softc_p = sc;

	/* Unlock devcfg registers. */
	WR4(sc, ZY7_DEVCFG_UNLOCK, ZY7_DEVCFG_UNLOCK_MAGIC);

	/* Make sure interrupts are completely disabled. */
	WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);
	WR4(sc, ZY7_DEVCFG_INT_MASK, 0xffffffff);

	/* Get PS_VERS for SYSCTL. */
	zy7_ps_vers = (RD4(sc, ZY7_DEVCFG_MCTRL) &
		       ZY7_DEVCFG_MCTRL_PS_VERS_MASK) >>
		ZY7_DEVCFG_MCTRL_PS_VERS_SHIFT;

	for (i = 0; i < FCLK_NUM; i++) {
		fclk_configs[i].source = zy7_pl_fclk_get_source(i);
		fclk_configs[i].actual_frequency = 
			zy7_pl_fclk_enabled(i) ? zy7_pl_fclk_get_freq(i) : 0;
		/* Initially assume actual frequency is the configure one */
		fclk_configs[i].frequency = fclk_configs[i].actual_frequency;
	}

	if (zy7_devcfg_init_fclk_sysctl(sc) < 0)
		device_printf(dev, "failed to initialized sysctl tree\n");

	return (0);
}
Exemple #25
0
static int
at91_usart_bus_attach(struct uart_softc *sc)
{
	int err;
	int i;
	uint32_t cr;
	struct at91_usart_softc *atsc;

	atsc = (struct at91_usart_softc *)sc;

	if (at91_usart_requires_rts0_workaround(sc))
		atsc->flags |= USE_RTS0_WORKAROUND;

	/*
	 * See if we have a TIMEOUT bit.  We disable all interrupts as
	 * a side effect.  Boot loaders may have enabled them.  Since
	 * a TIMEOUT interrupt can't happen without other setup, the
	 * apparent race here can't actually happen.
	 */
	WR4(&sc->sc_bas, USART_IDR, 0xffffffff);
	WR4(&sc->sc_bas, USART_IER, USART_CSR_TIMEOUT);
	if (RD4(&sc->sc_bas, USART_IMR) & USART_CSR_TIMEOUT)
		atsc->flags |= HAS_TIMEOUT;
	WR4(&sc->sc_bas, USART_IDR, 0xffffffff);

	/*
	 * Allocate transmit DMA tag and map.  We allow a transmit buffer
	 * to be any size, but it must map to a single contiguous physical
	 * extent.
	 */
	err = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
	    BUS_SPACE_MAXSIZE_32BIT, 1, BUS_SPACE_MAXSIZE_32BIT, 0, NULL,
	    NULL, &atsc->tx_tag);
	if (err != 0)
		goto errout;
	err = bus_dmamap_create(atsc->tx_tag, 0, &atsc->tx_map);
	if (err != 0)
		goto errout;

	if (atsc->flags & HAS_TIMEOUT) {
		/*
		 * Allocate receive DMA tags, maps, and buffers.
		 * The receive buffers should be aligned to arm_dcache_align,
		 * otherwise partial cache line flushes on every receive
		 * interrupt are pretty much guaranteed.
		 */
		err = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),
		    arm_dcache_align, 0, BUS_SPACE_MAXADDR_32BIT,
		    BUS_SPACE_MAXADDR, NULL, NULL, sc->sc_rxfifosz, 1,
		    sc->sc_rxfifosz, BUS_DMA_ALLOCNOW, NULL, NULL,
		    &atsc->rx_tag);
		if (err != 0)
			goto errout;
		for (i = 0; i < 2; i++) {
			err = bus_dmamem_alloc(atsc->rx_tag,
			    (void **)&atsc->ping_pong[i].buffer,
			    BUS_DMA_NOWAIT, &atsc->ping_pong[i].map);
			if (err != 0)
				goto errout;
			err = bus_dmamap_load(atsc->rx_tag,
			    atsc->ping_pong[i].map,
			    atsc->ping_pong[i].buffer, sc->sc_rxfifosz,
			    at91_getaddr, &atsc->ping_pong[i].pa, 0);
			if (err != 0)
				goto errout;
			bus_dmamap_sync(atsc->rx_tag, atsc->ping_pong[i].map,
			    BUS_DMASYNC_PREREAD);
		}
		atsc->ping = &atsc->ping_pong[0];
		atsc->pong = &atsc->ping_pong[1];
	}

	/* Turn on rx and tx */
	cr = USART_CR_RSTSTA | USART_CR_RSTRX | USART_CR_RSTTX;
	WR4(&sc->sc_bas, USART_CR, cr);
	WR4(&sc->sc_bas, USART_CR, USART_CR_RXEN | USART_CR_TXEN);

	/*
	 * Setup the PDC to receive data.  We use the ping-pong buffers
	 * so that we can more easily bounce between the two and so that
	 * we get an interrupt 1/2 way through the software 'fifo' we have
	 * to avoid overruns.
	 */
	if (atsc->flags & HAS_TIMEOUT) {
		WR4(&sc->sc_bas, PDC_RPR, atsc->ping->pa);
		WR4(&sc->sc_bas, PDC_RCR, sc->sc_rxfifosz);
		WR4(&sc->sc_bas, PDC_RNPR, atsc->pong->pa);
		WR4(&sc->sc_bas, PDC_RNCR, sc->sc_rxfifosz);
		WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_RXTEN);

		/*
		 * Set the receive timeout to be 1.5 character times
		 * assuming 8N1.
		 */
		WR4(&sc->sc_bas, USART_RTOR, 15);
		WR4(&sc->sc_bas, USART_CR, USART_CR_STTTO);
		WR4(&sc->sc_bas, USART_IER, USART_CSR_TIMEOUT |
		    USART_CSR_RXBUFF | USART_CSR_ENDRX);
	} else {
		WR4(&sc->sc_bas, USART_IER, USART_CSR_RXRDY);
	}
	WR4(&sc->sc_bas, USART_IER, USART_CSR_RXBRK | USART_DCE_CHANGE_BITS);

	/* Prime sc->hwsig with the initial hw line states. */
	at91_usart_bus_getsig(sc);

errout:
	return (err);
}
Exemple #26
0
static int
at91_rst_attach(device_t dev)
{
	struct rst_softc *sc;
	const char *cause;
	int rid, err;

	rst_sc = sc = device_get_softc(dev);
	sc->sc_dev = dev;

	callout_init(&sc->tick_ch, 0);

	rid = 0;
	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
	    RF_ACTIVE);
	if (sc->mem_res == NULL) {
		device_printf(dev, "could not allocate memory resources.\n");
		err = ENOMEM;
		goto out;
	}
	rid = 0;
	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
	    RF_ACTIVE | RF_SHAREABLE);
	if (sc->irq_res == NULL) {
		device_printf(dev, "could not allocate interrupt resources.\n");
		err = ENOMEM;
		goto out;
	}

	/* Activate the interrupt. */
	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
	    rst_intr, NULL, sc, &sc->intrhand);
	if (err)
		device_printf(dev, "could not establish interrupt handler.\n");

	WR4(rst_sc, RST_MR, RST_MR_ERSTL(0xd) | RST_MR_URSIEN | RST_MR_KEY);

	switch (RD4(sc, RST_SR) & RST_SR_RST_MASK) {
		case	RST_SR_RST_POW:
			cause = "Power On";
			break;
		case	RST_SR_RST_WAKE:
			cause = "Wake Up";
			break;
		case	RST_SR_RST_WDT:	
			cause = "Watchdog";
			break;
		case	RST_SR_RST_SOFT:
			cause = "Software Request";
			break;
		case	RST_SR_RST_USR:
			cause = "External (User)";
			break;
		default:
			cause = "Unknown";
			break;
	}

	device_printf(dev, "Reset cause: %s.\n", cause);
	/* cpu_reset_addr = cpu_reset; */

out:
	return (err);
}
static int
at91_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
{
	struct at91_spi_softc *sc;
	int i, j, rxdone, err, mode[4];
	bus_addr_t addr;

	sc = device_get_softc(dev);
	WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
	i = 0;
	if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_cmd,
	    cmd->tx_cmd_sz, at91_getaddr, &addr, 0) != 0)
		goto out;
	WR4(sc, PDC_TPR, addr);
	WR4(sc, PDC_TCR, cmd->tx_cmd_sz);
	bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
	mode[i++] = BUS_DMASYNC_POSTWRITE;
	if (cmd->tx_data_sz > 0) {
		if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_data,
			cmd->tx_data_sz, at91_getaddr, &addr, 0) != 0)
			goto out;
		WR4(sc, PDC_TNPR, addr);
		WR4(sc, PDC_TNCR, cmd->tx_data_sz);
		bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
		mode[i++] = BUS_DMASYNC_POSTWRITE;
	}
	if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_cmd,
	    cmd->tx_cmd_sz, at91_getaddr, &addr, 0) != 0)
		goto out;
	WR4(sc, PDC_RPR, addr);
	WR4(sc, PDC_RCR, cmd->tx_cmd_sz);
	bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
	mode[i++] = BUS_DMASYNC_POSTREAD;
	if (cmd->rx_data_sz > 0) {
		if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_data,
			cmd->tx_data_sz, at91_getaddr, &addr, 0) != 0)
			goto out;
		WR4(sc, PDC_RNPR, addr);
		WR4(sc, PDC_RNCR, cmd->rx_data_sz);
		bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
		mode[i++] = BUS_DMASYNC_POSTREAD;
	}
	WR4(sc, SPI_IER, SPI_SR_ENDRX);
	WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN | PDC_PTCR_RXTEN);

	rxdone = sc->rxdone;
	do {
		err = tsleep(&sc->rxdone, PCATCH | PZERO, "spi", hz);
	} while (rxdone == sc->rxdone && err != EINTR);
	WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
	if (err == 0) {
		for (j = 0; j < i; j++) 
			bus_dmamap_sync(sc->dmatag, sc->map[j], mode[j]);
	}
	for (j = 0; j < i; j++)
		bus_dmamap_unload(sc->dmatag, sc->map[j]);
	return (err);
out:;
	for (j = 0; j < i; j++)
		bus_dmamap_unload(sc->dmatag, sc->map[j]);
	return (EIO);
}
Exemple #28
0
static void
at91_mci_cmdrdy(struct at91_mci_softc *sc, uint32_t sr)
{
	struct mmc_command *cmd = sc->curcmd;
	int i;

	if (cmd == NULL)
		return;

	/*
	 * We get here at the end of EVERY command.  We retrieve the command
	 * response (if any) then decide what to do next based on the command.
	 */

	if (cmd->flags & MMC_RSP_PRESENT) {
		for (i = 0; i < ((cmd->flags & MMC_RSP_136) ? 4 : 1); i++) {
			cmd->resp[i] = RD4(sc, MCI_RSPR + i * 4);
			if (mci_debug)
				printf("RSPR[%d] = %x sr=%x\n", i, cmd->resp[i],  sr);
		}
	}

	/*
	 * If this was a stop command, go handle the various special
	 * conditions (read: bugs) that have to be dealt with following a stop.
	 */
	if (cmd->opcode == MMC_STOP_TRANSMISSION) {
		at91_mci_stop_done(sc, sr);
		return;
	}

	/*
	 * If this command can continue to assert BUSY beyond the response then
	 * we need to wait for NOTBUSY before the command is really done.
	 *
	 * Note that this may not work properly on the at91rm9200.  It certainly
	 * doesn't work for the STOP command that follows a multi-block write,
	 * so post-stop CMDRDY is handled separately; see the special handling
	 * in at91_mci_stop_done().
	 *
	 * Beside STOP, there are other R1B-type commands that use the busy
	 * signal after CMDRDY: CMD7 (card select), CMD28-29 (write protect),
	 * CMD38 (erase). I haven't tested any of them, but I rather expect
	 * them all to have the same sort of problem with MCI_SR not actually
	 * reflecting the state of the DAT0-line busy indicator.  So this code
	 * may need to grow some sort of special handling for them too. (This
	 * just in: CMD7 isn't a problem right now because dev/mmc.c incorrectly
	 * sets the response flags to R1 rather than R1B.) XXX
	 */
	if ((cmd->flags & MMC_RSP_BUSY)) {
		WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_NOTBUSY);
		return;
	}

	/*
	 * If there is a data transfer with this command, then...
	 * - If it's a read, we need to wait for ENDRX.
	 * - If it's a write, now is the time to enable the PDC, and we need
	 *   to wait for a BLKE that follows a TXBUFE, because if we're doing
	 *   a split transfer we get a BLKE after the first half (when TPR/TCR
	 *   get loaded from TNPR/TNCR).  So first we wait for the TXBUFE, and
	 *   the handling for that interrupt will then invoke the wait for the
	 *   subsequent BLKE which indicates actual completion.
	 */
	if (cmd->data) {
		uint32_t ier;
		if (cmd->data->flags & MMC_DATA_READ) {
			ier = MCI_SR_ENDRX;
		} else {
			ier = MCI_SR_TXBUFE;
			WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN);
		}
		WR4(sc, MCI_IER, MCI_SR_ERROR | ier);
		return;
	}

	/*
	 * If we made it to here, we don't need to wait for anything more for
	 * the current command, move on to the next command (will complete the
	 * request if there is no next command).
	 */
	cmd->error = MMC_ERR_NONE;
	at91_mci_next_operation(sc);
}
Exemple #29
0
static int
at91_twi_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
{
	struct at91_twi_softc *sc;
	int i, len, err;
	uint32_t rdwr;
	uint8_t *buf;
	uint32_t sr;

	sc = device_get_softc(dev);
	err = 0;
	AT91_TWI_LOCK(sc);
	for (i = 0; i < nmsgs; i++) {
		/*
		 * The linux atmel driver doesn't use the internal device
		 * address feature of twi.  A separate i2c message needs to
		 * be written to use this.
		 * See http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
		 * for details.  Upon reflection, we could use this as an
		 * optimization, but it is unclear the code bloat will
		 * result in faster/better operations.
		 */
		rdwr = (msgs[i].flags & IIC_M_RD) ? TWI_MMR_MREAD : 0;
		WR4(sc, TWI_MMR, TWI_MMR_DADR(msgs[i].slave) | rdwr);
		len = msgs[i].len;
		buf = msgs[i].buf;
		/* zero byte transfers aren't allowed */
		if (len == 0 || buf == NULL) {
			err = EINVAL;
			goto out;
		}
		if (len == 1 && msgs[i].flags & IIC_M_RD)
			WR4(sc, TWI_CR, TWI_CR_START | TWI_CR_STOP);
		else
			WR4(sc, TWI_CR, TWI_CR_START);
		if (msgs[i].flags & IIC_M_RD) {
			sr = RD4(sc, TWI_SR);
			while (!(sr & TWI_SR_TXCOMP)) {
				if ((sr = RD4(sc, TWI_SR)) & TWI_SR_RXRDY) {
					len--;
					*buf++ = RD4(sc, TWI_RHR) & 0xff;
					if (len == 1)
						WR4(sc, TWI_CR, TWI_CR_STOP);
				}
			}
			if (len > 0 || (sr & TWI_SR_NACK)) {
				err = ENXIO;		// iic nack convention
				goto out;
			}
		} else {
			while (len--) {
				if ((err = at91_twi_wait(sc, TWI_SR_TXRDY)))
					goto out;
				WR4(sc, TWI_THR, *buf++);
			}
			WR4(sc, TWI_CR, TWI_CR_STOP);
		}
		if ((err = at91_twi_wait(sc, TWI_SR_TXCOMP)))
			break;
	}
out:
	if (err) {
		WR4(sc, TWI_CR, TWI_CR_SWRST);
		WR4(sc, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS);
		WR4(sc, TWI_CWGR, sc->cwgr);
	}
	AT91_TWI_UNLOCK(sc);
	return (err);
}
Exemple #30
0
static int
usbphy_utmi_enable(struct usbphy_softc *sc)
{
	int rv;
	uint32_t val;

	/* Reset phy */
	val = RD4(sc, IF_USB_SUSP_CTRL);
	val |= UTMIP_RESET;
	WR4(sc, IF_USB_SUSP_CTRL, val);


	val = RD4(sc, UTMIP_TX_CFG0);
	val |= UTMIP_FS_PREAMBLE_J;
	WR4(sc, UTMIP_TX_CFG0, val);

	val = RD4(sc, UTMIP_HSRX_CFG0);
	val &= ~UTMIP_IDLE_WAIT(~0);
	val &= ~UTMIP_ELASTIC_LIMIT(~0);
	val |= UTMIP_IDLE_WAIT(sc->idle_wait_delay);
	val |= UTMIP_ELASTIC_LIMIT(sc->elastic_limit);
	WR4(sc, UTMIP_HSRX_CFG0, val);

	val = RD4(sc, UTMIP_HSRX_CFG1);
	val &= ~UTMIP_HS_SYNC_START_DLY(~0);
	val |= UTMIP_HS_SYNC_START_DLY(sc->hssync_start_delay);
	WR4(sc, UTMIP_HSRX_CFG1, val);

	val = RD4(sc, UTMIP_DEBOUNCE_CFG0);
	val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
	val |= UTMIP_BIAS_DEBOUNCE_A(0x7530);  /* For 12MHz */
	WR4(sc, UTMIP_DEBOUNCE_CFG0, val);

	val = RD4(sc, UTMIP_MISC_CFG0);
	val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
	WR4(sc, UTMIP_MISC_CFG0, val);

	if (sc->dr_mode == USB_DR_MODE_DEVICE) {
		val = RD4(sc,IF_USB_SUSP_CTRL);
		val &= ~USB_WAKE_ON_CNNT_EN_DEV;
		val &= ~USB_WAKE_ON_DISCON_EN_DEV;
		WR4(sc, IF_USB_SUSP_CTRL, val);

		val = RD4(sc, UTMIP_BAT_CHRG_CFG0);
		val &= ~UTMIP_PD_CHRG;
		WR4(sc, UTMIP_BAT_CHRG_CFG0, val);
	} else {
		val = RD4(sc, UTMIP_BAT_CHRG_CFG0);
		val |= UTMIP_PD_CHRG;
		WR4(sc, UTMIP_BAT_CHRG_CFG0, val);
	}

	usbpby_enable_cnt++;
	if (usbpby_enable_cnt == 1) {
		rv = hwreset_deassert(sc->reset_pads);
		if (rv != 0) {
			device_printf(sc->dev,
			     "Cannot unreset 'utmi-pads' reset\n");
			return (rv);
		}
		rv = clk_enable(sc->clk_pads);
		if (rv != 0) {
			device_printf(sc->dev,
			    "Cannot enable 'utmi-pads' clock\n");
			return (rv);
		}

		val = bus_read_4(sc->pads_res, UTMIP_BIAS_CFG0);
		val &= ~UTMIP_OTGPD;
		val &= ~UTMIP_BIASPD;
		val &= ~UTMIP_HSSQUELCH_LEVEL(~0);
		val &= ~UTMIP_HSDISCON_LEVEL(~0);
		val &= ~UTMIP_HSDISCON_LEVEL_MSB(~0);
		val |= UTMIP_HSSQUELCH_LEVEL(sc->hssquelch_level);
		val |= UTMIP_HSDISCON_LEVEL(sc->hsdiscon_level);
		val |= UTMIP_HSDISCON_LEVEL_MSB(sc->hsdiscon_level);
		bus_write_4(sc->pads_res, UTMIP_BIAS_CFG0, val);

		rv = clk_disable(sc->clk_pads);
		if (rv != 0) {
			device_printf(sc->dev,
			    "Cannot disable 'utmi-pads' clock\n");
			return (rv);
		}
	}

	val = RD4(sc, UTMIP_XCVR_CFG0);
	val &= ~UTMIP_FORCE_PD_POWERDOWN;
	val &= ~UTMIP_FORCE_PD2_POWERDOWN ;
	val &= ~UTMIP_FORCE_PDZI_POWERDOWN;
	val &= ~UTMIP_XCVR_LSBIAS_SEL;
	val &= ~UTMIP_XCVR_LSFSLEW(~0);
	val &= ~UTMIP_XCVR_LSRSLEW(~0);
	val &= ~UTMIP_XCVR_HSSLEW(~0);
	val &= ~UTMIP_XCVR_HSSLEW_MSB(~0);
	val |= UTMIP_XCVR_LSFSLEW(sc->xcvr_lsfslew);
	val |= UTMIP_XCVR_LSRSLEW(sc->xcvr_lsrslew);
	val |= UTMIP_XCVR_HSSLEW(sc->xcvr_hsslew);
	val |= UTMIP_XCVR_HSSLEW_MSB(sc->xcvr_hsslew);
	if (!sc->xcvr_setup_use_fuses) {
		val &= ~UTMIP_XCVR_SETUP(~0);
		val &= ~UTMIP_XCVR_SETUP_MSB(~0);
		val |= UTMIP_XCVR_SETUP(sc->xcvr_setup);
		val |= UTMIP_XCVR_SETUP_MSB(sc->xcvr_setup);
	}
	WR4(sc, UTMIP_XCVR_CFG0, val);

	val = RD4(sc, UTMIP_XCVR_CFG1);
	val &= ~UTMIP_FORCE_PDDISC_POWERDOWN;
	val &= ~UTMIP_FORCE_PDCHRP_POWERDOWN;
	val &= ~UTMIP_FORCE_PDDR_POWERDOWN;
	val &= ~UTMIP_XCVR_TERM_RANGE_ADJ(~0);
	val |= UTMIP_XCVR_TERM_RANGE_ADJ(sc->term_range_adj);
	WR4(sc, UTMIP_XCVR_CFG1, val);


	val = RD4(sc, UTMIP_BIAS_CFG1);
	val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
	val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
	WR4(sc, UTMIP_BIAS_CFG1, val);

	val = RD4(sc, UTMIP_SPARE_CFG0);
	if (sc->xcvr_setup_use_fuses)
		val |= FUSE_SETUP_SEL;
	else
		val &= ~FUSE_SETUP_SEL;
	WR4(sc, UTMIP_SPARE_CFG0, val);

	val = RD4(sc, IF_USB_SUSP_CTRL);
	val |= UTMIP_PHY_ENB;
	WR4(sc, IF_USB_SUSP_CTRL, val);

	val = RD4(sc, IF_USB_SUSP_CTRL);
	val &= ~UTMIP_RESET;
	WR4(sc, IF_USB_SUSP_CTRL, val);

	usbphy_utmi_phy_clk(sc, true);

	val = RD4(sc, CTRL_USB_USBMODE);
	val &= ~USB_USBMODE_MASK;
	if (sc->dr_mode == USB_DR_MODE_HOST)
		val |= USB_USBMODE_HOST;
	else
		val |= USB_USBMODE_DEVICE;
	WR4(sc, CTRL_USB_USBMODE, val);

	val = RD4(sc, CTRL_USB_HOSTPC1_DEVLC);
	val &= ~USB_HOSTPC1_DEVLC_PTS(~0);
	val |= USB_HOSTPC1_DEVLC_PTS(0);
	WR4(sc, CTRL_USB_HOSTPC1_DEVLC, val);

	return (0);
}