This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335X: GPMC, DMA and NAND prefetch

Have you ever tried to do GPMC I/O with the EDMA engine - and failed?

No wonder: there are some common pitfalls.

(Assuming you are using Linux)

1) EDMA event processing

=====================

If you call edma_start(), a list of unused (==free) channels is used to determine if the channel is started per software (for free channels) or per event (for non-free channels).

The GPMC platform data has no DMA channel allocated, so every time you try to start the DMA engine, you will get the software start. This is not what you want!

So, add a DMA channel to the platform data in arch/arm/mach-omap2/omap_hwmod_33xx_data.c

@@ -1335,15 +1335,21 @@ static struct omap_hwmod_ocp_if *am33xx_gpmc_slaves[] = {
 static struct omap_hwmod_irq_info am33xx_gpmc_irqs[] = {
     { .irq = 100 },
     { .irq = -1 }
 };
 
+static struct omap_hwmod_dma_info am33xx_gpmc_edma_reqs[] = {
+        { .name = "dma", .dma_req = AM33XX_DMA_GPM },
+    { .dma_req = -1 },
+};
+
 static struct omap_hwmod am33xx_gpmc_hwmod = {
     .name        = "gpmc",
     .class        = &am33xx_gpmc_hwmod_class,
     .clkdm_name    = "l3s_clkdm",
     .mpu_irqs    = am33xx_gpmc_irqs,
+   .sdma_reqs      = am33xx_gpmc_edma_reqs,
     .main_clk    = "gpmc_fck",
     .prcm        = {
     .omap4    = {
         .clkctrl_offs    = AM33XX_CM_PER_GPMC_CLKCTRL_OFFSET,
         .modulemode    = MODULEMODE_SWCTRL,

2) GPMC FIFO handling

===================

The GPMC has a FIFO for prefetch/post operations. So the first thing you do is to set the DAM or SAM field of the DMA parameters to FIFO mode.

This will not work. For unknown reasons, the DMA transfer is only able to transfer data from/to GPMC if you use the normal address increment mode.


3) Prefetch engine startup

====================

For the prefetch engine, it is documented that the DMA request flag is cleared AT THE START of the engine,

so the requested sequence is to first start the prefetch engine, and then start the DMA engine.

This will not work.

Starting the DMA engine with edma_start() will clear the DMA event register, and it is very likely that at this moment in time, the prefetch engine has transfered the first 32 Bytes and rised the DMA event flag. The DMA event will get lost. That's it.

So what to do?

- start the prefetch engine with a terminal count of 0 bytes.

- stop the pretech engine.

This sequence will erase any spurious DMA flag inside the prefetch engine.

- start the DMA channel.

- start the prefetch engine.

This will give you a working DMA over GPMC + Prefetch engine.

regards

Wolfgang

  • Thank you for sharing with the community, Wolfgang!

    Best regards,
    Miroslav

  • Nice contribution!

    EDMA3 is very powerful, but also a big potential source for confusion.  I'm not familiar with the linux EDMA driver, but have been trying to get a thorough understanding of how EDMA3 works exactly.  I've noticed that:

    • The terminology and register naming is.. not ideal.  While studying EDMA at some point I actually decided to do a big renaming into terms that actually made sense to me.  The result is this heavily annotated header file: 5126.edma3.h (Beware: I'm still just using this as a piece of personal documentation, it may not even compile.)
    • EDMA originated on DSPs using TI's Common Bus Architecture (the VBUSP/VBUSM protocols) and which use events (pulsed / edge-triggered) for interrupts.  Its integration into SoCs involves a switch to level-based interrupts and bridging to other bus protocols.  The impact of this is often not discussed, and much documentation continues to reflect the original environment.

    FIFO mode (aka constant-addressing mode) is a nice example of this.  It is a CBA feature apparently meant to allow efficient bursts of data from/into FIFOs with a narrow memory-mapped window, e.g. a single register, by having the address wrap modulo the size of that window during the burst instead of having to split it into lots of small requests.  For some reason it comes with an annoying 32-byte alignment restriction on the address of the FIFO, which rather limits its usefulness.

    TI's ARM-based SoCs however do not use CBA except locally in some subsystems, the EDMA transfer controller ports get bridged onto the L3 interconnect which is Arteris FlexNOC in current SoCs.  Its native feature set is poorly documented, but apparently it does support a similar wrap mode.  I've tried various types of EDMA transfers to a bogus address and examined the interconnect error logs (the documentation is sufficiently inadequate here that empirical science is the only way to understand what's going on):  FIFO mode sets the "wrap-mode" bit 0 of the cmd and the "wrapsize" field varies with the specified FIFO size.

    On the other hand, most bus interfaces on current SoCs, including that of GPMC, use OCP.  While OCP supports wrap-mode bursts, it supports them for a completely different reason ("critical word first" cache line fills) and has no explicit control over the wrap size: it always equals the total burst size.  For aligned bursts there's therefore no difference with normal (increment) mode.

    This means I have no idea what the relevant target agent would do with such EDMA transfers.  It must turn them into some kind of OCP transaction but apparently, based on your experience, something that the GPMC doesn't understand.

    Wolfgang Muees1 said:
    Starting the DMA engine with edma_start() will clear the DMA event register

    As I said I'm not familiar with the linux EDMA driver, but.... that sounds really broken.

    DMA events are normally tracked meticulously with silent loss being considered completely unacceptable.  The DMA event clear register should only be used as part of cleaning up the mess after a fatal error, or -- if you're very careful -- after stopping a DMA channel, in which case it should accompany a report to the relevant client driver that a DMA event was still pending so it can process it in some other way.  (Normally a DMA channel is of course only stopped after the event source has been disabled and the channel drained, but in obscure cases there might be a reason to stop it while events are still produced to switch to non-DMA-based processing.)

  • Hi, Walfgang:

    I need to access FPGA through GPMC in burst synch mode. My burst is 16words, Can you give some example code how to set up the DMA for the FPGA device driver?

    Thank you very much!

    Jin