DMA Drivers

For documentation of support devices, refer to Supported Devices.

Intro

Access to the DMA Controllers (DMAC) available on the platform is provided by the dma_get() function implemented by the library code. Reference to a DMAC instance obtained from dma_get() is represented by a pointer to struct dma. Each struct dma instance provides the dma_ops API used by the DMA clients to set up and run the DMA transmission.

class lib {
   dma_get(dmac_id) : struct dma*
   dma_put(struct dma*)
}
hide lib attributes

class dma_ops {
   channel_get()
   channel_put()
   start()
   stop()
   pause()
   release()
   status()
   set_config()
   set_cb()
   pm_context_restore()
   probe()
   remove()
}
hide dma_ops attributes

class dma_plat_data {
   id : uint32_t
   base : uint32_t
   channels : uint32_t
   irq : uint32_t
   drv_plat_data : void *
}
hide dma_plat_data methods

class "struct dma" as s_dma {
   plat_data : dma_plat_data
   lock : spinlock_t
   ops : const dma_ops *
   private : void *
}
hide s_dma methods

dma_ops - s_dma
s_dma -- dma_plat_data
s_dma <- lib : provides

Figure 36 DMA Driver API

Programming Flows

DMAC Initialization

In a one-time initialization phase, the ADSP goes to the D0 device power state. In this fully functional state, the platform registers its DMA drivers in the list maintained by the lib at startup.

Note

A static array of dma instances declared in the platform’s code may be replaced with a dynamic discovery of the DMA resources available on the platform, using capability registers if provided by the HW.

Any component from the audio package may use a DMA engine by obtaining a reference to the dma_ops interface from the lib’s list. This flow may happen an unlimited number of times during ADSP D0.

Channel Initialization & Data Transfer

participant client
participant lib
participant dma

== Obtaining Reference to DMAC ==
client -> lib : dma_get(capabilities)
client <-- lib : dma

== Start ==
client -> dma : dma_channel_get( stream tag )
client <-- dma : ch#

client -> dma : dma_set_cb( ch#, client.cb() )
client -> dma : dma_set_config( ch#, config )
client -> dma : dma_start( ch# )

== Transmission ==
...

== Stop ==
client -> dma : dma_stop( ch# )
client -> dma : dma_channel_put( ch# )

Figure 37 Channel Initialization & Data Transfer

In case the host co-manages the DMA HW and the channel is “allocated” by the host side, the FW component must wait until its params() API is called in order to learn the channel ID and pass it to the channel_get() request.

Using DMA Driver API

See DMA Drivers API

Note

The API is accessed through a common structure; however, an implementation may keep some specific private data, attached to the dma.private pointer.