DMA Support — Description


#include <cyg/hal/bcm283x_dma.h>

ok = hal_dma_channel_init(hal_dma_channel *chan, cyg_uint8 permap, cyg_bool fast, hal_dma_callback *callback, CYG_ADDRWORD data);

hal_dma_channel_delete(hal_dma_channel *chan);

hal_dma_channel_set_polled(hal_dma_channel *chan, cyg_bool polled);


hal_dma_cb_init(hal_dma_cb *cb, cyg_uint32 ti, void *source, void *dest, cyg_uint32 size);

hal_dma_add_cb(hal_dma_channel *chan, hal_dma_cb *cb);

hal_dma_channel_start(hal_dma_channel *chan);

hal_dma_channel_stop(hal_dma_channel *chan);


The HAL provides support for access to the DMA channels. This support is not intended to expose the full functionality of these devices and is mainly limited to supporting peripheral DMA. The API is therefore mainly oriented for use by device drivers rather than applications. The user is referred to the BCM2835 documentation for full details of the DMA channels, and to the SDHOST driver for an example of this API in use.

The DMA hardware consist of sixteen independent channels. DMA is initiated by attaching a chain of control blocks to a channel and starting it running. Each control block contains source and destination addresses, size, transfer direction and a number of other parameters. Of the sixteen channels available, some are reserved for use by the GPU. Also, the channels are divided into full function channels and lite channels that lack some functionality and have lower bandwidth. Full details are available in the BCM2835 documentation.

A DMA channel is represented by a hal_dma_channel object that the client must allocate. Control blocks are similarly represented by a hal_dma_cb object, which again must be allocated by the client. DMA control blocks must be aligned on a 32 byte boundary. The type definition in bcm283x_dma.h has an alignment attribute so that static allocations should be correctly aligned by default; however care should be taken to align dynamic allocations.

A DMA channel is initialized by calling hal_dma_channel_init, the parameters are as follows:

A pointer to the channel object to be initialized.
Peripheral map value. This is one of the CYGHWR_HAL_BCM283X_DMA_DREQ_XXXX values defined in bcm238x.h. It specifies the peripheral to or from which the transfer will be made.
This specifies whether the DMA channel should be a full featured fast channel or a reduced bandwidth lite channel. If a lite channel is specified and none are available a fast channel will be allocated. However, if a fast channel is specified and none are available then this routine will return 0 to indicate an error.
A pointer to a function that will be called when the DMA transfer has been completed. This will be called with a pointer to the channel, an event code, nd a copy of the data parameter. The event code will be either CYGHWR_REG_BCM283X_DMA_CS_END to indicate a successful completion of the transfer or CYGHWR_REG_BCM283X_DMA_CS_ERROR to indicate an error.
An uninterpreted data value that will be passed to the callback. This would typically be a pointer to a client data structure.

If the initialization is successful the routine will return 1. The current implementation of the DMA API permanently allocates a physical channel when this routine is called. In the future the allocation of physical channels may be more dynamic, so the client should not assume that the channel in use is constant.

The hal_dma_channel_delete function deletes the given channel, releasing any resources and making them available for reuse.

The hal_dma_channel_set_polled function marks a channel for polled operation only. Otherwise the channel will enable interrupts and wait for an interrupt to complete. If a channel is marked polled then it will only be completed and its callback called during calls to hal_dma_poll. Note that channels not marked polled may also be completed during this call if their interrupt has not yet fired.

A transfer control block is initialized by calling hal_dma_cb_init. The parameters are as follows:

A pointer to the control block to be initialized.
This is an initial value for the TI register field of the control block. This may contain any of the bits and fields specified for this register except the PERMAP field, which will be set from the value set in the channel. For simplicity the standard settings for common operations are defined by the DMA API; HAL_DMA_INFO_DEV2MEM initializes the control block for a single buffer transfer from a device to memory, and HAL_DMA_INFO_MEM2DEV for a transfer in the reverse direction. If a client needs to perform scatter/gather transfers, then it needs to set this argument more explicitly. In particular, the INTEN bit should normally only be set on the last control block of a chain.
The source address for the transfer, either the start of a memory buffer or the data register of the appropriate device.
The destination address for the transfer, either the start of a memory buffer or the data register of the appropriate device.
Transfer size in bytes.

Once initialized a control block may be added to a channel by calling hal_dma_cb_add. Control blocks will be chained together on the channel in the order in which they are added. The DMA engines operate on addresses in the GPU address space, not the physical address space visible the the ARM CPUs or the virtual address space set up by the MMU. During initialization the source and destination addresses will be translated into GPU addresses, and after it is added, the dma_next field of the control block will be translated to a GPU address. So, care should be taken when inspecting an active control block and it should not be changed.

Once a channel had been initialized and any control blocks have been added the transfers may be started by calling hal_dma_channel_start. For channels not marked polled, interrupts will fire and the callback will be called from a DSR when the control block chain has been completed. For polled channel, it will be necessary to call hal_dma_poll until all channels have completed.

An ongoing transfer may be halted by calling hal_dma_channel_stop. This function should also be called as a matter of course when a transfer has completed normally.