Blackfin: overhaul SPI flash handling to speed things up
authorMike Frysinger <vapier@gentoo.org>
Sun, 12 Oct 2008 02:51:23 +0000 (22:51 -0400)
committerMike Frysinger <vapier@gentoo.org>
Wed, 25 Mar 2009 00:36:31 +0000 (20:36 -0400)
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
board/bf537-stamp/spi_flash.c

index a3368943cd22f9d657f249c5db6aa4d8d6c5e190..214981a4c201395d73a507bee6cb92295904fcd1 100644 (file)
@@ -18,6 +18,7 @@
 #include <malloc.h>
 #include <asm/io.h>
 #include <asm/mach-common/bits/spi.h>
+#include <asm/mach-common/bits/dma.h>
 
 /* Forcibly phase out these */
 #ifdef CONFIG_SPI_FLASH_NUM_SECTORS
@@ -185,7 +186,7 @@ static struct manufacturer_info flash_manufacturers[] = {
        },
 };
 
-#define        TIMEOUT 5000    /* timeout of 5 seconds */
+#define TIMEOUT        5000    /* timeout of 5 seconds */
 
 /* If part has multiple SPI flashes, assume SPI0 as that is
  * the one we can boot off of ...
@@ -213,6 +214,7 @@ static void SPI_INIT(void)
        /* [#3541] This delay appears to be necessary, but not sure
         * exactly why as the history behind it is non-existant.
         */
+       *pSPI_CTL = 0;
        udelay(CONFIG_CCLK_HZ / 25000000);
 
        /* enable SPI pins: SSEL, MOSI, MISO, SCK */
@@ -229,14 +231,13 @@ static void SPI_INIT(void)
 #endif
 
        /* initate communication upon write of TDBR */
-       *pSPI_CTL = (SPE|MSTR|CPHA|CPOL|0x01);
+       *pSPI_CTL = (SPE | MSTR | CPHA | CPOL | TDBR_CORE);
        *pSPI_BAUD = CONFIG_SPI_BAUD;
 }
 
 static void SPI_DEINIT(void)
 {
-       /* put SPI settings back to reset state */
-       *pSPI_CTL = 0x0400;
+       *pSPI_CTL = 0;
        *pSPI_BAUD = 0;
        SSYNC();
 }
@@ -622,9 +623,10 @@ static void transmit_address(uint32_t addr)
  *                     int pnData - pointer to store value read from flash
  *                     long lCount - number of elements to read
  */
+#ifdef CONFIG_SPI_READFLASH_NODMA
 static int read_flash(unsigned long address, long count, uchar *buffer)
 {
-       size_t i;
+       size_t i, j;
 
        /* Send the read command to SPI device */
        SPI_ON();
@@ -638,16 +640,134 @@ static int read_flash(unsigned long address, long count, uchar *buffer)
 
        /* After the SPI device address has been placed on the MOSI pin the data can be */
        /* received on the MISO pin. */
+       j = flash.sector_size << 1;
        for (i = 1; i <= count; ++i) {
                *buffer++ = spi_write_read_byte(0);
-               if (i % flash.sector_size == 0)
+               if (!j--) {
                        puts(".");
+                       j = flash.sector_size;
+               }
+       }
+
+       SPI_OFF();
+
+       return 0;
+}
+#else
+
+#ifdef __ADSPBF54x__
+#define bfin_write_DMA_SPI_IRQ_STATUS     bfin_write_DMA4_IRQ_STATUS
+#define bfin_read_DMA_SPI_IRQ_STATUS      bfin_read_DMA4_IRQ_STATUS
+#define bfin_write_DMA_SPI_CURR_DESC_PTR  bfin_write_DMA4_CURR_DESC_PTR
+#define bfin_write_DMA_SPI_CONFIG         bfin_write_DMA4_CONFIG
+#elif defined(__ADSPBF533__) || defined(__ADSPBF532__) || defined(__ADSPBF531__) || \
+      defined(__ADSPBF538__) || defined(__ADSPBF539__)
+#define bfin_write_DMA_SPI_IRQ_STATUS     bfin_write_DMA5_IRQ_STATUS
+#define bfin_read_DMA_SPI_IRQ_STATUS      bfin_read_DMA5_IRQ_STATUS
+#define bfin_write_DMA_SPI_CURR_DESC_PTR  bfin_write_DMA5_CURR_DESC_PTR
+#define bfin_write_DMA_SPI_CONFIG         bfin_write_DMA5_CONFIG
+#elif defined(__ADSPBF561__)
+#define bfin_write_DMA_SPI_IRQ_STATUS     bfin_write_DMA16_IRQ_STATUS
+#define bfin_read_DMA_SPI_IRQ_STATUS      bfin_read_DMA16_IRQ_STATUS
+#define bfin_write_DMA_SPI_CURR_DESC_PTR  bfin_write_DMA16_CURR_DESC_PTR
+#define bfin_write_DMA_SPI_CONFIG         bfin_write_DMA16_CONFIG
+#elif defined(__ADSPBF537__) || defined(__ADSPBF536__) || defined(__ADSPBF534__) || \
+      defined(__ADSPBF52x__) || defined(__ADSPBF51x__)
+#define bfin_write_DMA_SPI_IRQ_STATUS     bfin_write_DMA7_IRQ_STATUS
+#define bfin_read_DMA_SPI_IRQ_STATUS      bfin_read_DMA7_IRQ_STATUS
+#define bfin_write_DMA_SPI_CURR_DESC_PTR  bfin_write_DMA7_CURR_DESC_PTR
+#define bfin_write_DMA_SPI_CONFIG         bfin_write_DMA7_CONFIG
+#else
+#error "Please provide SPI DMA channel defines"
+#endif
+
+struct dmadesc_array {
+       unsigned long start_addr;
+       unsigned short cfg;
+       unsigned short x_count;
+       short x_modify;
+       unsigned short y_count;
+       short y_modify;
+} __attribute__((packed));
+
+/*
+ * Read a value from flash for verify purpose
+ * Inputs:     unsigned long ulStart - holds the SPI start address
+ *                     int pnData - pointer to store value read from flash
+ *                     long lCount - number of elements to read
+ */
+
+static int read_flash(unsigned long address, long count, uchar *buffer)
+{
+       unsigned int ndsize;
+       struct dmadesc_array dma[2];
+       /* Send the read command to SPI device */
+
+       if (!count)
+               return 0;
+
+       dma[0].start_addr = (unsigned long)buffer;
+       dma[0].x_modify = 1;
+       if (count <= 65536) {
+               blackfin_dcache_flush_invalidate_range(buffer, buffer + count);
+               ndsize = NDSIZE_5;
+               dma[0].cfg = NDSIZE_0 | WNR | WDSIZE_8 | FLOW_STOP | DMAEN | DI_EN;
+               dma[0].x_count = count;
+       } else {
+               blackfin_dcache_flush_invalidate_range(buffer, buffer + 65536 - 1);
+               ndsize = NDSIZE_7;
+               dma[0].cfg = NDSIZE_5 | WNR | WDSIZE_8 | FLOW_ARRAY | DMAEN | DMA2D;
+               dma[0].x_count = 0;     /* 2^16 */
+               dma[0].y_count = count >> 16;   /* count / 2^16 */
+               dma[0].y_modify = 1;
+               dma[1].start_addr = (unsigned long)(buffer + (count & ~0xFFFF));
+               dma[1].cfg = NDSIZE_0 | WNR | WDSIZE_8 | FLOW_STOP | DMAEN | DI_EN;
+               dma[1].x_count = count & 0xFFFF; /* count % 2^16 */
+               dma[1].x_modify = 1;
        }
 
+       bfin_write_DMA_SPI_CONFIG(0);
+       bfin_write_DMA_SPI_IRQ_STATUS(DMA_DONE | DMA_ERR);
+       bfin_write_DMA_SPI_CURR_DESC_PTR(dma);
+
+       SPI_ON();
+
+       spi_write_read_byte(flash.ops->read);
+       transmit_address(address);
+
+#ifndef CONFIG_SPI_FLASH_SLOW_READ
+       /* Send dummy byte when doing SPI fast reads */
+       spi_write_read_byte(0);
+#endif
+
+       bfin_write_DMA_SPI_CONFIG(ndsize | FLOW_ARRAY | DMAEN);
+       *pSPI_CTL = (MSTR | CPHA | CPOL | RDBR_DMA | SPE | SZ);
+       SSYNC();
+
+       /*
+        * We already invalidated the first 64k,
+        * now while we just wait invalidate the remaining part.
+        * Its not likely that the DMA is going to overtake
+        */
+       if (count > 65536)
+               blackfin_dcache_flush_invalidate_range(buffer + 65536,
+                                                        buffer + count);
+
+       while (!(bfin_read_DMA_SPI_IRQ_STATUS() & DMA_DONE))
+               if (ctrlc())
+                       break;
+
        SPI_OFF();
 
+       *pSPI_CTL = 0;
+
+       bfin_write_DMA_SPI_CONFIG(0);
+
+       *pSPI_CTL = (SPE | MSTR | CPHA | CPOL | TDBR_CORE);
+
        return 0;
 }
+#endif
 
 static long address_to_sector(unsigned long address)
 {