/* * 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 #include #include #include /* 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 & CONFIG_SYS_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