summaryrefslogtreecommitdiff
path: root/board/bf537-stamp
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2008-02-19 00:58:13 -0500
committerMike Frysinger <vapier@gentoo.org>2008-03-30 15:13:42 -0400
commit9ce7e53abd039decea1af67aec81bbd5df7a2593 (patch)
tree107b16118720b894357b18a1db16ca690239d136 /board/bf537-stamp
parent74d1e66d22dac91388bc538b2fe19f735edc5b82 (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/Makefile2
-rw-r--r--board/bf537-stamp/spi_flash.c815
-rw-r--r--board/bf537-stamp/stm_m25p64.c516
3 files changed, 816 insertions, 517 deletions
diff --git a/board/bf537-stamp/Makefile b/board/bf537-stamp/Makefile
index 5d223933715..53261549720 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 00000000000..7c73ddd7208
--- /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 c48c3c7c7e2..00000000000
--- 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 */