diff options
Diffstat (limited to 'board/bf537-stamp/spi_flash.c')
-rw-r--r-- | board/bf537-stamp/spi_flash.c | 297 |
1 files changed, 241 insertions, 56 deletions
diff --git a/board/bf537-stamp/spi_flash.c b/board/bf537-stamp/spi_flash.c index 7b764b4..7b753ad 100644 --- a/board/bf537-stamp/spi_flash.c +++ b/board/bf537-stamp/spi_flash.c @@ -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 @@ -32,53 +33,65 @@ struct flash_info { char *name; uint16_t id; + uint16_t ext_id; unsigned sector_size; unsigned num_sectors; }; /* SPI Speeds: 50 MHz / 33 MHz */ static struct flash_info flash_spansion_serial_flash[] = { - { "S25FL016", 0x0215, 64 * 1024, 32 }, - { "S25FL032", 0x0216, 64 * 1024, 64 }, - { "S25FL064", 0x0217, 64 * 1024, 128 }, - { "S25FL0128", 0x0218, 256 * 1024, 64 }, - { NULL, 0, 0, 0 } + { "S25FL016", 0x0215, 0, 64 * 1024, 32 }, + { "S25FL032", 0x0216, 0, 64 * 1024, 64 }, + { "S25FL064", 0x0217, 0, 64 * 1024, 128 }, + { "S25FL128-00", 0x2018, 0x0301, 64 * 1024, 256 }, /* Package marking FL128PIF */ + { "S25FL128-01", 0x2018, 0x0300, 128 * 1024, 64 }, /* Package marking FL128PIFL */ + { NULL, 0, 0, 0, 0 } }; /* SPI Speeds: 50 MHz / 20 MHz */ static struct flash_info flash_st_serial_flash[] = { - { "m25p05", 0x2010, 32 * 1024, 2 }, - { "m25p10", 0x2011, 32 * 1024, 4 }, - { "m25p20", 0x2012, 64 * 1024, 4 }, - { "m25p40", 0x2013, 64 * 1024, 8 }, - { "m25p16", 0x2015, 64 * 1024, 32 }, - { "m25p32", 0x2016, 64 * 1024, 64 }, - { "m25p64", 0x2017, 64 * 1024, 128 }, - { "m25p128", 0x2018, 256 * 1024, 64 }, - { NULL, 0, 0, 0 } + { "m25p05", 0x2010, 0, 32 * 1024, 2 }, + { "m25p10", 0x2011, 0, 32 * 1024, 4 }, + { "m25p20", 0x2012, 0, 64 * 1024, 4 }, + { "m25p40", 0x2013, 0, 64 * 1024, 8 }, + { "m25p80", 0x20FF, 0, 64 * 1024, 16 }, + { "m25p16", 0x2015, 0, 64 * 1024, 32 }, + { "m25p32", 0x2016, 0, 64 * 1024, 64 }, + { "m25p64", 0x2017, 0, 64 * 1024, 128 }, + { "m25p128", 0x2018, 0, 256 * 1024, 64 }, + { NULL, 0, 0, 0, 0 } +}; + +/* SPI Speeds: 20 MHz / 40 MHz */ +static struct flash_info flash_sst_serial_flash[] = { + { "SST25WF512", 0x2501, 0, 4 * 1024, 128 }, + { "SST25WF010", 0x2502, 0, 4 * 1024, 256 }, + { "SST25WF020", 0x2503, 0, 4 * 1024, 512 }, + { "SST25WF040", 0x2504, 0, 4 * 1024, 1024 }, + { NULL, 0, 0, 0, 0 } }; /* SPI Speeds: 66 MHz / 33 MHz */ static struct flash_info flash_atmel_dataflash[] = { - { "AT45DB011x", 0x0c, 264, 512 }, - { "AT45DB021x", 0x14, 264, 1025 }, - { "AT45DB041x", 0x1c, 264, 2048 }, - { "AT45DB081x", 0x24, 264, 4096 }, - { "AT45DB161x", 0x2c, 528, 4096 }, - { "AT45DB321x", 0x34, 528, 8192 }, - { "AT45DB642x", 0x3c, 1056, 8192 }, - { NULL, 0, 0, 0 } + { "AT45DB011x", 0x0c, 0, 264, 512 }, + { "AT45DB021x", 0x14, 0, 264, 1025 }, + { "AT45DB041x", 0x1c, 0, 264, 2048 }, + { "AT45DB081x", 0x24, 0, 264, 4096 }, + { "AT45DB161x", 0x2c, 0, 528, 4096 }, + { "AT45DB321x", 0x34, 0, 528, 8192 }, + { "AT45DB642x", 0x3c, 0, 1056, 8192 }, + { NULL, 0, 0, 0, 0 } }; /* SPI Speed: 50 MHz / 25 MHz or 40 MHz / 20 MHz */ static struct flash_info flash_winbond_serial_flash[] = { - { "W25X10", 0x3011, 16 * 256, 32 }, - { "W25X20", 0x3012, 16 * 256, 64 }, - { "W25X40", 0x3013, 16 * 256, 128 }, - { "W25X80", 0x3014, 16 * 256, 256 }, - { "W25P80", 0x2014, 256 * 256, 16 }, - { "W25P16", 0x2015, 256 * 256, 32 }, - { NULL, 0, 0, 0 } + { "W25X10", 0x3011, 0, 16 * 256, 32 }, + { "W25X20", 0x3012, 0, 16 * 256, 64 }, + { "W25X40", 0x3013, 0, 16 * 256, 128 }, + { "W25X80", 0x3014, 0, 16 * 256, 256 }, + { "W25P80", 0x2014, 0, 256 * 256, 16 }, + { "W25P16", 0x2015, 0, 256 * 256, 32 }, + { NULL, 0, 0, 0, 0 } }; struct flash_ops { @@ -97,6 +110,13 @@ static struct flash_ops flash_st_ops = { .status = 0x05, }; +static struct flash_ops flash_sst_ops = { + .read = OP_READ, + .write = 0x02, + .erase = 0x20, + .status = 0x05, +}; + static struct flash_ops flash_atmel_ops = { .read = OP_READ, .write = 0x82, @@ -122,7 +142,7 @@ static struct { struct manufacturer_info *manufacturer; struct flash_info *flash; struct flash_ops *ops; - uint8_t manufacturer_id, device_id1, device_id2; + uint8_t manufacturer_id, device_id1, device_id2, device_extid1, device_extid2; unsigned int write_length; unsigned long sector_size, num_sectors; } flash; @@ -130,6 +150,7 @@ static struct { enum { JED_MANU_SPANSION = 0x01, JED_MANU_ST = 0x20, + JED_MANU_SST = 0xBF, JED_MANU_ATMEL = 0x1F, JED_MANU_WINBOND = 0xEF, }; @@ -148,6 +169,12 @@ static struct manufacturer_info flash_manufacturers[] = { .ops = &flash_st_ops, }, { + .name = "SST", + .id = JED_MANU_SST, + .flashes = flash_sst_serial_flash, + .ops = &flash_sst_ops, + }, + { .name = "Atmel", .id = JED_MANU_ATMEL, .flashes = flash_atmel_dataflash, @@ -161,7 +188,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 ... @@ -189,6 +216,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 */ @@ -205,14 +233,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(); } @@ -275,6 +302,7 @@ static int wait_for_ready_status(void) switch (flash.manufacturer_id) { case JED_MANU_SPANSION: case JED_MANU_ST: + case JED_MANU_SST: case JED_MANU_WINBOND: if (!(read_status_register() & 0x01)) return 0; @@ -296,19 +324,68 @@ static int wait_for_ready_status(void) return -1; } +static int enable_writing(void) +{ + ulong start; + + if (flash.manufacturer_id == JED_MANU_ATMEL) + return 0; + + /* A write enable instruction must previously have been executed */ + SPI_ON(); + spi_write_read_byte(0x06); + SPI_OFF(); + + /* The status register will be polled to check the write enable latch "WREN" */ + start = get_timer(0); + while (get_timer(0) - start < TIMEOUT) { + if (read_status_register() & 0x02) + return 0; + + if (ctrlc()) { + puts("\nAbort\n"); + return -1; + } + } + + puts("Timeout\n"); + return -1; +} + +static void write_status_register(uint8_t val) +{ + if (flash.manufacturer_id != JED_MANU_SST) + hang(); + + if (enable_writing()) + return; + + /* send instruction to write status register */ + SPI_ON(); + spi_write_read_byte(0x01); + /* and clear it! */ + spi_write_read_byte(val); + SPI_OFF(); +} + /* Request and read the manufacturer and device id of parts which * are compatible with the JEDEC standard (JEP106) and use that to * setup other operating conditions. */ static int spi_detect_part(void) { - uint16_t dev_id; + uint16_t dev_id, dev_extid; size_t i; static char called_init; if (called_init) return 0; +#ifdef CONFIG_SPI_FLASH_M25P80 + flash.manufacturer_id = JED_MANU_ST; + flash.device_id1 = 0x20; + flash.device_id2 = 0xFF; +#else SPI_ON(); /* Send the request for the part identification */ @@ -327,9 +404,15 @@ static int spi_detect_part(void) /* Now read in the second device id byte */ flash.device_id2 = spi_write_read_byte(0); + /* Read extended device ids */ + flash.device_extid1 = spi_write_read_byte(0); + flash.device_extid2 = spi_write_read_byte(0); + SPI_OFF(); +#endif dev_id = (flash.device_id1 << 8) | flash.device_id2; + dev_extid = (flash.device_extid1 << 8) | flash.device_extid2; for (i = 0; i < ARRAY_SIZE(flash_manufacturers); ++i) { if (flash.manufacturer_id == flash_manufacturers[i].id) @@ -344,9 +427,12 @@ static int spi_detect_part(void) switch (flash.manufacturer_id) { case JED_MANU_SPANSION: case JED_MANU_ST: + case JED_MANU_SST: case JED_MANU_WINBOND: for (i = 0; flash.manufacturer->flashes[i].name; ++i) { - if (dev_id == flash.manufacturer->flashes[i].id) + if (dev_id == flash.manufacturer->flashes[i].id && + (flash.manufacturer->flashes[i].ext_id == 0 || + flash.manufacturer->flashes[i].ext_id == dev_extid)) break; } if (!flash.manufacturer->flashes[i].name) @@ -355,7 +441,11 @@ static int spi_detect_part(void) flash.flash = &flash.manufacturer->flashes[i]; flash.sector_size = flash.flash->sector_size; flash.num_sectors = flash.flash->num_sectors; - flash.write_length = 256; + + if (flash.manufacturer_id == JED_MANU_SST) + flash.write_length = 1; /* pwnt :( */ + else + flash.write_length = 256; break; case JED_MANU_ATMEL: { @@ -381,6 +471,10 @@ static int spi_detect_part(void) } } + /* the SST parts power up with software protection enabled by default */ + if (flash.manufacturer_id == JED_MANU_SST) + write_status_register(0); + called_init = 1; return 0; @@ -538,9 +632,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(); @@ -554,44 +649,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 -static int enable_writing(void) +#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) { - ulong start; + unsigned int ndsize; + struct dmadesc_array dma[2]; + /* Send the read command to SPI device */ - if (flash.manufacturer_id == JED_MANU_ATMEL) + if (!count) return 0; - /* A write enable instruction must previously have been executed */ + 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(0x06); + + 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(); - /* The status register will be polled to check the write enable latch "WREN" */ - start = get_timer(0); - while (get_timer(0) - start < TIMEOUT) { - if (read_status_register() & 0x02) - return 0; + *pSPI_CTL = 0; - if (ctrlc()) { - puts("\nAbort\n"); - return -1; - } - } + bfin_write_DMA_SPI_CONFIG(0); - puts("Timeout\n"); - return -1; + *pSPI_CTL = (SPE | MSTR | CPHA | CPOL | TDBR_CORE); + + return 0; } +#endif static long address_to_sector(unsigned long address) { |