diff options
author | Mike Frysinger <vapier@gentoo.org> | 2008-02-19 00:58:13 -0500 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2008-03-30 15:13:42 -0400 |
commit | 9ce7e53abd039decea1af67aec81bbd5df7a2593 (patch) | |
tree | 107b16118720b894357b18a1db16ca690239d136 /board/bf537-stamp | |
parent | 74d1e66d22dac91388bc538b2fe19f735edc5b82 (diff) |
Blackfin: BF537-stamp: cleanup spi flash driver
This punts the old spi flash driver for a new/generalized one until the
common one can be integrated.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'board/bf537-stamp')
-rw-r--r-- | board/bf537-stamp/Makefile | 2 | ||||
-rw-r--r-- | board/bf537-stamp/spi_flash.c | 815 | ||||
-rw-r--r-- | board/bf537-stamp/stm_m25p64.c | 516 |
3 files changed, 816 insertions, 517 deletions
diff --git a/board/bf537-stamp/Makefile b/board/bf537-stamp/Makefile index 5d22393371..5326154972 100644 --- a/board/bf537-stamp/Makefile +++ b/board/bf537-stamp/Makefile @@ -29,7 +29,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(BOARD).a -COBJS := $(BOARD).o post-memory.o stm_m25p64.o cmd_bf537led.o nand.o +COBJS := $(BOARD).o post-memory.o spi_flash.o cmd_bf537led.o nand.o SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS)) diff --git a/board/bf537-stamp/spi_flash.c b/board/bf537-stamp/spi_flash.c new file mode 100644 index 0000000000..7c73ddd720 --- /dev/null +++ b/board/bf537-stamp/spi_flash.c @@ -0,0 +1,815 @@ +/* + * SPI flash driver + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Copyright (c) 2005-2007 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +/* Configuration options: + * CONFIG_SPI_BAUD - value to load into SPI_BAUD (divisor of SCLK to get SPI CLK) + * CONFIG_SPI_FLASH_SLOW_READ - force usage of the slower read + * WARNING: make sure your SCLK + SPI_BAUD is slow enough + */ + +#include <common.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/mach-common/bits/spi.h> + +/* Forcibly phase out these */ +#ifdef CONFIG_SPI_FLASH_NUM_SECTORS +# error do not set CONFIG_SPI_FLASH_NUM_SECTORS +#endif +#ifdef CONFIG_SPI_FLASH_SECTOR_SIZE +# error do not set CONFIG_SPI_FLASH_SECTOR_SIZE +#endif + +#if defined(CONFIG_SPI) + +struct flash_info { + char *name; + uint16_t 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 } +}; + +/* 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 } +}; + +/* 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 } +}; + +/* 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 } +}; + +struct flash_ops { + uint8_t read, write, erase, status; +}; + +#ifdef CONFIG_SPI_FLASH_SLOW_READ +# define OP_READ 0x03 +#else +# define OP_READ 0x0B +#endif +static struct flash_ops flash_st_ops = { + .read = OP_READ, + .write = 0x02, + .erase = 0xD8, + .status = 0x05, +}; + +static struct flash_ops flash_atmel_ops = { + .read = OP_READ, + .write = 0x82, + .erase = 0x81, + .status = 0xD7, +}; + +static struct flash_ops flash_winbond_ops = { + .read = OP_READ, + .write = 0x02, + .erase = 0x20, + .status = 0x05, +}; + +struct manufacturer_info { + const char *name; + uint8_t id; + struct flash_info *flashes; + struct flash_ops *ops; +}; + +static struct { + struct manufacturer_info *manufacturer; + struct flash_info *flash; + struct flash_ops *ops; + uint8_t manufacturer_id, device_id1, device_id2; + unsigned int write_length; + unsigned long sector_size, num_sectors; +} flash; + +enum { + JED_MANU_SPANSION = 0x01, + JED_MANU_ST = 0x20, + JED_MANU_ATMEL = 0x1F, + JED_MANU_WINBOND = 0xEF, +}; + +static struct manufacturer_info flash_manufacturers[] = { + { + .name = "Spansion", + .id = JED_MANU_SPANSION, + .flashes = flash_spansion_serial_flash, + .ops = &flash_st_ops, + }, + { + .name = "ST", + .id = JED_MANU_ST, + .flashes = flash_st_serial_flash, + .ops = &flash_st_ops, + }, + { + .name = "Atmel", + .id = JED_MANU_ATMEL, + .flashes = flash_atmel_dataflash, + .ops = &flash_atmel_ops, + }, + { + .name = "Winbond", + .id = JED_MANU_WINBOND, + .flashes = flash_winbond_serial_flash, + .ops = &flash_winbond_ops, + }, +}; + +#define TIMEOUT 5000 /* timeout of 5 seconds */ + +/* BF54x support */ +#ifndef pSPI_CTL +# define pSPI_CTL pSPI0_CTL +# define pSPI_BAUD pSPI0_BAUD +# define pSPI_FLG pSPI0_FLG +# define pSPI_RDBR pSPI0_RDBR +# define pSPI_STAT pSPI0_STAT +# define pSPI_TDBR pSPI0_TDBR +# define SPI0_SCK 0x0001 +# define SPI0_MOSI 0x0004 +# define SPI0_MISO 0x0002 +# define SPI0_SEL1 0x0010 +#endif + +/* Default to the SPI SSEL that we boot off of: + * BF54x, BF537, (everything new?): SSEL1 + * BF533, BF561: SSEL2 + */ +#ifndef CONFIG_SPI_FLASH_SSEL +# if defined(__ADSPBF531__) || defined(__ADSPBF532__) || \ + defined(__ADSPBF533__) || defined(__ADSPBF561__) +# define CONFIG_SPI_FLASH_SSEL 2 +# else +# define CONFIG_SPI_FLASH_SSEL 1 +# endif +#endif +#define SSEL_MASK (1 << CONFIG_SPI_FLASH_SSEL) + +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. + */ + udelay(CONFIG_CCLK_HZ / 25000000); + + /* enable SPI pins: SSEL, MOSI, MISO, SCK */ +#ifdef __ADSPBF54x__ + *pPORTE_FER |= (SPI0_SCK | SPI0_MOSI | SPI0_MISO | SPI0_SEL1); +#elif defined(__ADSPBF534__) || defined(__ADSPBF536__) || defined(__ADSPBF537__) + *pPORTF_FER |= (PF10 | PF11 | PF12 | PF13); +#elif defined(__ADSPBF52x__) + bfin_write_PORTG_MUX((bfin_read_PORTG_MUX() & ~PORT_x_MUX_0_MASK) | PORT_x_MUX_0_FUNC_3); + bfin_write_PORTG_FER(bfin_read_PORTG_FER() | PG1 | PG2 | PG3 | PG4); +#endif + + /* initate communication upon write of TDBR */ + *pSPI_CTL = (SPE|MSTR|CPHA|CPOL|0x01); + *pSPI_BAUD = CONFIG_SPI_BAUD; +} + +static void SPI_DEINIT(void) +{ + /* put SPI settings back to reset state */ + *pSPI_CTL = 0x0400; + *pSPI_BAUD = 0; + SSYNC(); +} + +static void SPI_ON(void) +{ + /* toggle SSEL to reset the device so it'll take a new command */ + *pSPI_FLG = 0xFF00 | SSEL_MASK; + SSYNC(); + + *pSPI_FLG = ((0xFF & ~SSEL_MASK) << 8) | SSEL_MASK; + SSYNC(); +} + +static void SPI_OFF(void) +{ + /* put SPI settings back to reset state */ + *pSPI_FLG = 0xFF00; + SSYNC(); +} + +static uint8_t spi_write_read_byte(uint8_t transmit) +{ + *pSPI_TDBR = transmit; + SSYNC(); + + while ((*pSPI_STAT & TXS)) + if (ctrlc()) + break; + while (!(*pSPI_STAT & SPIF)) + if (ctrlc()) + break; + while (!(*pSPI_STAT & RXS)) + if (ctrlc()) + break; + + /* Read dummy to empty the receive register */ + return *pSPI_RDBR; +} + +static uint8_t read_status_register(void) +{ + uint8_t status_register; + + /* send instruction to read status register */ + SPI_ON(); + spi_write_read_byte(flash.ops->status); + /* send dummy to receive the status register */ + status_register = spi_write_read_byte(0); + SPI_OFF(); + + return status_register; +} + +static int wait_for_ready_status(void) +{ + ulong start = get_timer(0); + + while (get_timer(0) - start < TIMEOUT) { + switch (flash.manufacturer_id) { + case JED_MANU_SPANSION: + case JED_MANU_ST: + case JED_MANU_WINBOND: + if (!(read_status_register() & 0x01)) + return 0; + break; + + case JED_MANU_ATMEL: + if (read_status_register() & 0x80) + return 0; + break; + } + + if (ctrlc()) { + puts("\nAbort\n"); + return -1; + } + } + + puts("Timeout\n"); + return -1; +} + +/* 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; + size_t i; + + static char called_init; + if (called_init) + return 0; + + SPI_ON(); + + /* Send the request for the part identification */ + spi_write_read_byte(0x9F); + + /* Now read in the manufacturer id bytes */ + do { + flash.manufacturer_id = spi_write_read_byte(0); + if (flash.manufacturer_id == 0x7F) + puts("Warning: unhandled manufacturer continuation byte!\n"); + } while (flash.manufacturer_id == 0x7F); + + /* Now read in the first device id byte */ + flash.device_id1 = spi_write_read_byte(0); + + /* Now read in the second device id byte */ + flash.device_id2 = spi_write_read_byte(0); + + SPI_OFF(); + + dev_id = (flash.device_id1 << 8) | flash.device_id2; + + for (i = 0; i < ARRAY_SIZE(flash_manufacturers); ++i) { + if (flash.manufacturer_id == flash_manufacturers[i].id) + break; + } + if (i == ARRAY_SIZE(flash_manufacturers)) + goto unknown; + + flash.manufacturer = &flash_manufacturers[i]; + flash.ops = flash_manufacturers[i].ops; + + switch (flash.manufacturer_id) { + case JED_MANU_SPANSION: + case JED_MANU_ST: + case JED_MANU_WINBOND: + for (i = 0; flash.manufacturer->flashes[i].name; ++i) { + if (dev_id == flash.manufacturer->flashes[i].id) + break; + } + if (!flash.manufacturer->flashes[i].name) + goto unknown; + + flash.flash = &flash.manufacturer->flashes[i]; + flash.sector_size = flash.flash->sector_size; + flash.num_sectors = flash.flash->num_sectors; + flash.write_length = 256; + break; + + case JED_MANU_ATMEL: { + uint8_t status = read_status_register(); + + for (i = 0; flash.manufacturer->flashes[i].name; ++i) { + if ((status & 0x3c) == flash.manufacturer->flashes[i].id) + break; + } + if (!flash.manufacturer->flashes[i].name) + goto unknown; + + flash.flash = &flash.manufacturer->flashes[i]; + flash.sector_size = flash.flash->sector_size; + flash.num_sectors = flash.flash->num_sectors; + + /* see if flash is in "power of 2" mode */ + if (status & 0x1) + flash.sector_size &= ~(1 << (ffs(flash.sector_size) - 1)); + + flash.write_length = flash.sector_size; + break; + } + } + + called_init = 1; + return 0; + + unknown: + printf("Unknown SPI device: 0x%02X 0x%02X 0x%02X\n", + flash.manufacturer_id, flash.device_id1, flash.device_id2); + return 1; +} + +/* + * Function: spi_init_f + * Description: Init SPI-Controller (ROM part) + * return: --- + */ +void spi_init_f(void) +{ +} + +/* + * Function: spi_init_r + * Description: Init SPI-Controller (RAM part) - + * The malloc engine is ready and we can move our buffers to + * normal RAM + * return: --- + */ +void spi_init_r(void) +{ +#if defined(CONFIG_POST) && (CONFIG_POST & CFG_POST_SPI) + /* Our testing strategy here is pretty basic: + * - fill src memory with an 8-bit pattern + * - write the src memory to the SPI flash + * - read the SPI flash into the dst memory + * - compare src and dst memory regions + * - repeat a few times + * The variations we test for: + * - change the 8-bit pattern a bit + * - change the read/write block size so we know: + * - writes smaller/equal/larger than the buffer work + * - writes smaller/equal/larger than the sector work + * - change the SPI offsets so we know: + * - writing partial sectors works + */ + uint8_t *mem_src, *mem_dst; + size_t i, c, l, o; + size_t test_count, errors; + uint8_t pattern; + + SPI_INIT(); + + if (spi_detect_part()) + goto out; + eeprom_info(); + + ulong lengths[] = { + flash.write_length, + flash.write_length * 2, + flash.write_length / 2, + flash.sector_size, + flash.sector_size * 2, + flash.sector_size / 2 + }; + ulong offsets[] = { + 0, + flash.write_length, + flash.write_length * 2, + flash.write_length / 2, + flash.write_length / 4, + flash.sector_size, + flash.sector_size * 2, + flash.sector_size / 2, + flash.sector_size / 4, + }; + + /* the exact addresses are arbitrary ... they just need to not overlap */ + mem_src = (void *)(0); + mem_dst = (void *)(max(flash.write_length, flash.sector_size) * 2); + + test_count = 0; + errors = 0; + pattern = 0x00; + + for (i = 0; i < 16; ++i) { /* 16 = 8 bits * 2 iterations */ + for (l = 0; l < ARRAY_SIZE(lengths); ++l) { + for (o = 0; o < ARRAY_SIZE(offsets); ++o) { + ulong len = lengths[l]; + ulong off = offsets[o]; + + printf("Testing pattern 0x%02X of length %5lu and offset %5lu: ", pattern, len, off); + + /* setup the source memory region */ + memset(mem_src, pattern, len); + + test_count += 4; + for (c = 0; c < 4; ++c) { /* 4 is just a random repeat count */ + if (ctrlc()) { + puts("\nAbort\n"); + goto out; + } + + /* make sure background fill pattern != pattern */ + memset(mem_dst, pattern ^ 0xFF, len); + + /* write out the source memory and then read it back and compare */ + eeprom_write(0, off, mem_src, len); + eeprom_read(0, off, mem_dst, len); + + if (memcmp(mem_src, mem_dst, len)) { + for (c = 0; c < len; ++c) + if (mem_src[c] != mem_dst[c]) + break; + printf(" FAIL @ offset %u, skipping repeats ", c); + ++errors; + break; + } + + /* XXX: should shrink write region here to test with + * leading/trailing canaries so we know surrounding + * bytes don't get screwed. + */ + } + puts("\n"); + } + } + + /* invert the pattern every other run and shift out bits slowly */ + pattern ^= 0xFF; + if (i % 2) + pattern = (pattern | 0x01) << 1; + } + + if (errors) + printf("SPI FAIL: Out of %i tests, there were %i errors ;(\n", test_count, errors); + else + printf("SPI PASS: %i tests worked!\n", test_count); + + out: + SPI_DEINIT(); + +#endif +} + +static void transmit_address(uint32_t addr) +{ + /* Send the highest byte of the 24 bit address at first */ + spi_write_read_byte(addr >> 16); + /* Send the middle byte of the 24 bit address at second */ + spi_write_read_byte(addr >> 8); + /* Send the lowest byte of the 24 bit address finally */ + spi_write_read_byte(addr); +} + +/* + * 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) +{ + size_t i; + + /* Send the read command to SPI device */ + 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 + + /* After the SPI device address has been placed on the MOSI pin the data can be */ + /* received on the MISO pin. */ + for (i = 1; i <= count; ++i) { + *buffer++ = spi_write_read_byte(0); + if (i % flash.sector_size == 0) + puts("."); + } + + SPI_OFF(); + + return 0; +} + +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 long address_to_sector(unsigned long address) +{ + if (address > (flash.num_sectors * flash.sector_size) - 1) + return -1; + return address / flash.sector_size; +} + +static int erase_sector(int address) +{ + /* sector gets checked in higher function, so assume it's valid + * here and figure out the offset of the sector in flash + */ + if (enable_writing()) + return -1; + + /* + * Send the erase block command to the flash followed by the 24 address + * to point to the start of a sector + */ + SPI_ON(); + spi_write_read_byte(flash.ops->erase); + transmit_address(address); + SPI_OFF(); + + return wait_for_ready_status(); +} + +/* Write [count] bytes out of [buffer] into the given SPI [address] */ +static long write_flash(unsigned long address, long count, uchar *buffer) +{ + long i, write_buffer_size; + + if (enable_writing()) + return -1; + + /* Send write command followed by the 24 bit address */ + SPI_ON(); + spi_write_read_byte(flash.ops->write); + transmit_address(address); + + /* Shoot out a single write buffer */ + write_buffer_size = min(count, flash.write_length); + for (i = 0; i < write_buffer_size; ++i) + spi_write_read_byte(buffer[i]); + + SPI_OFF(); + + /* Wait for the flash to do its thing */ + if (wait_for_ready_status()) { + puts("SPI Program Time out! "); + return -1; + } + + return i; +} + +/* Write [count] bytes out of [buffer] into the given SPI [address] */ +static int write_sector(unsigned long address, long count, uchar *buffer) +{ + long write_cnt; + + while (count != 0) { + write_cnt = write_flash(address, count, buffer); + if (write_cnt == -1) + return -1; + + /* Now that we've sent some bytes out to the flash, update + * our counters a bit + */ + count -= write_cnt; + address += write_cnt; + buffer += write_cnt; + } + + /* return the appropriate error code */ + return 0; +} + +/* + * Function: spi_write + */ +ssize_t spi_write(uchar *addr, int alen, uchar *buffer, int len) +{ + unsigned long offset; + int start_sector, end_sector; + int start_byte, end_byte; + uchar *temp = NULL; + int num, ret = 0; + + SPI_INIT(); + + if (spi_detect_part()) + goto out; + + offset = addr[0] << 16 | addr[1] << 8 | addr[2]; + + /* Get the start block number */ + start_sector = address_to_sector(offset); + if (start_sector == -1) { + puts("Invalid sector! "); + goto out; + } + end_sector = address_to_sector(offset + len - 1); + if (end_sector == -1) { + puts("Invalid sector! "); + goto out; + } + + /* Since flashes operate in sector units but the eeprom command + * operates as a continuous stream of bytes, we need to emulate + * the eeprom behavior. So here we read in the sector, overlay + * any bytes we're actually modifying, erase the sector, and + * then write back out the new sector. + */ + temp = malloc(flash.sector_size); + if (!temp) { + puts("Malloc for sector failed! "); + goto out; + } + + for (num = start_sector; num <= end_sector; num++) { + unsigned long address = num * flash.sector_size; + + /* XXX: should add an optimization when spanning sectors: + * No point in reading in a sector if we're going to be + * clobbering the whole thing. Need to also add a test + * case to make sure the optimization is correct. + */ + if (read_flash(address, flash.sector_size, temp)) { + puts("Read sector failed! "); + len = 0; + break; + } + + start_byte = max(address, offset); + end_byte = address + flash.sector_size - 1; + if (end_byte > (offset + len)) + end_byte = (offset + len - 1); + + memcpy(temp + start_byte - address, + buffer + start_byte - offset, + end_byte - start_byte + 1); + + if (erase_sector(address)) { + puts("Erase sector failed! "); + goto out; + } + + if (write_sector(address, flash.sector_size, temp)) { + puts("Write sector failed! "); + goto out; + } + + puts("."); + } + + ret = len; + + out: + free(temp); + + SPI_DEINIT(); + + return ret; +} + +/* + * Function: spi_read + */ +ssize_t spi_read(uchar *addr, int alen, uchar *buffer, int len) +{ + unsigned long offset; + + SPI_INIT(); + + if (spi_detect_part()) + len = 0; + else { + offset = addr[0] << 16 | addr[1] << 8 | addr[2]; + read_flash(offset, len, buffer); + } + + SPI_DEINIT(); + + return len; +} + +/* + * Spit out some useful information about the SPI eeprom + */ +int eeprom_info(void) +{ + int ret = 0; + + SPI_INIT(); + + if (spi_detect_part()) + ret = 1; + else + printf("SPI Device: %s 0x%02X (%s) 0x%02X 0x%02X\n" + "Parameters: num sectors = %i, sector size = %i, write size = %i\n" + "Flash Size: %i mbit (%i mbyte)\n" + "Status: 0x%02X\n", + flash.flash->name, flash.manufacturer_id, flash.manufacturer->name, + flash.device_id1, flash.device_id2, flash.num_sectors, + flash.sector_size, flash.write_length, + (flash.num_sectors * flash.sector_size) >> 17, + (flash.num_sectors * flash.sector_size) >> 20, + read_status_register()); + + SPI_DEINIT(); + + return ret; +} + +#endif diff --git a/board/bf537-stamp/stm_m25p64.c b/board/bf537-stamp/stm_m25p64.c deleted file mode 100644 index c48c3c7c7e..0000000000 --- a/board/bf537-stamp/stm_m25p64.c +++ /dev/null @@ -1,516 +0,0 @@ -/**************************************************************************** - * SPI flash driver for M25P64 - ****************************************************************************/ -#include <common.h> -#include <linux/ctype.h> -#include <asm/io.h> -#include <asm/mach-common/bits/spi.h> - -#if defined(CONFIG_SPI) - -/* Application definitions */ - -#define NUM_SECTORS 128 /* number of sectors */ -#define SECTOR_SIZE 0x10000 -#define NOP_NUM 1000 - -#define COMMON_SPI_SETTINGS (SPE|MSTR|CPHA|CPOL) /* Settings to the SPI_CTL */ -#define TIMOD01 (0x01) /* stes the SPI to work with core instructions */ - -/* Flash commands */ -#define SPI_WREN (0x06) /*Set Write Enable Latch */ -#define SPI_WRDI (0x04) /*Reset Write Enable Latch */ -#define SPI_RDSR (0x05) /*Read Status Register */ -#define SPI_WRSR (0x01) /*Write Status Register */ -#define SPI_READ (0x03) /*Read data from memory */ -#define SPI_FAST_READ (0x0B) /*Read data from memory */ -#define SPI_PP (0x02) /*Program Data into memory */ -#define SPI_SE (0xD8) /*Erase one sector in memory */ -#define SPI_BE (0xC7) /*Erase all memory */ -#define WIP (0x1) /*Check the write in progress bit of the SPI status register */ -#define WEL (0x2) /*Check the write enable bit of the SPI status register */ - -#define TIMEOUT 350000000 - -typedef enum { - NO_ERR, - POLL_TIMEOUT, - INVALID_SECTOR, - INVALID_BLOCK, -} ERROR_CODE; - -void spi_init_f(void); -void spi_init_r(void); -ssize_t spi_read(uchar *, int, uchar *, int); -ssize_t spi_write(uchar *, int, uchar *, int); - -char ReadStatusRegister(void); -void Wait_For_SPIF(void); -void SetupSPI(const int spi_setting); -void SPI_OFF(void); -void SendSingleCommand(const int iCommand); - -ERROR_CODE GetSectorNumber(unsigned long ulOffset, int *pnSector); -ERROR_CODE EraseBlock(int nBlock); -ERROR_CODE ReadData(unsigned long ulStart, long lCount, int *pnData); -ERROR_CODE WriteData(unsigned long ulStart, long lCount, int *pnData); -ERROR_CODE Wait_For_Status(char Statusbit); -ERROR_CODE Wait_For_WEL(void); - -/* - * Function: spi_init_f - * Description: Init SPI-Controller (ROM part) - * return: --- - */ -void spi_init_f(void) -{ -} - -/* - * Function: spi_init_r - * Description: Init SPI-Controller (RAM part) - - * The malloc engine is ready and we can move our buffers to - * normal RAM - * return: --- - */ -void spi_init_r(void) -{ - return; -} - -/* - * Function: spi_write - */ -ssize_t spi_write(uchar * addr, int alen, uchar * buffer, int len) -{ - unsigned long offset; - int start_block, end_block; - int start_byte, end_byte; - ERROR_CODE result = NO_ERR; - uchar temp[SECTOR_SIZE]; - int i, num; - - offset = addr[0] << 16 | addr[1] << 8 | addr[2]; - /* Get the start block number */ - result = GetSectorNumber(offset, &start_block); - if (result == INVALID_SECTOR) { - printf("Invalid sector! "); - return 0; - } - /* Get the end block number */ - result = GetSectorNumber(offset + len - 1, &end_block); - if (result == INVALID_SECTOR) { - printf("Invalid sector! "); - return 0; - } - - for (num = start_block; num <= end_block; num++) { - ReadData(num * SECTOR_SIZE, SECTOR_SIZE, (int *)temp); - start_byte = num * SECTOR_SIZE; - end_byte = (num + 1) * SECTOR_SIZE - 1; - if (start_byte < offset) - start_byte = offset; - if (end_byte > (offset + len)) - end_byte = (offset + len - 1); - for (i = start_byte; i <= end_byte; i++) - temp[i - num * SECTOR_SIZE] = buffer[i - offset]; - EraseBlock(num); - result = WriteData(num * SECTOR_SIZE, SECTOR_SIZE, (int *)temp); - if (result != NO_ERR) - return 0; - printf("."); - } - return len; -} - -/* - * Function: spi_read - */ -ssize_t spi_read(uchar * addr, int alen, uchar * buffer, int len) -{ - unsigned long offset; - offset = addr[0] << 16 | addr[1] << 8 | addr[2]; - ReadData(offset, len, (int *)buffer); - return len; -} - -void SendSingleCommand(const int iCommand) -{ - unsigned short dummy; - - /* turns on the SPI in single write mode */ - SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); - - /* sends the actual command to the SPI TX register */ - *pSPI_TDBR = iCommand; - SSYNC(); - - /* The SPI status register will be polled to check the SPIF bit */ - Wait_For_SPIF(); - - dummy = *pSPI_RDBR; - - /* The SPI will be turned off */ - SPI_OFF(); - -} - -void SetupSPI(const int spi_setting) -{ - - if (icache_status() || dcache_status()) - udelay(CONFIG_CCLK_HZ / 50000000); - /*sets up the PF10 to be the slave select of the SPI */ - *pPORTF_FER |= (PF10 | PF11 | PF12 | PF13); - *pSPI_FLG = 0xFF02; - *pSPI_BAUD = CONFIG_SPI_BAUD; - *pSPI_CTL = spi_setting; - SSYNC(); - - *pSPI_FLG = 0xFD02; - SSYNC(); -} - -void SPI_OFF(void) -{ - - *pSPI_CTL = 0x0400; /* disable SPI */ - *pSPI_FLG = 0; - *pSPI_BAUD = 0; - SSYNC(); - udelay(CONFIG_CCLK_HZ / 50000000); - -} - -void Wait_For_SPIF(void) -{ - unsigned short dummyread; - while ((*pSPI_STAT & TXS)) ; - while (!(*pSPI_STAT & SPIF)) ; - while (!(*pSPI_STAT & RXS)) ; - /* Read dummy to empty the receive register */ - dummyread = *pSPI_RDBR; -} - -ERROR_CODE Wait_For_WEL(void) -{ - int i; - char status_register = 0; - ERROR_CODE ErrorCode = NO_ERR; - - for (i = 0; i < TIMEOUT; i++) { - status_register = ReadStatusRegister(); - if ((status_register & WEL)) { - ErrorCode = NO_ERR; - break; - } - ErrorCode = POLL_TIMEOUT; /* Time out error */ - }; - - return ErrorCode; -} - -ERROR_CODE Wait_For_Status(char Statusbit) -{ - int i; - char status_register = 0xFF; - ERROR_CODE ErrorCode = NO_ERR; - - for (i = 0; i < TIMEOUT; i++) { - status_register = ReadStatusRegister(); - if (!(status_register & Statusbit)) { - ErrorCode = NO_ERR; - break; - } - ErrorCode = POLL_TIMEOUT; /* Time out error */ - }; - - return ErrorCode; -} - -char ReadStatusRegister(void) -{ - char status_register = 0; - - SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); /* Turn on the SPI */ - - *pSPI_TDBR = SPI_RDSR; /* send instruction to read status register */ - SSYNC(); - Wait_For_SPIF(); /*wait until the instruction has been sent */ - *pSPI_TDBR = 0; /*send dummy to receive the status register */ - SSYNC(); - Wait_For_SPIF(); /*wait until the data has been sent */ - status_register = *pSPI_RDBR; /*read the status register */ - - SPI_OFF(); /* Turn off the SPI */ - - return status_register; -} - -ERROR_CODE GetSectorNumber(unsigned long ulOffset, int *pnSector) -{ - int nSector = 0; - ERROR_CODE ErrorCode = NO_ERR; - - if (ulOffset > (NUM_SECTORS * 0x10000 - 1)) { - ErrorCode = INVALID_SECTOR; - return ErrorCode; - } - - nSector = (int)ulOffset / 0x10000; - *pnSector = nSector; - - return ErrorCode; -} - -ERROR_CODE EraseBlock(int nBlock) -{ - unsigned long ulSectorOff = 0x0, ShiftValue; - ERROR_CODE ErrorCode = NO_ERR; - - /* if the block is invalid just return */ - if ((nBlock < 0) || (nBlock > NUM_SECTORS)) { - ErrorCode = INVALID_BLOCK; - return ErrorCode; - } - /* figure out the offset of the block in flash */ - if ((nBlock >= 0) && (nBlock < NUM_SECTORS)) { - ulSectorOff = (nBlock * SECTOR_SIZE); - - } else { - ErrorCode = INVALID_BLOCK; - return ErrorCode; - } - - /* A write enable instruction must previously have been executed */ - SendSingleCommand(SPI_WREN); - - /* The status register will be polled to check the write enable latch "WREN" */ - ErrorCode = Wait_For_WEL(); - - if (POLL_TIMEOUT == ErrorCode) { - printf("SPI Erase block error\n"); - return ErrorCode; - } else - - /* Turn on the SPI to send single commands */ - SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); - - /* - * Send the erase block command to the flash followed by the 24 address - * to point to the start of a sector - */ - *pSPI_TDBR = SPI_SE; - SSYNC(); - Wait_For_SPIF(); - /* Send the highest byte of the 24 bit address at first */ - ShiftValue = (ulSectorOff >> 16); - *pSPI_TDBR = ShiftValue; - SSYNC(); - /* Wait until the instruction has been sent */ - Wait_For_SPIF(); - /* Send the middle byte of the 24 bit address at second */ - ShiftValue = (ulSectorOff >> 8); - *pSPI_TDBR = ShiftValue; - SSYNC(); - /* Wait until the instruction has been sent */ - Wait_For_SPIF(); - /* Send the lowest byte of the 24 bit address finally */ - *pSPI_TDBR = ulSectorOff; - SSYNC(); - /* Wait until the instruction has been sent */ - Wait_For_SPIF(); - - /* Turns off the SPI */ - SPI_OFF(); - - /* Poll the status register to check the Write in Progress bit */ - /* Sector erase takes time */ - ErrorCode = Wait_For_Status(WIP); - - /* block erase should be complete */ - return ErrorCode; -} - -/* - * ERROR_CODE ReadData() - * 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 - */ -ERROR_CODE ReadData(unsigned long ulStart, long lCount, int *pnData) -{ - unsigned long ShiftValue; - char *cnData; - int i; - - /* Pointer cast to be able to increment byte wise */ - - cnData = (char *)pnData; - /* Start SPI interface */ - SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); - -#ifdef CONFIG_SPI_FLASH_FAST_READ - /* Send the read command to SPI device */ - *pSPI_TDBR = SPI_FAST_READ; -#else - /* Send the read command to SPI device */ - *pSPI_TDBR = SPI_READ; -#endif - SSYNC(); - /* Wait until the instruction has been sent */ - Wait_For_SPIF(); - /* Send the highest byte of the 24 bit address at first */ - ShiftValue = (ulStart >> 16); - /* Send the byte to the SPI device */ - *pSPI_TDBR = ShiftValue; - SSYNC(); - /* Wait until the instruction has been sent */ - Wait_For_SPIF(); - /* Send the middle byte of the 24 bit address at second */ - ShiftValue = (ulStart >> 8); - /* Send the byte to the SPI device */ - *pSPI_TDBR = ShiftValue; - SSYNC(); - /* Wait until the instruction has been sent */ - Wait_For_SPIF(); - /* Send the lowest byte of the 24 bit address finally */ - *pSPI_TDBR = ulStart; - SSYNC(); - /* Wait until the instruction has been sent */ - Wait_For_SPIF(); - -#ifdef CONFIG_SPI_FLASH_FAST_READ - /* Send dummy for FAST_READ */ - *pSPI_TDBR = 0; - SSYNC(); - /* Wait until the instruction has been sent */ - Wait_For_SPIF(); -#endif - - /* After the SPI device address has been placed on the MOSI pin the data can be */ - /* received on the MISO pin. */ - for (i = 0; i < lCount; i++) { - *pSPI_TDBR = 0; - SSYNC(); - while (!(*pSPI_STAT & RXS)) ; - *cnData++ = *pSPI_RDBR; - - if ((i >= SECTOR_SIZE) && (i % SECTOR_SIZE == 0)) - printf("."); - } - - /* Turn off the SPI */ - SPI_OFF(); - - return NO_ERR; -} - -ERROR_CODE WriteFlash(unsigned long ulStartAddr, long lTransferCount, - int *iDataSource, long *lWriteCount) -{ - - unsigned long ulWAddr; - long lWTransferCount = 0; - int i; - char iData; - char *temp = (char *)iDataSource; - ERROR_CODE ErrorCode = NO_ERR; - - /* First, a Write Enable Command must be sent to the SPI. */ - SendSingleCommand(SPI_WREN); - - /* - * Second, the SPI Status Register will be tested whether the - * Write Enable Bit has been set - */ - ErrorCode = Wait_For_WEL(); - if (POLL_TIMEOUT == ErrorCode) { - printf("SPI Write Time Out\n"); - return ErrorCode; - } else - /* Third, the 24 bit address will be shifted out - * the SPI MOSI bytewise. - * Turns the SPI on - */ - SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); - *pSPI_TDBR = SPI_PP; - SSYNC(); - /*wait until the instruction has been sent */ - Wait_For_SPIF(); - ulWAddr = (ulStartAddr >> 16); - *pSPI_TDBR = ulWAddr; - SSYNC(); - /*wait until the instruction has been sent */ - Wait_For_SPIF(); - ulWAddr = (ulStartAddr >> 8); - *pSPI_TDBR = ulWAddr; - SSYNC(); - /*wait until the instruction has been sent */ - Wait_For_SPIF(); - ulWAddr = ulStartAddr; - *pSPI_TDBR = ulWAddr; - SSYNC(); - /*wait until the instruction has been sent */ - Wait_For_SPIF(); - /* - * Fourth, maximum number of 256 bytes will be taken from the Buffer - * and sent to the SPI device. - */ - for (i = 0; (i < lTransferCount) && (i < 256); i++, lWTransferCount++) { - iData = *temp; - *pSPI_TDBR = iData; - SSYNC(); - /*wait until the instruction has been sent */ - Wait_For_SPIF(); - temp++; - } - - /* Turns the SPI off */ - SPI_OFF(); - - /* - * Sixth, the SPI Write in Progress Bit must be toggled to ensure the - * programming is done before start of next transfer - */ - ErrorCode = Wait_For_Status(WIP); - - if (POLL_TIMEOUT == ErrorCode) { - printf("SPI Program Time out!\n"); - return ErrorCode; - } else - - *lWriteCount = lWTransferCount; - - return ErrorCode; -} - -ERROR_CODE WriteData(unsigned long ulStart, long lCount, int *pnData) -{ - - unsigned long ulWStart = ulStart; - long lWCount = lCount, lWriteCount; - long *pnWriteCount = &lWriteCount; - - ERROR_CODE ErrorCode = NO_ERR; - - while (lWCount != 0) { - ErrorCode = WriteFlash(ulWStart, lWCount, pnData, pnWriteCount); - - /* - * After each function call of WriteFlash the counter - * must be adjusted - */ - lWCount -= *pnWriteCount; - - /* Also, both address pointers must be recalculated. */ - ulWStart += *pnWriteCount; - pnData += *pnWriteCount / 4; - } - - /* return the appropriate error code */ - return ErrorCode; -} - -#endif /* CONFIG_SPI */ |