Distribution Guide
|
|
STMicroelectronics DMA API
This API is introduced to provide support for DMA functionality on STMicroelectronics' DMA controllers. For STMicroelectronics' devices, DMA is controlled through a number of distinct DMAC blocks; the STm8000 and STi5528 parts include a GPDMA block while the STb7100 contains the more flexible FDMA block. Refer to the relevant SoC users manuals for information about programming unsupported devices.
A Linux-2.6 driver is available which controls the FDMA through the STMicroelectronics DMA API. This supports scatter-gather and paced transfers to and from selected on-chip peripherals over 16 multi-purpose channels, and memory to memory moves. The FDMA allows transfers with 0D, 1D and 2D dimensions for both source and destination locations.
The Linux-2.6 driver for GPDMA supports only free running transfers using the GPDMA's four general purpose channels. The GPDMA driver supports only 0D, 1D and scatter-gather transfers.
Configuration and build with STMicroelectronics DMA API
Full support on the STb7100 is provided for Linux kernels 2.6.11 and later. The STMicroelectronics DMA API driver is enabled by default for the STb7100. To configure the kernel for this driver, bring up the Linux Kernel Configuration screen (as in Kernel configuration) and enter:
-
Device Drivers ---> STM specific devices ---> STMicroelectronics DMA API
Note: Neither DMA driver is available as a separate module in this release; it must be compiled with the option to be built-in to the kernel.
The driver may be required to allocate large physically contiguous regions for use in scatter-gather (sg) and linked transfers. For this, the CONFIG_BIGPHYS_AREA flag must be set in the kernel, using the menus:
-
System type ---> Big Physical Area
It is then necessary to specify the number of pages of memory (4 Kbytes per page) to reserve at boot time by adding the bigphysarea command to your kernel command line; for example:
This reserves 400 Kbytes. The number required for FDMA must be added to any previous value in the command line. As a guide, each individual transfer requires 32, 40 or 84 bytes if running in FREERUNNING/PACED, SPDIF or SCD_PES modes respectively.
Operating FDMA
Of the 16 channels available (numbered 0 to 15), any channel number may be selected for use in any of the operating modes as described below. It is also possible to use all 16 channels simultaneously. One restriction is that if a transfer is currently in progress on a channel, that channel is unavailable for transfer configuration or initiation until the current transfer has completed. It is possible to run in blocking or non-blocking mode when configuring a channel. This is determined by the FDMA_SETUP_NOBLOCK flag. If this is set as a channel configuration option, the channel will run in non-blocking mode.
To access the current status of a transfer, two methods are available: callbacks and the dma_get_residue() API function, which returns the current status of the operation. Three callback scenarios are possible:
- a completion interrupt can be specified, which will be executed when all bytes of the transfer have been written,
- an error callback can be specified, to be called if the transfer fails,
- for linked list or scatter-gather transfers, the FDMA can be directed either to pause after each element in the list has been completed, or to trigger a callback only when all transfers are complete.
By specifying the NODE_PAUSE_ISR flag to dma_configure_channel(), the completion callback is executed for each element. The transfer continues when the callback returns.
The transfer type can be linked list or single shot. In linked mode, which is enabled by the LIST_TYPE_LINKED flag of the dma_channel structure, the FDMA will continue processing until a dma_stop_channel() call is issued. In linked mode, an arbitrary number of nodes may be processed simultaneously by FDMA, which reduces CPU intervention. This is achieved by passing a pointer to the first element of a contiguous list of dma_channel structures which specify each transfer, and by setting list_len to the total length.
Scatter-gather support is provided as a superset of FREERUNNING mode transfers. There are additional members of the dma_channel structure, in which the user must provide the requisite scatterlist data for the transfer to be configured correctly. Two scatter-gather modes are supported: from scatter-gather to memory and from memory to scatter-gather. To configure a scatter-gather transfer, MODE_FREERUNNING must be selected, together with the dimensionality required: DIM_SG_x_0 or DIM_0_x_SG. The source and destination scatterlist structures must point to an array of scatterlists which describe the transfer. In addition, a dma_channel structure must be created to pass the other requisite data and configuration to the FDMA.
An example of a dma_channel structure is:
static void api_SG_x_0(void) { struct dma_channel * dma_chan; int chan_id=0; u32 * buffer =0; int i=0; struct scatterlist sg[15]; chan_id = request_dma(9,"STB7100_DMA_TST"); source_buff = (u32*)bigphysarea_alloc(sizeof(char)*2048); dest_buff = (u32*)bigphysarea_alloc(sizeof(char)*2048); buffer = &source_buff[0]; printk(" chan_id is %d\n",chan_id); for(i;i < 2048; i++){ source_buff[i] = 0xfff0; } dma_cache_wback(&source_buff[0],sizeof(u32)*2048); dma_cache_wback(&dest_buff[0],sizeof(u32)*2048); for(i=0;i < 10;i++){ sg[i].dma_address = virt_to_bus(buffer); sg[i].length = 128; buffer +=sg[i].length; } dma_chan = get_dma_channel(chan_id); dma_chan->list_len = 1; dma_chan->chan = chan_id; dma_chan->mode = MODE_FREERUNNING; dma_chan->dar = virt_to_bus(&dest_buff[0]); dma_chan->count = 128; dma_chan->src_sz = 32* sizeof(char); dma_chan->flags = DIM_SG_x_0 | LIST_TYPE_UNLINKED | NODE_DONE_ISR| NODE_PAUSE_ISR; dma_chan->comp_callback = report_test; dma_chan->src_sg_len = 10; dma_chan->src_sg = &sg[0]; dma_configure_channel(dma_chan); dma_xfer(chan_id); } |
|
|
FDMA modes
There are various modes in which the FDMA can operate. To set the mode, a mode flag must be specified on setup of a transfer in the dma_channel structure. Three modes are supported.
-
MODE_FREERUNNING
-
Simple memory to memory moves are permitted. These can be either single location transfers, of arbitrary size, or multi-dimensional (0D-2D) block moves. Further information can be found in the STb7100 datasheet.
-
MODE_PACED
-
STBus paced transfers to and from on-chip peripheral devices are possible for 31 pre-defined devices. A flag must be passed to dma_configure_channel to specify the correct peripheral. This value also determines whether the transfer is to or from the peripheral. Data concerning the paced channel numbers can be found in the STb7100 datasheet. In this mode, source and destination sizes and move types are specified by the interface to the peripheral in question, but it is possible to configure source and destination addresses to increment between transfers. To do this specify one of: DIM_1_x_0 or DIM_0_x_1, according to the direction of the paced channel. This produces an incrementing source address with a static destination address, or vice versa.
-
The size of the increment is pre-determined by the selected channel. It is not possible to modify the STBus LDST sizes programmatically at present.
-
MODE_SPDIF
-
A paced channel is provided for transfers to the SPDIF (digital audio) player. When utilizing this channel, the FDMA is capable of putting the data in the SPDIF format and writing directly to the FIFO. The state of the SPDIF data on input must be specified by passing additional variables in the spdif member of the dma_channel structure. This mode is paced by the STBus, and the FDMA only writes data to the SPDIF FIFO when DREQ is held high. More specific information can be found in the STb7100 Datasheet.
Another mode that is not currently supported by the STMicroelectronics kernel is MODE_PES. PES (Program Elementary Stream) and SCD (Start Code Detect) parsing would be accomplished in a similar manner to MODE_SPDIF above. This is intended to reduce CPU load during a video decode by parsing and formatting incoming packets form the PTI.
Transfer setup
To set up a channel correctly, the channel configuration must be specified in a dma_channel structure. This holds all the data required for the FDMA to build a node or linked list with the correct format. The comments in the structure definition of dma_channel should provide some pointers on how to do this correctly.
Four steps are required to transfer data using the FDMA driver.
-
Request a channel upon which to transfer the data. This can be done with the request_dma() API function, which can specify either a specific channel or any available channel according to the ANY_CHANNEL flag. A negative return indicates failure.
-
Call get_dma_channel() on the claimed channel. This returns a pointer to the default setup of the channel. This should be modified to set up the transfer, and passed to dma_configure().
-
Set up the dma_channel structure to describe the transfer type, and pass this configuration to dma_configure_channel(). A negative return value indicates a failure. Note that dma_configure_channel() can operate in blocking or non-blocking mode. A call to this function on a channel which currently has a transfer in progress will be blocked by default until the transfer is complete. If non-blocking mode is set with the FDMA_SETUP_NOBLOCK flag, then an -EBUSY signal will be returned if the channel is busy.
-
Call dma_xfer() to start the channel. If the channel has not been configured, a default mode of 1 x 1, or memory to memory, is used.
In this example a 1d x 0d move of 1 Kbyte of data is performed:
#include <asm-sh/dma.h> struct dma_channel * channel; /*get the next available channel*/ int ch_num = request_dma(ANY_CHANNEL,"STB7100_TEST")); /*get some contiguous memory for our buffer. Transfers on non-contiguous memory will require the use of sg or llu functionality*/ u32 source_buff = bigphysarea_alloc(sizeof(u32)*256); u32 dest_buff = bigphysarea_alloc(sizeof(u32)*256); /*put some data in the src buffer here*/ /*align both buffers to 32 byte boundaries*/ ALIGN(*source_buff,32); ALIGN(*dest_buff,32) /*flush and invalidate the buffer data from the cache*/ dma_cache_wback(&source_buff[0],sizeof(u32)*256); dma_cache_wback(&dest_buff[0],sizeof(u32)*256); /*get the default setup of the claimed channel*/ channel = get_dma_channel(ch_num); /*these members point to functions of type void foo(void)*/ channel->err_callback = 0; channel->comp_callback = report_test; /*if using free-running mode a DIM_n_x_n flag must be set if using a paced channel, specify SRC/DST STATIC/INCR flags*/ channel->mode = MODE_FREERUNNING; /*total number of bytes for the transfer*/ channel->count = 256*sizeof(u32); /*buffers must be physically contiguous and given in bus(P3)addr */ channel->sar = virt_to_bus(&source_buff[0]); channel->dar = virt_to_bus(&dest_buff[0]); /*src and dst location sizes in bytes*/ channel->src_sz = 4; channel->dst_sz = 0; /*src and dst line strides in bytes*/ channel->dstride=0; channel->sstride=0; /*num transfers in list*/ channel->list_len=1; channel->flags =NODE_DONE_ISR | DIM_1_x_0 | LIST_TYPE_UNLINKED; /*prepare the dma transfer and lock channel it will be unlocked again on completion of all loaded transfers*/ dma_configure_channel(ch_num,channel->flags); /*push the big red button*/ dma_xfer(ch_num); void report_test(void) { /*free's memory and unlocks for next transfer*/ free_dma(ch_num); } |
|
|
The STMicroelectronics DMA API
The features of the DMAC are accessed through the STMicroelectronics DMA API. This is defined in the file /include/asm-sh/dma.h. Please refer to this file for more function specific information. The following functions are exported by the API:
request_dma()
-
int request_dma(unsigned int chan, const char *dev_id)
Where:
-
chan is a channel number within a valid range (0 to 15 for STb7100). Specifying the ANY_CHANNEL flag in this field, returns the next available free channel.
-
dev_id specifies which device will use the channel, for example STB7100_AUDIO_DMA.
A call to this function locks a specified channel of the FDMA for single or repeated use until an equivalent call to free_dma is made. This function also initializes the helper data in the API layer.
Attempting a transfer on the claimed channel by a device with a different dev_id will fail. This enables a channel to be pre-allocated, if need be, for as long as the driver may require it.
If successful, the channel number claimed is returned, or a negative value is returned if the channel number is out of range or in use.
free_dma()
-
void free_dma(unsigned int chan)
Where:
-
chan is the channel number to be freed.
This function frees the resources associated with the allocated channel and makes it available for use by other devices.
get_dma_info()
-
struct dma_info *get_dma_info(unsigned int chan)
Where:
-
chan is a channel number within a valid range (0 to 15 for STb7100).
This function iterates through the registered DMAC list until the given channel is found; the associated DMAC setup is then returned in the dma_info structure.
The status of the associated DMAC for a given channel number is returned, or an error is returned if out of range.
get_dma_channel()
-
struct dma_channel *get_dma_channel(unsigned int chan)
Where:
-
chan is a channel number within a valid range (0 to 15 for STb7100).
This function iterates through the registered channels and returns the channel setup data associated with the input value.
Either the current setup for a given channel number is returned if a valid identifier is supplied, or a negative value if the identifier is out of range.
get_dma_residue()
-
int get_dma_residue(unsigned int chan)
Where:
-
chan is a channel number within a valid range (0 to 15 for STb7100).
This function queries the current state of the DMA transfer and returns the current number of bytes transmitted. If the channel is configured but not started, the total bytes remaining for the transfer is returned. If the channel is unrequested the return value is undefined.
dma_wait_for_completion()
-
void dma_wait_for_completion(unsigned int chan)
Where:
-
chan is a channel number within a valid range (0 to 15 for STb7100).
This blocking function causes the caller to sleep until the specified channel has received its completion interrupt, signifying that the transfer has completed successfully. It must not be used in the context of an interrupt.
dma_configure_channel()
-
void dma_configure_channel(struct dma_channel * chan, unsigned long flags)
Where:
-
chan is a structure providing the FDMA specific setup data. See /include/asm-sh/dma.h for the structure definition. If linked list mode is enabled this points to the first member of a list of transfers.
-
flags is a flag to identify either blocking or non-blocking mode.
A call with valid configuration flags, configures the selected channel of the FDMA engine for the next transfer. If a transfer is currently in progress the configuration is blocked until the channel becomes available. Note that the function implements the block with the spinlock, so it can be used under interrupt.
dma_xfer()
-
int dma_xfer(unsigned int chan)
Where:
-
chan is the channel to be started.
This function starts the selected channel.
A negative error value is returned if an invalid or unconfigured channel is specified, or if the channel is currently in use.
dma_pause_channel()
-
int dma_pause_channel(int flags, unsigned int chan)
Where:
-
flags specifies whether the channel should be flushed prior to a pause; values are CHANNEL_NOFLUSH or CHANNEL_FLUSH. This determines whether the internal data buffers of the FDMA engine are flushed (if so the current transfer will be aborted).
-
chan is the channel selected to be paused.
This function issues a pause command to the FDMA which stops the channel, flushes the data buffers and generates an interrupt when the DMA has become idle. If a callback has been specified this is executed when service of the interrupt is complete.
1 is returned if the channel has paused correctly, 0 is returned if the channel has failed to pause, or a negative error value is returned if an invalid channel is specified.
dma_unpause_channel()
-
void dma_unpause_channel(unsigned int chan)
Where:
-
chan is the channel to unpause.
If the channel is valid and in a paused state, this function restarts the current node.
dma_stop_channel()
-
int dma_stop_channel(unsigned int chan)
Where:
-
chan is the channel to be stopped.
This function causes an immediate termination of the active channel. It always returns a value of 1 (success).
|