From bf1e028bf3eab1d702fa0627cade4460688f3913 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 11 Oct 2008 22:51:23 -0400 Subject: Blackfin: overhaul SPI flash handling to speed things up Signed-off-by: Mike Frysinger --- board/bf537-stamp/spi_flash.c | 132 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 6 deletions(-) diff --git a/board/bf537-stamp/spi_flash.c b/board/bf537-stamp/spi_flash.c index a3368943cd..214981a4c2 100644 --- a/board/bf537-stamp/spi_flash.c +++ b/board/bf537-stamp/spi_flash.c @@ -18,6 +18,7 @@ #include #include #include +#include /* 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) { -- cgit v1.2.1