Blackfin: overhaul SPI flash handling to speed things up

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
This commit is contained in:
Mike Frysinger 2008-10-11 22:51:23 -04:00
parent efcc08cede
commit bf1e028bf3

View file

@ -18,6 +18,7 @@
#include <malloc.h> #include <malloc.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/mach-common/bits/spi.h> #include <asm/mach-common/bits/spi.h>
#include <asm/mach-common/bits/dma.h>
/* Forcibly phase out these */ /* Forcibly phase out these */
#ifdef CONFIG_SPI_FLASH_NUM_SECTORS #ifdef CONFIG_SPI_FLASH_NUM_SECTORS
@ -213,6 +214,7 @@ static void SPI_INIT(void)
/* [#3541] This delay appears to be necessary, but not sure /* [#3541] This delay appears to be necessary, but not sure
* exactly why as the history behind it is non-existant. * exactly why as the history behind it is non-existant.
*/ */
*pSPI_CTL = 0;
udelay(CONFIG_CCLK_HZ / 25000000); udelay(CONFIG_CCLK_HZ / 25000000);
/* enable SPI pins: SSEL, MOSI, MISO, SCK */ /* enable SPI pins: SSEL, MOSI, MISO, SCK */
@ -229,14 +231,13 @@ static void SPI_INIT(void)
#endif #endif
/* initate communication upon write of TDBR */ /* 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; *pSPI_BAUD = CONFIG_SPI_BAUD;
} }
static void SPI_DEINIT(void) static void SPI_DEINIT(void)
{ {
/* put SPI settings back to reset state */ *pSPI_CTL = 0;
*pSPI_CTL = 0x0400;
*pSPI_BAUD = 0; *pSPI_BAUD = 0;
SSYNC(); SSYNC();
} }
@ -622,9 +623,10 @@ static void transmit_address(uint32_t addr)
* int pnData - pointer to store value read from flash * int pnData - pointer to store value read from flash
* long lCount - number of elements to read * long lCount - number of elements to read
*/ */
#ifdef CONFIG_SPI_READFLASH_NODMA
static int read_flash(unsigned long address, long count, uchar *buffer) 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 */ /* Send the read command to SPI device */
SPI_ON(); 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 */ /* After the SPI device address has been placed on the MOSI pin the data can be */
/* received on the MISO pin. */ /* received on the MISO pin. */
j = flash.sector_size << 1;
for (i = 1; i <= count; ++i) { for (i = 1; i <= count; ++i) {
*buffer++ = spi_write_read_byte(0); *buffer++ = spi_write_read_byte(0);
if (i % flash.sector_size == 0) if (!j--) {
puts("."); puts(".");
j = flash.sector_size;
}
} }
SPI_OFF(); SPI_OFF();
return 0; 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) static long address_to_sector(unsigned long address)
{ {