changeset 3241:834344bb1faa

Fix: Disable DMA requests for transfers that don't use DMA. [ Bugzilla 1001815 ]
author vae
date Sun, 02 Jun 2013 16:22:36 +0000
parents c98d5e2bd690
children 1b3a6c3f449e
files packages/devs/spi/freescale/dspi/current/ChangeLog packages/devs/spi/freescale/dspi/current/cdl/spi_freescale_dspi.cdl packages/devs/spi/freescale/dspi/current/src/spi_freescale_dspi.c
diffstat 3 files changed, 93 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/packages/devs/spi/freescale/dspi/current/ChangeLog
+++ b/packages/devs/spi/freescale/dspi/current/ChangeLog
@@ -1,3 +1,9 @@
+2013-05-08  Ilija Kocho <ilijak@siva.com.mk>
+
+	* src/spi_freescale_dspi.cdl: Add CYGINT_DEVS_SPI_DMA_USE
+	* src/spi_freescale_dspi.c: Fix: Disable DMA requests for transfers
+	that don't use DMA. [ Bugzilla 1001815 ]
+
 2013-04-01  Ilija Kocho <ilijak@siva.com.mk>
 
 	* include/spi_freescale_dspi.h, include/spi_freescale_busses.inl
--- a/packages/devs/spi/freescale/dspi/current/cdl/spi_freescale_dspi.cdl
+++ b/packages/devs/spi/freescale/dspi/current/cdl/spi_freescale_dspi.cdl
@@ -114,6 +114,11 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
         }
     }
 
+    cdl_interface CYGINT_DEVS_SPI_DSPI_DMA_USE {
+        display  "DSPI DMA use"
+        flavor   data
+        description "Number of DMA channels used by DSPI buses."
+    }
 
     for { set ::spibus 0 } { $::spibus < 8 } { incr ::spibus } {
 
@@ -207,6 +212,7 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
             cdl_component CYGHWR_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_TX_DMA_CHAN {
                 display "TX DMA channel"
                 flavor data
+                implements CYGINT_DEVS_SPI_DSPI_DMA_USE
                 implements CYGINT_DEVS_SPI_DSPI[set ::spibus]_USES_DMA
 
                 active_if CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_PUSHQUE_SIZE > \
@@ -256,6 +262,7 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
             cdl_component CYGHWR_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_RX_DMA_CHAN {
                 display "RX DMA channel"
                 flavor data
+                implements CYGINT_DEVS_SPI_DSPI_DMA_USE
                 implements CYGINT_DEVS_SPI_DSPI[set ::spibus]_USES_DMA
 
                 active_if CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_PUSHQUE_SIZE > \
--- a/packages/devs/spi/freescale/dspi/current/src/spi_freescale_dspi.c
+++ b/packages/devs/spi/freescale/dspi/current/src/spi_freescale_dspi.c
@@ -8,7 +8,7 @@
 // ####ECOSGPLCOPYRIGHTBEGIN####                                            
 // -------------------------------------------                              
 // This file is part of eCos, the Embedded Configurable Operating System.   
-// Copyright (C) 2011 Free Software Foundation, Inc.
+// Copyright (C) 2011, 2013 Free Software Foundation, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under    
 // the terms of the GNU General Public License as published by the Free     
@@ -155,14 +155,12 @@ dspi_status_clear(cyghwr_devs_freescale_
 static inline void
 dspi_fifo_clear(cyghwr_devs_freescale_dspi_t* dspi_p)
 {
-    DEBUG2_PRINTF("  Fifo Clear\n");
     dspi_p->mcr |= FREESCALE_DSPI_MCR_CLR_RXF_M | FREESCALE_DSPI_MCR_CLR_TXF_M;
 }
 
 static inline void
 dspi_fifo_drain(cyghwr_devs_freescale_dspi_t* dspi_p)
 {
-    DEBUG2_PRINTF("  Fifo Drain\n");
     dspi_p->sr |= FREESCALE_DSPI_SR_RFDF_M;
 }
 
@@ -209,7 +207,7 @@ static cyg_uint32 dspi_dma_ISR(cyg_vecto
     edma_p = dma_set_p->edma_p;
 
     cyg_drv_isr_lock();
-    
+
     // Disable the Tx DMA channel and DSPI IRQ.
     hal_freescale_edma_erq_disable(edma_p, SPI_DMA_CHAN_I(dma_set_p, TX));
     DSPI_IRQ_DISABLE(dspi_p);
@@ -415,7 +413,7 @@ static void dspi_bus_setup(cyg_spi_frees
     cyg_uint32 dma_chan_i;
 
     // Set up the clocking.
-    CYGHWR_IO_CLOCK_ENABLE(spi_bus_p->setup_p->clk_gate);    
+    CYGHWR_IO_CLOCK_ENABLE(spi_bus_p->setup_p->clk_gate);
     spi_bus_p->clock_freq = CYGHWR_IO_SPI_FREESCALE_DSPI_CLOCK;
     DEBUG1_PRINTF("DSPI BUS %p: SysClk=%d\n", spi_bus_p, spi_bus_p->clock_freq);
 
@@ -453,11 +451,6 @@ static void dspi_bus_setup(cyg_spi_frees
 #if DEBUG_SPI >= 1
         hal_freescale_edma_transfer_diag(edma_p, dma_chan_i, true);
 #endif
-        // Enable SPI DMA requests
-        dspi_p->rser = FREESCALE_DSPI_RSER_TFFF_DIRS_M |
-                       FREESCALE_DSPI_RSER_RFDF_DIRS_M |
-                       FREESCALE_DSPI_RSER_TFFF_RE_M |
-                       FREESCALE_DSPI_RSER_RFDF_RE_M;
     }
 #if DEBUG_SPI >= 1
     cyghwr_devs_freescale_dspi_diag(spi_bus_p);
@@ -524,6 +517,7 @@ rx_dma_channel_setup(cyghwr_hal_freescal
 
 #if DEBUG_SPI >= 2
 static const char debug_format[] = "BUFF %dbit %s: %p 0x%08x remain %d:\n";
+static const char debug_format1[] = "PUSHR 0x%08x %s: %p 0x%08x remain %d:\n";
 #endif
 
 static inline volatile cyg_uint32
@@ -540,13 +534,13 @@ fifo_pushque_fill(cyg_spi_freescale_dspi
                 if(!(--txfifo_n)) {
                     dspi_p->pushr = pushr |= *data_p | FREESCALE_DSPI_PUSHR_EOQ_M;
                     count--;
-                    DEBUG2_PRINTF(debug_format, 8, "FBK", &dspi_p->pushr,
+                    DEBUG2_PRINTF(debug_format, 8, "FBK", data_p,
                                   pushr | *data_p, count);
                     return count;
                 }
+                DEBUG3_PRINTF(debug_format, 8, "FAD", data_p,
+                              pushr | *data_p, count-1);
                 dspi_p->pushr = pushr | *data_p++;
-                DEBUG3_PRINTF(debug_format, 8, "FAD", &dspi_p->pushr,
-                              pushr | data_p[-1], count-1);
             }
             pushr |= *data_p;
         } else {
@@ -557,14 +551,14 @@ fifo_pushque_fill(cyg_spi_freescale_dspi
                 if(!(--txfifo_n)) {
                     dspi_p->pushr = pushr |= *data16_p | FREESCALE_DSPI_PUSHR_EOQ_M;
                     count-=2;
-                    DEBUG2_PRINTF(debug_format, 16, "FBK", &dspi_p->pushr,
+                    DEBUG2_PRINTF(debug_format, 16, "FBK", data_p,
                                   pushr, count);
                     return count;
                 }
+                DEBUG3_PRINTF(debug_format, 16, "FAD", data16_p,
+                              pushr | *data16_p, (count-1)*2);
                 data_word = *data16_p++;
                 dspi_p->pushr = pushr | data_word;
-                DEBUG3_PRINTF(debug_format, 16, "FAD", &dspi_p->pushr,
-                              pushr | data_word, (count-1)*2);
             }
             data_word = *data16_p;
             pushr |= data_word;
@@ -587,8 +581,8 @@ fifo_pushque_fill(cyg_spi_freescale_dspi
     if(drop_cs)
         pushr &= ~FREESCALE_DSPI_PUSHR_CONT_M;
     dspi_p->pushr = pushr |= FREESCALE_DSPI_PUSHR_EOQ_M;
-    DEBUG3_PRINTF(debug_format, data_p ? (bus_16bit ? 16 :8) : pushr,
-                  (drop_cs ? "FEN" : "FSG"), &dspi_p->pushr, pushr, 0);
+    DEBUG2_PRINTF(data_p ? debug_format : debug_format1, data_p ? (bus_16bit ? 16 :8) : pushr,
+                  (drop_cs ? "FEN" : "FSG"), data_p /*&dspi_p->pushr*/, pushr, 0);
     return 0;
 }
 
@@ -607,16 +601,17 @@ dma_pushque_fill(cyg_spi_freescale_dspi_
     volatile cyg_uint32* pushque_end;
 
     pushque_p = dspi_bus->pushque_p;
-    pushque_end = pushque_p + dspi_bus->pushque_n;
+    pushque_end = pushque_p + (dspi_bus->pushque_n - (bus_16bit ? 2 : 1));
     pushque_p = dspi_bus->pushque_p;
     if(data_p) {
         if(!bus_16bit) {
             do {
                 if(pushque_p == pushque_end) {
-                    pushque_p[0] = pushr;
-                    pushque_p[-1] |= FREESCALE_DSPI_PUSHR_EOQ_M;
-                    DEBUG2_PRINTF(debug_format, 8, "BRK", pushque_p-1,
-                                  pushque_p[-1], count);
+                    *pushque_p = pushr | *data_p | FREESCALE_DSPI_PUSHR_EOQ_M;
+                    count--;
+
+                    DEBUG2_PRINTF(debug_format, 8, "BRK", pushque_p,
+                                  pushque_p[0], count);
                     return count;
                 }
                 *pushque_p++ = pushr | *data_p++;
@@ -629,10 +624,12 @@ dma_pushque_fill(cyg_spi_freescale_dspi_
             cyg_uint16 data_word;
             do {
                 if(pushque_p == pushque_end) {
-                    pushque_p[0] = pushr;
-                    pushque_p[-1] |= FREESCALE_DSPI_PUSHR_EOQ_M;
-                    DEBUG2_PRINTF(debug_format, 16, "BRK", pushque_p-1,
-                                  pushque_p[-1], count);
+                    data_word = *data16_p;
+                    *pushque_p = pushr | data_word | FREESCALE_DSPI_PUSHR_EOQ_M;
+                    count-=2;
+
+                    DEBUG2_PRINTF(debug_format, 16, "BRK", pushque_p,
+                                  pushque_p[0], count);
                     return count;
                 }
                 data_word = *data16_p++;
@@ -647,22 +644,23 @@ dma_pushque_fill(cyg_spi_freescale_dspi_
         pushr |= PUSHR_NULL;
         do {
             if(pushque_p == pushque_end) {
-                pushque_p[0] = pushr;
-                pushque_p[-1] |= FREESCALE_DSPI_PUSHR_EOQ_M;
-                DEBUG2_PRINTF(debug_format, 0, "BRK", pushque_p-1,
-                              pushque_p[-1], count);
+                *pushque_p = pushr | FREESCALE_DSPI_PUSHR_EOQ_M;
+                count--;
+
+                DEBUG2_PRINTF(debug_format, 0, "BRK", pushque_p,
+                              pushque_p[0], count);
                 return count;
             }
             *pushque_p++ = pushr;
-            DEBUG3_PRINTF(debug_format, 0, "BRK", pushque_p-1, pushque_p[-1],
+            DEBUG3_PRINTF(debug_format, 0, "ADD", pushque_p-1, pushque_p[-1],
                           count-1);
         } while(--count > 1);
     }
     if(drop_cs) pushr &= ~FREESCALE_DSPI_PUSHR_CONT_M;
-    pushque_p[1] = pushr;
     *pushque_p = pushr |= FREESCALE_DSPI_PUSHR_EOQ_M;
     DEBUG2_PRINTF(debug_format, data_p ? (bus_16bit ? 16 :8) : 0,
                   (drop_cs ? "END" : "SGM"), pushque_p, pushque_p[0], 0);
+
     return 0;
 }
 
@@ -745,12 +743,14 @@ static void spi_transaction_do (cyg_spi_
     cyg_uint32 pushque_n;
     cyg_uint32 dma_chan_rx_i = 0;
     cyg_uint32 dma_chan_tx_i = 0;
+    cyg_uint8* rx_data0;
 
 #if DEBUG_SPI >= 2
     cyg_uint32 first_turn = 1;
 #endif
 
-    DEBUG2_PRINTF("DSPI: transaction: count=%d drop_cs=%d\n", count, drop_cs);
+    DEBUG2_PRINTF("DSPI: transaction: count=%d drop_cs=%d tick_only=%d\n",
+                  count, drop_cs, tick_only);
 
     // Set up peripheral CS field. DSPI automatically asserts and deasserts CS
     pushr =
@@ -758,7 +758,7 @@ static void spi_transaction_do (cyg_spi_
           // Compatibility option
           // eCos Reference Manual states that CS should drop prior to sending
           // ticks, but other SPI drivers do not touch the CS.
-          tick_only ? dspi_p->pushr & 0x87FF0000 : 
+          tick_only ? dspi_p->pushr & 0x87FF0000 :
 #endif
           dspi_chip_select_set(
 #ifdef CYGOPT_DEVS_SPI_FREESCALE_DSPI_TICK_ONLY_DROPS_CS
@@ -770,23 +770,14 @@ static void spi_transaction_do (cyg_spi_
     pushr |= FREESCALE_DSPI_PUSHR_CONT_M;
 
     dspi_fifo_clear(dspi_p);
-    dspi_fifo_drain(dspi_p);
 
     pushque_n = dspi_bus->pushque_n;
     if(bus_16bit)
         txfifo_n *= 2;
-    
-    if(count <= txfifo_n){
-        // If byte count fits in the FIFO don't bother with DMA.
-        if((dma_set_p = dspi_bus->setup_p->dma_set_p)) {
-            edma_p = dma_set_p->edma_p;
-            hal_freescale_edma_erq_disable(edma_p, SPI_DMA_CHAN_I(dma_set_p, RX));
-        }
-        dma_set_p = NULL;
-    } else {
-        dma_set_p = dspi_bus->setup_p->dma_set_p;
-    }
-    if(dma_set_p) {
+
+    dma_set_p = dspi_bus->setup_p->dma_set_p;
+    if((count > txfifo_n) && dma_set_p) {
+        rx_data0 = rx_data;
         edma_p = dma_set_p->edma_p;
         // Set up the DMA channels.
         dma_chan_rx_i = SPI_DMA_CHAN_I(dma_set_p, RX);
@@ -794,6 +785,24 @@ static void spi_transaction_do (cyg_spi_
         rx_dma_channel_setup(dma_set_p, (cyg_uint8*) rx_data,
                              bus_16bit, &edma_p->tcd[dma_chan_rx_i]);
         hal_freescale_edma_erq_enable(edma_p, dma_chan_rx_i);
+        dspi_irq_enable(dspi_p,
+                        FREESCALE_DSPI_RSER_TFFF_RE_M   |
+                        FREESCALE_DSPI_RSER_RFDF_RE_M   |
+                        FREESCALE_DSPI_RSER_TFFF_DIRS_M |
+                        FREESCALE_DSPI_RSER_RFDF_DIRS_M);
+    } else {
+        rx_data0 = NULL;
+        // If byte count fits in the FIFO don't bother with DMA.
+        if(dma_set_p) {
+            edma_p = dma_set_p->edma_p;
+            hal_freescale_edma_erq_disable(edma_p, SPI_DMA_CHAN_I(dma_set_p, RX));
+        }
+        dma_set_p = NULL;
+        dspi_irq_disable(dspi_p,
+                         FREESCALE_DSPI_RSER_TFFF_RE_M   |
+                         FREESCALE_DSPI_RSER_RFDF_RE_M   |
+                         FREESCALE_DSPI_RSER_TFFF_DIRS_M |
+                         FREESCALE_DSPI_RSER_RFDF_DIRS_M);
     }
 
     if(!polled)
@@ -836,8 +845,10 @@ static void spi_transaction_do (cyg_spi_
             // Busy-wait for DSPI/DMA (polling for completion).
             while(!(dspi_p->sr & FREESCALE_DSPI_SR_EOQF_M));
 
-            if(dma_set_p) // Disable the Tx DMA channel on completion.
+            if(dma_set_p) {
+                // Disable the Tx DMA channel on completion.
                 hal_freescale_edma_erq_disable(edma_p, dma_chan_tx_i);
+            }
         } else {
             // Wait for DSPI/DMA completion. (interrupt driven).
             cyg_drv_mutex_lock(&dspi_bus->transfer_mutex);
@@ -855,8 +866,12 @@ static void spi_transaction_do (cyg_spi_
 
         if(dma_set_p) {
             // Make sure that Rx has been drained by DMA.
-            if(rx_data)
-                while((dspi_p->sr & FREESCALE_DSPI_SR_RFDF_M));
+            while((dspi_p->sr & FREESCALE_DSPI_SR_RFDF_M));
+            DEBUG2_PRINTF("Fifo Drained by DMA 0x%08x\n", dspi_p->sr);
+            if(count_down <= txfifo_n && count_down > 0) {
+                hal_freescale_edma_erq_disable(edma_p, dma_chan_rx_i);
+                dma_set_p = NULL;
+            }
         } else {
             // No DMA - "manually" drain Rx FIFO
             DEBUG2_PRINTF("DSPI FIFO: 'Manually' drain Rx fifo rx_data=%p bus_16bit=%d\n",
@@ -868,19 +883,18 @@ static void spi_transaction_do (cyg_spi_
                 if(bus_16bit) {
                     cyg_uint16* rx_data16 = (cyg_uint16*) rx_data;
                     while(dspi_p->sr & FREESCALE_DSPI_SR_RXCTR_M) {
-                        DEBUG2_PRINTF("  Fifo Pull16\n");
+                        DEBUG2_PRINTF("  Fifo Pull16 at %p\n", rx_data16);
                         *rx_data16++ = dspi_p->popr;
                     }
                     rx_data = (cyg_uint8*) rx_data16;
                 } else {
                     while(dspi_p->sr & FREESCALE_DSPI_SR_RXCTR_M) {
-                        DEBUG2_PRINTF("  Fifo Pull\n");
+                        DEBUG2_PRINTF("  Fifo Pull at %p\n", rx_data);
                         *rx_data++ = dspi_p->popr;
                     }
                 }
-            } else {
-                dspi_fifo_drain(dspi_p);
             }
+            dspi_fifo_drain(dspi_p);
         }
         dspi_fifo_clear(dspi_p);
         // Prepare for next iteration
@@ -890,16 +904,18 @@ static void spi_transaction_do (cyg_spi_
                 tx_data += pushque_n;
         }
     }
-    if(dma_set_p && rx_data) {
+    if(rx_data0) {
         // Rx buffer may be out of sync with cache.
-        DEBUG2_PRINTF("DSPI DMA: Invalidate cache\n");
-        HAL_DCACHE_INVALIDATE(rx_data, count);
-        DEBUG2_PRINTF("DSPI DMA: Cache invalidated\n");
+        DEBUG2_PRINTF("DSPI DMA: Flush cache %p len=%d\n", rx_data0, count);
+        HAL_DCACHE_INVALIDATE(rx_data0, count);
+        DEBUG2_PRINTF("DSPI DMA: Cache flushed\n");
     }
+
     if(!polled)
         cyg_drv_interrupt_mask(dspi_bus->setup_p->intr_num);
 
     dspi_device->chip_sel = !drop_cs;
+    DEBUG2_PRINTF("cyg_transaction_do() chip_sel = %d drop_cs = %d\n", dspi_device->chip_sel, drop_cs);
 }
 
 //-----------------------------------------------------------------------------
@@ -957,7 +973,7 @@ static void dspi_transaction_transfer(cy
     cyg_spi_freescale_dspi_device_t* dspi_device =
           (cyg_spi_freescale_dspi_device_t*) device;
 
-    DEBUG3_PRINTF("Transaction tx_data = %p count=%d\n", tx_data, count);
+    DEBUG2_PRINTF("Transaction rx_data = %p tx_data = %p count=%d\n", rx_data, tx_data, count);
 
     // Check for unsupported transactions.
     CYG_ASSERT (count > 0, "DSPI: Null transfer requested.");
@@ -993,6 +1009,7 @@ static void dspi_transaction_tick(cyg_sp
     }
 
     // Perform null transfer
+    DEBUG2_PRINTF("cyg_transaction_tick()\n");
     spi_transaction_do (device, true, polled, count, NULL, NULL, false);
 }
 
@@ -1010,6 +1027,7 @@ static void dspi_transaction_end(cyg_spi
     cyghwr_hal_freescale_edma_t *edma_p;
     cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus->setup_p->dspi_p;
 
+    DEBUG2_PRINTF("cyg_transaction_end() chip_sel = %d\n", dspi_device->chip_sel);
     if(dma_set_p) {
         edma_p = dma_set_p->edma_p;
         hal_freescale_edma_erq_disable(edma_p, SPI_DMA_CHAN_I(dma_set_p, TX));
@@ -1018,10 +1036,11 @@ static void dspi_transaction_end(cyg_spi
 
     if(dspi_device->chip_sel){
         // Clear peripheral CS by executing a dummy 4 bit transfer.
-        DSPI_EOQ_CLEAR(dspi_p);
         dspi_p->pushr = PUSHR_NULL | FREESCALE_DSPI_PUSHR_EOQ_M |
                         FREESCALE_DSPI_PUSHR_CTAS(1);
+        DSPI_EOQ_CLEAR(dspi_p);
         while(!(dspi_p->sr & FREESCALE_DSPI_SR_EOQF_M));
+        dspi_fifo_drain(dspi_p);
         dspi_device->chip_sel = 0;
     }
 }