1
0
mirror of synced 2026-01-13 15:17:34 +00:00

basic DMA support

This commit is contained in:
Romain Dolbeau 2020-12-18 07:28:30 -05:00
parent 10447bb7ec
commit 92c7751290
2 changed files with 148 additions and 26 deletions

View File

@ -46,6 +46,8 @@ __KERNEL_RCSID(0, "$NetBSD$");
#include <dev/sbus/rdfpga.h>
#include <machine/param.h>
int rdfpga_print(void *, const char *);
int rdfpga_match(device_t, cfdata_t, void *);
void rdfpga_attach(device_t, device_t, void *);
@ -99,19 +101,19 @@ rdfpga_ioctl (dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
switch (cmd) {
case RDFPGA_WC:
for (i = 0 ; i < 2 ; i++)
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_C + (i*8)), bits->x[i] );
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_C + (i*8)), bits->x[i] );
break;
case RDFPGA_WH:
for (i = 0 ; i < 2 ; i++)
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_H + (i*8)), bits->x[i] );
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_H + (i*8)), bits->x[i] );
break;
case RDFPGA_WI:
for (i = 0 ; i < 2 ; i++)
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_I + (i*8)), bits->x[i] );
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_I + (i*8)), bits->x[i] );
break;
case RDFPGA_RC:
for (i = 0 ; i < 2 ; i++)
bits->x[i] = bus_space_read_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_C + (i*8)));
bits->x[i] = bus_space_read_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_C + (i*8)));
break;
case RDFPGA_WL:
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, RDFPGA_REG_LED, *(uint32_t*)data);
@ -131,11 +133,11 @@ rdfpga_open(dev_t dev, int flags, int mode, struct lwp *l)
int i;
for (i = 0 ; i < 4 ; i++)
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_C + (i*4)), 0);
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_C + (i*4)), 0);
for (i = 0 ; i < 4 ; i++)
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_H + (i*4)), 0);
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_H + (i*4)), 0);
for (i = 0 ; i < 4 ; i++)
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_I + (i*4)), 0);
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_I + (i*4)), 0);
return (0);
}
@ -147,11 +149,11 @@ rdfpga_close(dev_t dev, int flags, int mode, struct lwp *l)
int i;
for (i = 0 ; i < 4 ; i++)
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_C + (i*4)), 0);
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_C + (i*4)), 0);
for (i = 0 ; i < 4 ; i++)
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_H + (i*4)), 0);
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_H + (i*4)), 0);
for (i = 0 ; i < 4 ; i++)
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_I + (i*4)), 0);
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_I + (i*4)), 0);
return (0);
}
@ -160,17 +162,115 @@ int
rdfpga_write(dev_t dev, struct uio *uio, int flags)
{
struct rdfpga_softc *sc = device_lookup_private(&rdfpga_cd, minor(dev));
int error = 0;
int error = 0, ctr = 0, res;
while (uio->uio_resid > 0) {
aprint_normal_dev(sc->sc_dev, "dma uio: %zu in %d\n", uio->uio_resid, uio->uio_iovcnt);
delay(100);
while (!error && uio->uio_resid >= 16 && uio->uio_iovcnt == 1) {
uint64_t ctrl;
uint32_t nblock = uio->uio_resid/16;
if (nblock > 256)
nblock = 256;
/* no implemented on sparc ? */
/* if (bus_dmamap_load_uio(sc->sc_dmatag, sc->sc_dmamap, uio, BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE)) { */
/* aprint_error_dev(sc->sc_dev, "cannot allocate DVMA address"); */
/* return ENXIO; */
/* } else { */
/* aprint_normal_dev(sc->sc_dev, "dma: %lu %lu %d\n", sc->sc_dmamap->dm_maxsegsz, sc->sc_dmamap->dm_mapsize, sc->sc_dmamap->dm_nsegs); */
/* } */
/* uint64_t buf[4]; */
/* if ((error = uiomove(buf, 32, uio)) != 0) */
/* break; */
/* if (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, buf, 32, /\* kernel space *\/ NULL, */
/* BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE)) { */
/* aprint_error_dev(sc->sc_dev, "cannot allocate DVMA address"); */
/* return ENXIO; */
/* } else { */
/* aprint_normal_dev(sc->sc_dev, "dma: %lu %lu %d\n", sc->sc_dmamap->dm_maxsegsz, sc->sc_dmamap->dm_mapsize, sc->sc_dmamap->dm_nsegs); */
/* } */
aprint_normal_dev(sc->sc_dev, "dmamem about to alloc for %d blocks...\n", nblock);
bus_dma_segment_t segs;
int rsegs;
if (bus_dmamem_alloc(sc->sc_dmatag, nblock*16, 64, 64, &segs, 1, &rsegs, BUS_DMA_NOWAIT | BUS_DMA_STREAMING)) {
aprint_error_dev(sc->sc_dev, "cannot allocate DVMA memory");
return ENXIO;
} else {
aprint_normal_dev(sc->sc_dev, "dmamem alloc: %d\n", rsegs);
}
void* kvap;
if (bus_dmamem_map(sc->sc_dmatag, &segs, 1, nblock*16, &kvap, BUS_DMA_NOWAIT)) {
aprint_error_dev(sc->sc_dev, "cannot allocate DVMA address");
return ENXIO;
} else {
aprint_normal_dev(sc->sc_dev, "dmamem map: %p\n", kvap);
}
if ((error = uiomove(kvap, nblock*16, uio)) != 0)
break;
aprint_normal_dev(sc->sc_dev, "uimove: left %zu in %d\n", uio->uio_resid, uio->uio_iovcnt);
if (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, kvap, nblock*16, /* kernel space */ NULL,
BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE)) {
aprint_error_dev(sc->sc_dev, "cannot load dma map");
return ENXIO;
} else {
aprint_normal_dev(sc->sc_dev, "dmamap: %lu %lu %d\n", sc->sc_dmamap->dm_maxsegsz, sc->sc_dmamap->dm_mapsize, sc->sc_dmamap->dm_nsegs);
}
bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, 0, nblock*16, BUS_DMASYNC_PREWRITE);
aprint_normal_dev(sc->sc_dev, "dma: synced\n");
ctrl = ((uint64_t)(0x80000000 | ((nblock-1) & 0x0FF))) | ((uint64_t)(uint32_t)(sc->sc_dmamap->dm_segs[0].ds_addr)) << 32;
aprint_normal_dev(sc->sc_dev, "trying 0x%016llx\n", ctrl);
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_DMA_ADDR), ctrl);
aprint_normal_dev(sc->sc_dev, "dma: cmd sent\n");
do {
ctr ++;
delay(1);
} while (((res = bus_space_read_4(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_DMA_CTRL))) & 0x80000000) && (ctr < 10));
if ((res & 0x80000000) || (res & 0x20000000)) {
aprint_error_dev(sc->sc_dev, "read 0x%08x (%d try)\n", res, ctr);
error = ENXIO;
}
/* if (sc->sc_dmamap->dm_nsegs > 0) { */
bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, 0, nblock*16, BUS_DMASYNC_POSTWRITE);
aprint_normal_dev(sc->sc_dev, "dma: synced (2)\n");
bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
aprint_normal_dev(sc->sc_dev, "dma: unloaded\n");
bus_dmamem_unmap(sc->sc_dmatag, kvap, nblock*16);
aprint_normal_dev(sc->sc_dev, "dma: unmapped\n");
bus_dmamem_free(sc->sc_dmatag, &segs, 1);
aprint_normal_dev(sc->sc_dev, "dma: freed\n");
/* } */
}
if (uio->uio_resid > 0)
aprint_normal_dev(sc->sc_dev, "%zd bytes left after DMA\n", uio->uio_resid);
while (!error && uio->uio_resid > 0) {
uint64_t bp[2] = {0, 0};
size_t len = uimin(16, uio->uio_resid);
if ((error = uiomove(bp, len, uio)) != 0)
break;
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_I + 0), bp[0]);
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_I + 8), bp[1]);
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_I + 0), bp[0]);
bus_space_write_8(sc->sc_bustag, sc->sc_bhregs, (RDFPGA_REG_GCM_I + 8), bp[1]);
}
return (error);
@ -204,19 +304,17 @@ rdfpga_attach(device_t parent, device_t self, void *aux)
int node;
int sbusburst;
/* bus_dma_tag_t dt = sa->sa_dmatag; */
bus_space_handle_t bh;
sc->sc_bustag = sa->sa_bustag;
sc->sc_dmatag = sa->sa_dmatag;
sc->sc_dev = self;
if (sbus_bus_map(sc->sc_bustag, sa->sa_slot, sa->sa_offset, sa->sa_size,
BUS_SPACE_MAP_LINEAR, &bh) != 0) {
BUS_SPACE_MAP_LINEAR, &sc->sc_bhregs) != 0) {
aprint_error(": cannot map registers\n");
return;
}
sc->sc_bhregs = bh;
//sc->sc_buffer = bus_space_vaddr(sc->sc_bustag, sc->sc_bhregs);
sc->sc_bufsiz = sa->sa_size;
@ -239,12 +337,22 @@ rdfpga_attach(device_t parent, device_t self, void *aux)
sc->sc_burst &= sbusburst;
aprint_normal("\n");
aprint_normal_dev(self, " nid 0x%x, bustag %p, slave-burst 0x%x\n",
aprint_normal_dev(self, "nid 0x%x, bustag %p, slave-burst 0x%x\n",
sc->sc_node,
sc->sc_bustag,
sc->sc_burst);
/* change blink pattern */
/* change blink pattern to marching 2 */
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, RDFPGA_REG_LED , 0x81422418);
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, RDFPGA_REG_LED , 0xc0300c03);
/* DMA */
/* Allocate a dmamap */
#define MAX_DMA_SZ 4096
if (bus_dmamap_create(sc->sc_dmatag, MAX_DMA_SZ, 1, MAX_DMA_SZ, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_dmamap) != 0) {
aprint_error_dev(self, ": DMA map create failed\n");
} else {
aprint_normal_dev(self, "dmamap: %lu %lu %d (%p)\n", sc->sc_dmamap->dm_maxsegsz, sc->sc_dmamap->dm_mapsize, sc->sc_dmamap->dm_nsegs, sc->sc_dmatag->_dmamap_load);
}
}

View File

@ -41,12 +41,26 @@ struct rdfpga_softc {
bus_space_handle_t sc_bhregs; /* bus handle */
//void * sc_buffer; /* VA of the registers */
int sc_bufsiz; /* Size of buffer */
bus_dma_tag_t sc_dmatag;
bus_dmamap_t sc_dmamap; /* DMA map for bus_dma_* */
};
#define RDFPGA_REG_LED 0x0
#define RDFPGA_REG_LED 0x0 /* 1 reg */
#define RDFPGA_REG_H 0x40
#define RDFPGA_REG_C 0x50
#define RDFPGA_REG_I 0x60
#define RDFGPA_REG_GCM_BASE 0x40
#define RDFPGA_REG_GCM_H (RDFGPA_REG_GCM_BASE + 0x00) /* 4 regs */
#define RDFPGA_REG_GCM_C (RDFGPA_REG_GCM_BASE + 0x10) /* 4 regs */
#define RDFPGA_REG_GCM_I (RDFGPA_REG_GCM_BASE + 0x20) /* 4 regs */
#define RDFPGA_REG_DMA_BASE 0x80
#define RDFPGA_REG_DMA_ADDR (RDFPGA_REG_DMA_BASE + 0x00)
#define RDFPGA_REG_DMA_CTRL (RDFPGA_REG_DMA_BASE + 0x04)
#define RDFPGA_MASK_DMA_CTRL_START 0x80000000
#define RDFPGA_MASK_DMA_CTRL_BUSY 0x40000000
#define RDFPGA_MASK_DMA_CTRL_ERR 0x20000000
/* #define RDFPGA_MASK_DMA_CTRL_RW 0x10000000 */
#define RDFPGA_MASK_DMA_CTRL_BLKCNT 0x000000FF
/* #define RDFPGA_MASK_DMA_CTRL_SIZ 0x00000F00 */
#endif /* _RDFPGA_H_ */