h6. [[Hardware Abstraction Layer]] h6(. » [[HAL Device API]] h6((. » [[List of HAL devices]] h6(((. » DMA controller h5. (HALDeviceSysPeri_DMAC) h4. Device API Currently, only API versions 0, 0.1 and 1 are defined. h5. API version 0 <pre> struct dmacontroller { /* Public interface */ struct device dev; uint32_t (*Features)(struct dmacontroller *); __value_in_regs struct { struct dmachannel **channel; uint32_t count; } (*Enumerate)(struct dmacontroller *); struct dmachannel *(*Allocate)(struct dmacontroller *, uint32_t channel); void (*Deallocate)(struct dmacontroller *, uint32_t channel); }; </pre> _dev_ is the standard [[HAL Device descriptor]]. The _address_ field is not used. Controllers are activated/deactivated on module initialisation/finalisation. _dev.Reset_ is called on software-initiated OS resets. Interrupts are ignored - provide them using the DMA channel device instead. _Features_ returns a flag word indicating the capabilities of the controller. Currently no bits are defined; all bits should be zero. _Enumerate_ returns a static list of available physical DMA channel devices (Pointers to [[HALDeviceSysPeri_DMAB|DMA buffer]] or [[HALDeviceSysPeri_DMAL|DMA list]] devices) _Allocate_ returns a pointer to the physical DMA channel struct to associate with the given logical DMA channel. If the hardware requires a particular logical-physical mapping, this will be obeyed; otherwise one will be allocated at the whim of the software (typically: physical channels grouped according to priority of logical channel, then within each group logical channels are allocated on a one-to-one mapping until no physical channels remain, after which logical channels are arbitrarily doubled up). Return value NULL => this logical channel not supported on this controller Recommended DMA priorities: * High: sound DMA * Medium: other device DMA * Low: memory-to-memory DMA _Deallocate_ is the partner of Allocate, this lets the device know that a particular logical channel is no longer being used. h5. API version 0.1 API version 0.1 extends the _dmacontroller_ struct: <pre> struct dmacontroller_0_1 { /* Version 0 interface */ struct dmacontroller dev; /* 0.1 extension */ int32_t TestIRQ2(struct device *); } </pre> The _TestIRQ2_ function allows the controller to take on the role of identifying which physical DMA channel is the cause of the current interrupt. This is useful in situations where all the physical DMA channels share the same IRQ number, and the DMA controller contains a flag word indicating which channel(s) are currently interrupting. If _TestIRQ2_ is provided, then the following rules must be followed: * The _dev.dev.devicenumber_ field must specify the device (IRQ) number of the controller. * All channels returned by _Enumerate_ must be of the same type (e.g. all buffer-type or all list-type) * All channels returned by _Enumerate_ must still provide their _dev.devicenumber_ and _dev.TestIRQ_ entries. * All channels must share the same device number (the same as the controller) ** Note that in the channel devices, bit 31 of _devicenumber_ would typically be set in order to indicate a shared IRQ line. However for the controller bit 31 does not need to be set if the only other devices sharing the same IRQ are the channels belonging to the controller instance. _TestIRQ_ should return the index of the channel that is interrupting (relative to the list returned by _Enumerate_), or -1 if no channel is interrupting. If _TestIRQ_ is not provided, behaviour is as per API version 0. h5. API version 1 API version 1 refines the specification of _Deallocate_: <pre> void (*Deallocate)(struct dmacontroller *, uint32_t channel, struct device *dev); </pre> The _dev_ parameter is a pointer to the channel device that is being deallocated. h4. Memory barriers For both [[HALDeviceSysPeri_DMAL|list-based]] and [[HALDeviceSysPeri_DMAB|buffer-based]] DMA channels, it is the responsibility of the HAL device to ensure that the correct data read/write barriers are used where appropriate. Typically this means that: * Whenever a memory -> device transfer is about to be started, a write barrier should be used to ensure that any buffered writes have reached RAM (pages involved in a DMA transfer will never be cacheable, but they will typically be bufferable). * Whenever the progress of a device -> memory transfer is being reported (e.g. TransferState and Status calls), a read barrier should be used to ensure the CPU hasn't prefetched any stale data from the destination buffer. * For list-based controllers, the transfer descriptor list will typically be located in bufferable memory, and so barriers will be needed whenever it is being accessed. E.g. a write barrier is needed after the list has been fully populated by the CPU, and if the DMA controller updates the descriptors with progress information then a read barrier should be used before the CPU reads from the descriptors. The above covers situations where the HAL device should use barriers. The following covers situations where the client (e.g. a [[DMAManager]] client) should use barriers: * If DMA is being used to transfer code, an instruction synchronisation barrier (e.g. ARMv7 ISB instruction) may be required to ensure any stale prefetched instructions are flushed before the new code is executed. Calling [[OS_SynchroniseCodeAreas]] for the affected range is a safe and valid method of doing this. Other methods may fail on future systems (e.g. consider a DMA controller which is able to perform cache-coherent DMA to/from the CPU data cache, but not to the instruction cache). * If the contents of a circular buffer are being updated on-the-fly by the CPU (e.g. audio playback as used by [[SoundDMA]]) then it is the responsibility of the client to ensure any freshly written data is flushed to RAM. However, in this case barriers are only likely to be needed in exceptional circumstances - e.g. if the CPU is repeatedly writing to the same location, and the hardware keeps merging the data into the write buffer but never flushing it to RAM. h4. Support in RISC OS HALDeviceSysPeri_DMAC is supported by the trunk version of the [[DMAManager]] module. h4. Known implementations |_<. Device ID |_<. Description |_<. Implemented in | |HALDeviceID_DMAC_M1535 |Acer M1535+ legacy DMA controller |HAL.Tungsten.s.M1535DMA | |HALDeviceID_DMAC_M5229 |Acer M5229 ATA controller bus master |HAL.Tungsten.s.ATA | |HALDeviceID_DMAC_OMAP3 |OMAP3 system DMA controller |HAL.OMAP3.s.SDMA | h6. Information sources: Kernel.Hdr.HALDevice, HWSupport.DMA.HAL_DMAAPI, HWSupport.DMA.hdr.DMADevice in CVS