static void zy7_devcfg_intr(void *arg) { struct zy7_devcfg_softc *sc = (struct zy7_devcfg_softc *)arg; uint32_t istatus, imask; DEVCFG_SC_LOCK(sc); istatus = RD4(sc, ZY7_DEVCFG_INT_STATUS); imask = ~RD4(sc, ZY7_DEVCFG_INT_MASK); /* Turn interrupt off. */ WR4(sc, ZY7_DEVCFG_INT_MASK, ~0); if ((istatus & imask) == 0) { DEVCFG_SC_UNLOCK(sc); return; } /* DMA done? */ if ((istatus & ZY7_DEVCFG_INT_DMA_DONE) != 0) wakeup(sc->dma_map); /* INIT_B positive edge? */ if ((istatus & ZY7_DEVCFG_INT_PCFG_INIT_PE) != 0) wakeup(sc); DEVCFG_SC_UNLOCK(sc); }
static int zy7_devcfg_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { struct zy7_devcfg_softc *sc = dev->si_drv1; int err; DEVCFG_SC_LOCK(sc); if (sc->is_open) { DEVCFG_SC_UNLOCK(sc); return (EBUSY); } sc->dma_map = NULL; err = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 4, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, PAGE_SIZE, 1, PAGE_SIZE, 0, busdma_lock_mutex, &sc->sc_mtx, &sc->dma_tag); if (err) { DEVCFG_SC_UNLOCK(sc); return (err); } sc->is_open = 1; DEVCFG_SC_UNLOCK(sc); return (0); }
static int zy7_devcfg_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { struct zy7_devcfg_softc *sc = dev->si_drv1; DEVCFG_SC_LOCK(sc); sc->is_open = 0; bus_dma_tag_destroy(sc->dma_tag); DEVCFG_SC_UNLOCK(sc); return (0); }
/* zy7_devcfg_sysctl_pl_done() returns status of the PL_DONE signal. */ static int zy7_devcfg_sysctl_pl_done(SYSCTL_HANDLER_ARGS) { struct zy7_devcfg_softc *sc = zy7_devcfg_softc_p; int pl_done = 0; if (sc) { DEVCFG_SC_LOCK(sc); /* PCFG_DONE bit is sticky. Clear it before checking it. */ WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_PCFG_DONE); pl_done = ((RD4(sc, ZY7_DEVCFG_INT_STATUS) & ZY7_DEVCFG_INT_PCFG_DONE) != 0); DEVCFG_SC_UNLOCK(sc); } return (sysctl_handle_int(oidp, &pl_done, 0, req)); }
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); }