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); }
/* * 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); }
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); }
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); }
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); }
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); }
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); }
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); }
void arm_mask_irq(uintptr_t nb) { WR4(sc, IC_IDCR, 1 << nb); }
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); }
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); }
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); }
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); }
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); }
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); }
/* 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); }
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); }
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); }
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); } }
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); }
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); }
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); }
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); }
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); }
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); }