From: Siva Durga Prasad Paladugu Date: Fri, 29 Nov 2013 06:33:16 +0000 (+0530) Subject: sf: Merge quad, dual stacked and dual parallel changes X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b1db703dc71fef1f171d4de61e62ee706837401d;p=thirdparty%2Fu-boot.git sf: Merge quad, dual stacked and dual parallel changes Merged the quad, dual stacked and dual parallel changes into the new spi framework of v2013.10. Tested the changes on zc702, zc706. Also, tested on zc706 with Micron device as well. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- diff --git a/drivers/mtd/spi/sf.c b/drivers/mtd/spi/sf.c index d5e175ca000..a4a61114b73 100644 --- a/drivers/mtd/spi/sf.c +++ b/drivers/mtd/spi/sf.c @@ -9,6 +9,7 @@ #include #include +#include static int spi_flash_read_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, @@ -18,6 +19,8 @@ static int spi_flash_read_write(struct spi_slave *spi, unsigned long flags = SPI_XFER_BEGIN; int ret; + if ((spi->is_dual == MODE_DUAL_STACKED) && (spi->u_page == 1)) + flags |= SPI_FLASH_U_PAGE; if (data_len == 0) flags |= SPI_XFER_END; diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 6439d6acd02..e763c670203 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -17,6 +17,10 @@ #define SECT_32K (1 << 2) #define E_FSR (1 << 3) +/* QUAD flags */ +#define WR_QPP (1 << 4) +#define RD_QR (1 << 5) + /* Erase commands */ #define CMD_ERASE_4K 0x20 #define CMD_ERASE_32K 0x52 @@ -117,9 +121,6 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); /* Program the status register */ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); -/* Set quad enbale bit */ -int spi_flash_set_qeb(struct spi_flash *flash); - /* Enable writing on the SPI flash */ static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) { @@ -132,17 +133,6 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash) return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0); } -/* Program the status register. */ -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); - -/* Program the config register */ -int spi_flash_cmd_write_config(struct spi_flash *flash, u8 cr); - -#ifdef CONFIG_SPI_FLASH_BAR -/* Configure the BAR - discover the bank cmds */ -int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0); -#endif - /* * Send the read status command to the device and wait for the wip * (write-in-progress) bit to clear itself. diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 108665f4415..a51702fe05b 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -64,9 +64,19 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset) { u8 bank_sel; int ret; + int is_dual = flash->spi->is_dual; + if (is_dual == MODE_DUAL_STACKED) { + if (offset >= (flash->size / 2)) + flash->spi->u_page = 1; + else + flash->spi->u_page = 0; + } bank_sel = offset / SPI_FLASH_16MB_BOUN; + if ((is_dual == MODE_DUAL_STACKED) && (flash->spi->u_page == 1)) + bank_sel -= ((flash->size / 2) / SPI_FLASH_16MB_BOUN); + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); if (ret) { debug("SF: fail to set bank%d\n", bank_sel); @@ -165,9 +175,10 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) { - u32 erase_size; + u32 erase_size, erase_addr; u8 cmd[4]; int ret = -1; + int is_dual = flash->spi->is_dual; erase_size = flash->erase_size; if (offset % erase_size || len % erase_size) { @@ -177,15 +188,19 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) cmd[0] = flash->erase_cmd; while (len) { + erase_addr = offset; + if (is_dual == MODE_DUAL_PARALLEL) + erase_addr /= 2; + #ifdef CONFIG_SPI_FLASH_BAR - ret = spi_flash_bank(flash, offset); + ret = spi_flash_bank(flash, erase_addr); if (ret < 0) return ret; #endif - spi_flash_addr(offset, cmd); + spi_flash_addr(erase_addr, cmd); debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], - cmd[2], cmd[3], offset); + cmd[2], cmd[3], erase_addr); ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); if (ret < 0) { @@ -203,17 +218,21 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, size_t len, const void *buf) { - unsigned long byte_addr, page_size; + unsigned long byte_addr, page_size, write_addr; size_t chunk_len, actual; u8 cmd[4]; int ret = -1; + int is_dual = flash->spi->is_dual; page_size = flash->page_size; - cmd[0] = CMD_PAGE_PROGRAM; + cmd[0] = flash->write_cmd; for (actual = 0; actual < len; actual += chunk_len) { + write_addr = offset; + if (is_dual == MODE_DUAL_PARALLEL) + write_addr /= 2; #ifdef CONFIG_SPI_FLASH_BAR - ret = spi_flash_bank(flash, offset); + ret = spi_flash_bank(flash, write_addr); if (ret < 0) return ret; #endif @@ -223,7 +242,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, if (flash->spi->max_write_size) chunk_len = min(chunk_len, flash->spi->max_write_size); - spi_flash_addr(offset, cmd); + spi_flash_addr(write_addr, cmd); debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); @@ -268,37 +287,53 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data) { u8 cmd[5], bank_sel = 0; - u32 remain_len, read_len; + u32 remain_len, read_len, read_addr, bank_boun; int ret = -1; + int is_dual = flash->spi->is_dual; /* Handle memory-mapped SPI */ if (flash->memory_map) { - spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP); memcpy(data, flash->memory_map + offset, len); - spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END); return 0; } - cmd[0] = CMD_READ_ARRAY_FAST; + bank_boun = SPI_FLASH_16MB_BOUN; + if (is_dual == MODE_DUAL_PARALLEL) + bank_boun = SPI_FLASH_16MB_BOUN << 1; + + cmd[0] = flash->read_cmd; cmd[4] = 0x00; while (len) { + read_addr = offset; + if (is_dual == MODE_DUAL_PARALLEL) + read_addr /= 2; + if (is_dual == MODE_DUAL_STACKED) { + if (read_addr >= (flash->size / 2)) + flash->spi->u_page = 1; + else + flash->spi->u_page = 0; + } #ifdef CONFIG_SPI_FLASH_BAR - bank_sel = offset / SPI_FLASH_16MB_BOUN; + bank_sel = read_addr / SPI_FLASH_16MB_BOUN; + if ((is_dual == MODE_DUAL_STACKED) && (flash->spi->u_page == 1)) + bank_sel -= ((flash->size / 2) / bank_boun); ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); if (ret) { debug("SF: fail to set bank%d\n", bank_sel); return ret; } + if ((is_dual == MODE_DUAL_STACKED) && (flash->spi->u_page == 1)) + bank_sel += ((flash->size / 2) / bank_boun); #endif - remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset; + remain_len = (bank_boun * (bank_sel + 1)) - offset; if (len < remain_len) read_len = len; else read_len = remain_len; - spi_flash_addr(offset, cmd); + spi_flash_addr(read_addr, cmd); ret = spi_flash_read_common(flash, cmd, sizeof(cmd), data, read_len); diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 5eb8ffe843e..2fa2a39214d 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -39,104 +39,128 @@ struct spi_flash_params { static const struct spi_flash_params spi_flash_params_table[] = { #ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ - {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, SECT_4K}, - {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, SECT_4K}, - {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, SECT_4K}, - {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, SECT_4K}, - {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, SECT_4K}, - {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, SECT_4K}, - {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, SECT_4K}, - {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, SECT_4K}, + {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, SECT_4K}, + {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, SECT_4K}, + {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, SECT_4K}, + {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, SECT_4K}, + {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, SECT_4K}, + {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, SECT_4K}, + {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, SECT_4K}, + {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_EON /* EON */ - {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, - {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, SECT_4K}, - {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, - {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0}, + {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, + {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, SECT_4K}, + {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, + {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0}, #endif #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ - {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, SECT_4K}, - {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, SECT_4K}, + {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, SECT_4K}, + {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ - {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0}, - {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0}, - {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0}, - {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0}, - {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, - {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, - {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0}, - {"MX25L51235F", 0xc2201A, 0x0, 64 * 1024, 1024, 0}, - {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, + {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0}, + {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0}, + {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0}, + {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0}, + {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, + {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, + {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0}, + {"MX25L51235F", 0xc2201A, 0x0, 64 * 1024, 1024, 0}, + {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, #endif #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ - {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0}, - {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0}, - {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0}, - {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0}, - {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0}, - {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0}, - {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0}, - {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0}, - {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0}, - {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, 0}, - {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, 0}, - {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, 0}, - {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0}, + {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0}, + {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0}, + {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0}, + {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0}, + {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0}, + {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0}, + {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0}, + {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0}, + {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, RD_QR | WR_QPP}, + {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, RD_QR | WR_QPP}, + {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_QR | WR_QPP}, + {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, RD_QR | WR_QPP}, + {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, RD_QR | WR_QPP}, #endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0}, - {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0}, - {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0}, - {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0}, - {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0}, - {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0}, - {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0}, - {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0}, - {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, SECT_4K}, - {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, SECT_4K}, - {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, SECT_4K}, - {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, SECT_4K}, - {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, SECT_4K}, - {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, SECT_4K}, - {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, SECT_4K}, - {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, SECT_4K}, - {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K}, - {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K}, - {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K}, - {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K}, + {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0}, + {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0}, + {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0}, + {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0}, + {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0}, + {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0}, + {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0}, + {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0}, + {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, RD_QR | WR_QPP | + SECT_4K}, + {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, RD_QR | WR_QPP | + SECT_4K}, + {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, SECT_4K}, + {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, SECT_4K}, + {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, RD_QR | WR_QPP | + SECT_4K}, + {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, RD_QR | WR_QPP | + SECT_4K}, + {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, RD_QR | WR_QPP | + SECT_4K}, + {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, RD_QR | WR_QPP | + SECT_4K}, + {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, RD_QR | WR_QPP | + E_FSR | SECT_4K}, + {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, RD_QR | WR_QPP | + E_FSR | SECT_4K}, + {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, RD_QR | WR_QPP | + E_FSR | SECT_4K}, + {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, RD_QR | WR_QPP | + E_FSR | SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ - {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, - {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | SST_WP}, - {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | SST_WP}, - {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | SST_WP}, - {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, SECT_4K}, - {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | SST_WP}, - {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | SST_WP}, - {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | SST_WP}, - {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, - {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WP}, + {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | + SST_WP}, + {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | + SST_WP}, + {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | + SST_WP}, + {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | + SST_WP}, + {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, SECT_4K}, + {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | + SST_WP}, + {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | + SST_WP}, + {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | + SST_WP}, + {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | + SST_WP}, + {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | + SST_WP}, #endif #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ - {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0}, - {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0}, - {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0}, - {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, SECT_4K}, - {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, SECT_4K}, - {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, SECT_4K}, - {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, SECT_4K}, - {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, SECT_4K}, - {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, SECT_4K}, - {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, SECT_4K}, - {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, SECT_4K}, - {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, SECT_4K}, - {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, SECT_4K}, - {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, SECT_4K}, - {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, SECT_4K}, - {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, SECT_4K}, - {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, SECT_4K}, - {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, SECT_4K}, + {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0}, + {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0}, + {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0}, + {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, SECT_4K}, + {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, SECT_4K}, + {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, SECT_4K}, + {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, SECT_4K}, + {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, SECT_4K}, + {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, SECT_4K}, + {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, SECT_4K}, + {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, RD_QR | WR_QPP | + SECT_4K}, + {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, RD_QR | WR_QPP | + SECT_4K}, + {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, RD_QR | WR_QPP | + SECT_4K}, + {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, SECT_4K}, + {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, SECT_4K}, + {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, SECT_4K}, + {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, RD_QR | WR_QPP | + SECT_4K}, + {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, RD_QR | WR_QPP | + SECT_4K}, #endif /* * Note: @@ -159,6 +183,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, const struct spi_flash_params *params; struct spi_flash *flash; int i; + u8 qeb_status, cmd, data[2]; u16 jedec = idcode[1] << 8 | idcode[2]; u16 ext_jedec = idcode[3] << 8 | idcode[4]; @@ -206,8 +231,16 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, /* Compute the flash size */ flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; flash->sector_size = params->sector_size; + if (flash->spi->is_dual == MODE_DUAL_PARALLEL) { + flash->page_size *= 2; + flash->sector_size *= 2; + } + flash->size = flash->sector_size * params->nr_sectors; + if (flash->spi->is_dual == MODE_DUAL_STACKED) + flash->size *= 2; + /* Compute erase sector and command */ if (params->flags & SECT_4K) { flash->erase_cmd = CMD_ERASE_4K; @@ -227,6 +260,14 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, flash->poll_cmd = CMD_FLAG_STATUS; #endif + flash->read_cmd = CMD_READ_ARRAY_FAST; + if (params->flags & RD_QR) + flash->read_cmd = CMD_READ_QUAD_OUTPUT_FAST; + + flash->write_cmd = CMD_PAGE_PROGRAM; + if (params->flags & WR_QPP) + flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; + /* Configure the BAR - discover bank cmds and read current bank */ #ifdef CONFIG_SPI_FLASH_BAR u8 curr_bank = 0; @@ -247,6 +288,33 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, } #endif + if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || + (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { + cmd = CMD_READ_CONFIG; + if (spi_flash_read_common(flash, &cmd, 1, &qeb_status, 1)) { + debug("SF: fail to read config register\n"); + return NULL; + } + if (qeb_status & STATUS_QEB) { + debug("SF: qeb is already set\n"); + } else { + cmd = CMD_READ_STATUS; + if (spi_flash_read_common(flash, &cmd, + 1, &data[0], 1)) { + debug("SF: fail to read status register\n"); + return NULL; + } else { + cmd = CMD_WRITE_STATUS; + data[1] = STATUS_QEB; + if (spi_flash_write_common(flash, &cmd, + 1, &data, 2)) { + debug("SF: fail write conf register\n"); + return NULL; + } + } + } + } + /* Flash powers up read-only, so clear BP# bits */ #if defined(CONFIG_SPI_FLASH_ATMEL) || \ defined(CONFIG_SPI_FLASH_MACRONIX) || \