Warning: this is dirty working draft version and is subject to change in future.
The DMA engine device driver should include “gpdma_if.h”, <sys/dev/gpdma/gpdma.h> header files and support following kobject methods:
int setup_channel(device_t dev, int channel, struct dmae_transfer *xfer)
Sets up provided transfer on selected channel number, but doesn't start transfer. Transfer can be started by calling apporiated method or by external (hardware) trigger. Returns 0 on success, nonzero on error.
int clear_channel(device_t dev, int channel)
Clears previously set transfer on channel and effectively disables any kind of operation on that channel. Returns 0 on success, nonzero on error.
int start_channel(device_t dev, int channel)
Starts DMA transfer on channel or enables starting transfer from external triggers (if DMAE_TRANSFER_EXTTRIG is set in xfer→dt_flags). Returns 0 on success, nonzero on error.
int stop_channel(device_t dev, int channel)
Stops previously started (but not completed) transfer. Returns 0 on success, nonzero on error. This method is optional - default implementation returns ENOTSUP.
int poll_channel(device_t dev, int channel, int *status)
Returns channel status. Returns 0 if obtained correct status or nonzero if any error occured or channel status is unavailable. *status is filled with one of enum gpdma_transfer_status
int validate_transfer(device_t dev, int channel, struct gpdma_transfer *xfer)
Returns 0 if supplied transfer can be done using channel on engine dev, or nonzero if cannot. This method is optional - default implementation returns 0.
DMA engines registers themselves using gpdma_register_driver function in their attach method. gpdma_register_driver is defined as follows:
int gpdma_register_driver(device_t dev, struct dmae_capabilities *caps, bus_dma_tag_t tag);
- dev - DMA engine device
- caps - DMA capabilities structure defined as follows:
struct gpdma_capabilities { uint32_t dc_ops; /* one or more from 'enum dmae_op' */ uint32_t dc_buffers; /* one or more from 'enum dmae_buffer_type' */ uint32_t dc_flags; #define DMAECAP_REPEAT 0x1 #define DMAECAP_LINK 0x2 int dc_nchannels; };
- tag - engine root DMA tag
and can be unregistered (at device detach) using:
int gpdma_unregister_driver(device_t dev);
Required data structures:
typedef struct gpdma_engine *gpdma_engine_t; typedef int (*gpdma_callback_t)(int status, void *arg); enum gpdma_op { DMAE_FILL = 0x1, DMAE_COPY = 0x2, DMAE_XOR = 0x4, }; enum gpdma_transfer_status { DMAE_TRANSFER_COMPLETED, DMAE_TRANSFER_COMPLETED_STRIDE, DMAE_TRANSFER_COMPLETED_LINK, DMAE_TRANSFER_CANCELLED, DMAE_TRANSFER_IN_PROGRESS, DMAE_TRANSFER_ERROR, }; enum gpdma_buffer_type { DMAEBUF_BLOCK = 0x1, DMAEBUF_FRAME = 0x2, DMAEBUF_FIFO = 0x4, }; struct gpdma_buffer { struct gpdma_transfer * db_transfer; int db_type; int db_flags; bus_addr_t db_addr; bus_size_t db_length; bus_size_t db_stride_width; bus_size_t db_stride_spacing; bus_size_t db_fifo_width; void * db_immediate; /* Private fields: */ bus_dma_tag_t db_dmatag; bus_dmamap_t db_dmamap; }; struct gpdma_transfer { int dt_type; int dt_op; int dt_flags; #define GPDMA_TRANSFER_EXTTRIG 0x1 /* transfer is triggered by external source */ #define GPDMA_TRANSFER_REPEAT 0x2 /* repeat transfer until cancel */ #define GPDMA_TRANSFER_NOINTR 0x4 /* don't generate callbacks */ #define GPDMA_TRANSFER_STRIDE_CALLBACK 0x8 /* callback on every stride */ #define GPDMA_TRANSFER_LINK_CALLBACK 0x10 /* callback on every linked transfer */ gpdma_callback_t dt_callback; void * dt_callback_arg; struct gpdma_buffer dt_buffers[8]; #define GPDMA_BUF_DST 0 #define GPDMA_BUF_SRC 1 struct gpdma_transfer * dt_next; /* Private fields: */ struct gpdma_engine * dt_engine; struct resource * dt_res; };