diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/spi/eon.c | 35 | ||||
-rw-r--r-- | drivers/mtd/spi/macronix.c | 82 | ||||
-rw-r--r-- | drivers/mtd/spi/spansion.c | 24 | ||||
-rw-r--r-- | drivers/mtd/spi/spi_flash.c | 35 | ||||
-rw-r--r-- | drivers/mtd/spi/spi_flash_internal.h | 10 | ||||
-rw-r--r-- | drivers/mtd/spi/sst.c | 66 | ||||
-rw-r--r-- | drivers/mtd/spi/stmicro.c | 28 | ||||
-rw-r--r-- | drivers/mtd/spi/winbond.c | 55 | ||||
-rw-r--r-- | drivers/spi/Makefile | 2 | ||||
-rw-r--r-- | drivers/spi/xilinx_spi.c | 214 | ||||
-rw-r--r-- | drivers/spi/xilinx_spi.h | 135 |
11 files changed, 422 insertions, 264 deletions
diff --git a/drivers/mtd/spi/eon.c b/drivers/mtd/spi/eon.c index 6a3bf0f32..691ed4efc 100644 --- a/drivers/mtd/spi/eon.c +++ b/drivers/mtd/spi/eon.c @@ -10,15 +10,8 @@ #include "spi_flash_internal.h" -/* EN25Q128-specific commands */ -#define CMD_EN25Q128_SE 0x20 /* Sector Erase */ -#define CMD_EN25Q128_BE 0xd8 /* Block Erase */ - struct eon_spi_flash_params { u8 idcode1; - u16 page_size; - u16 pages_per_sector; - u16 sectors_per_block; u16 nr_sectors; const char *name; }; @@ -26,35 +19,16 @@ struct eon_spi_flash_params { static const struct eon_spi_flash_params eon_spi_flash_table[] = { { .idcode1 = 0x16, - .page_size = 256, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_sectors = 1024, .name = "EN25Q32B", }, { .idcode1 = 0x18, - .page_size = 256, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_sectors = 4096, .name = "EN25Q128", }, - { - .idcode1 = 0x16, - .page_size = 256, - .pages_per_sector = 16, - .sectors_per_block = 16, - .nr_sectors = 1024, - .name = "EN25Q32B", - }, }; -static int eon_erase(struct spi_flash *flash, u32 offset, size_t len) -{ - return spi_flash_cmd_erase(flash, CMD_EN25Q128_BE, offset, len); -} - struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode) { const struct eon_spi_flash_params *params; @@ -82,12 +56,11 @@ struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode) flash->name = params->name; flash->write = spi_flash_cmd_write_multi; - flash->erase = eon_erase; + flash->erase = spi_flash_cmd_erase; flash->read = spi_flash_cmd_read_fast; - flash->page_size = params->page_size; - flash->sector_size = params->page_size * params->pages_per_sector - * params->sectors_per_block; - flash->size = params->page_size * params->pages_per_sector + flash->page_size = 256; + flash->sector_size = 256 * 16 * 16; + flash->size = 256 * 16 * params->nr_sectors; return flash; diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c index 87a3ad0c3..c97a39d49 100644 --- a/drivers/mtd/spi/macronix.c +++ b/drivers/mtd/spi/macronix.c @@ -35,16 +35,8 @@ #include "spi_flash_internal.h" -/* MX25xx-specific commands */ -#define CMD_MX25XX_SE 0x20 /* Sector Erase */ -#define CMD_MX25XX_BE 0xD8 /* Block Erase */ -#define CMD_MX25XX_CE 0xc7 /* Chip Erase */ - struct macronix_spi_flash_params { u16 idcode; - u16 page_size; - u16 pages_per_sector; - u16 sectors_per_block; u16 nr_blocks; const char *name; }; @@ -52,106 +44,41 @@ struct macronix_spi_flash_params { static const struct macronix_spi_flash_params macronix_spi_flash_table[] = { { .idcode = 0x2013, - .page_size = 256, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 8, .name = "MX25L4005", }, { .idcode = 0x2014, - .page_size = 256, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 16, .name = "MX25L8005", }, { .idcode = 0x2015, - .page_size = 256, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 32, .name = "MX25L1605D", }, { .idcode = 0x2016, - .page_size = 256, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 64, .name = "MX25L3205D", }, { .idcode = 0x2017, - .page_size = 256, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 128, .name = "MX25L6405D", }, { .idcode = 0x2018, - .page_size = 256, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 256, .name = "MX25L12805D", }, { .idcode = 0x2618, - .page_size = 256, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 256, .name = "MX25L12855E", }, }; -static int macronix_write_status(struct spi_flash *flash, u8 sr) -{ - u8 cmd; - int ret; - - ret = spi_flash_cmd_write_enable(flash); - if (ret < 0) { - debug("SF: enabling write failed\n"); - return ret; - } - - cmd = CMD_WRITE_STATUS; - ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &sr, 1); - if (ret) { - debug("SF: fail to write status register\n"); - return ret; - } - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret < 0) { - debug("SF: write status register timed out\n"); - return ret; - } - - return 0; -} - -static int macronix_unlock(struct spi_flash *flash) -{ - int ret; - - /* Enable status register writing and clear BP# bits */ - ret = macronix_write_status(flash, 0); - if (ret) - debug("SF: fail to disable write protection\n"); - - return ret; -} - -static int macronix_erase(struct spi_flash *flash, u32 offset, size_t len) -{ - return spi_flash_cmd_erase(flash, CMD_MX25XX_BE, offset, len); -} - struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) { const struct macronix_spi_flash_params *params; @@ -180,15 +107,14 @@ struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) flash->name = params->name; flash->write = spi_flash_cmd_write_multi; - flash->erase = macronix_erase; + flash->erase = spi_flash_cmd_erase; flash->read = spi_flash_cmd_read_fast; - flash->page_size = params->page_size; - flash->sector_size = params->page_size * params->pages_per_sector - * params->sectors_per_block; + flash->page_size = 256; + flash->sector_size = 256 * 16 * 16; flash->size = flash->sector_size * params->nr_blocks; /* Clear BP# bits for read-only flash */ - macronix_unlock(flash); + spi_flash_cmd_write_status(flash, 0); return flash; } diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index 457cc0629..9a114ac6a 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -31,14 +31,9 @@ #include "spi_flash_internal.h" -/* S25FLxx-specific commands */ -#define CMD_S25FLXX_SE 0xd8 /* Sector Erase */ -#define CMD_S25FLXX_BE 0xc7 /* Bulk Erase */ - struct spansion_spi_flash_params { u16 idcode1; u16 idcode2; - u16 page_size; u16 pages_per_sector; u16 nr_sectors; const char *name; @@ -48,7 +43,6 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { { .idcode1 = 0x0213, .idcode2 = 0, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 16, .name = "S25FL008A", @@ -56,7 +50,6 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { { .idcode1 = 0x0214, .idcode2 = 0, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 32, .name = "S25FL016A", @@ -64,7 +57,6 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { { .idcode1 = 0x0215, .idcode2 = 0, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 64, .name = "S25FL032A", @@ -72,7 +64,6 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { { .idcode1 = 0x0216, .idcode2 = 0, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 128, .name = "S25FL064A", @@ -80,7 +71,6 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { { .idcode1 = 0x2018, .idcode2 = 0x0301, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 256, .name = "S25FL128P_64K", @@ -88,7 +78,6 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { { .idcode1 = 0x2018, .idcode2 = 0x0300, - .page_size = 256, .pages_per_sector = 1024, .nr_sectors = 64, .name = "S25FL128P_256K", @@ -96,7 +85,6 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { { .idcode1 = 0x0215, .idcode2 = 0x4d00, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 64, .name = "S25FL032P", @@ -104,18 +92,12 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { { .idcode1 = 0x2018, .idcode2 = 0x4d01, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 256, .name = "S25FL129P_64K", }, }; -static int spansion_erase(struct spi_flash *flash, u32 offset, size_t len) -{ - return spi_flash_cmd_erase(flash, CMD_S25FLXX_SE, offset, len); -} - struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) { const struct spansion_spi_flash_params *params; @@ -149,10 +131,10 @@ struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) flash->name = params->name; flash->write = spi_flash_cmd_write_multi; - flash->erase = spansion_erase; + flash->erase = spi_flash_cmd_erase; flash->read = spi_flash_cmd_read_fast; - flash->page_size = params->page_size; - flash->sector_size = params->page_size * params->pages_per_sector; + flash->page_size = 256; + flash->sector_size = 256 * params->pages_per_sector; flash->size = flash->sector_size * params->nr_sectors; return flash; diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index f689cc47c..00aece929 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -190,8 +190,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) CMD_READ_STATUS, STATUS_WIP); } -int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, - u32 offset, size_t len) +int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) { u32 start, end, erase_size; int ret; @@ -209,7 +208,10 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, return ret; } - cmd[0] = erase_cmd; + if (erase_size == 4096) + cmd[0] = CMD_ERASE_4K; + else + cmd[0] = CMD_ERASE_64K; start = offset; end = start + len; @@ -240,6 +242,33 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, return ret; } +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) +{ + u8 cmd; + int ret; + + ret = spi_flash_cmd_write_enable(flash); + if (ret < 0) { + debug("SF: enabling write failed\n"); + return ret; + } + + cmd = CMD_WRITE_STATUS; + ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &sr, 1); + if (ret) { + debug("SF: fail to write status register\n"); + return ret; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret < 0) { + debug("SF: write status register timed out\n"); + return ret; + } + + return 0; +} + /* * The following table holds all device probe functions * diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index 0c7824979..141cfa8b2 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -23,6 +23,10 @@ #define CMD_WRITE_DISABLE 0x04 #define CMD_READ_STATUS 0x05 #define CMD_WRITE_ENABLE 0x06 +#define CMD_ERASE_4K 0x20 +#define CMD_ERASE_32K 0x52 +#define CMD_ERASE_64K 0xd8 +#define CMD_ERASE_CHIP 0xc7 /* Common status */ #define STATUS_WIP 0x01 @@ -70,6 +74,9 @@ 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); + /* * Same as spi_flash_cmd_read() except it also claims/releases the SPI * bus. Used as common part of the ->read() operation. @@ -88,8 +95,7 @@ int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); /* Erase sectors. */ -int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, - u32 offset, size_t len); +int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len); /* Manufacturer-specific probe functions */ struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c index e51dfc7f2..ced4f2473 100644 --- a/drivers/mtd/spi/sst.c +++ b/drivers/mtd/spi/sst.c @@ -20,7 +20,6 @@ #define CMD_SST_BP 0x02 /* Byte Program */ #define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */ -#define CMD_SST_SE 0x20 /* Sector Erase */ #define SST_SR_WIP (1 << 0) /* Write-in-Progress */ #define SST_SR_WEL (1 << 1) /* Write enable */ @@ -45,13 +44,6 @@ struct sst_spi_flash { const struct sst_spi_flash_params *params; }; -static inline struct sst_spi_flash *to_sst_spi_flash(struct spi_flash *flash) -{ - return container_of(flash, struct sst_spi_flash, flash); -} - -#define SST_SECTOR_SIZE (4 * 1024) -#define SST_PAGE_SIZE 256 static const struct sst_spi_flash_params sst_spi_flash_table[] = { { .idcode1 = 0x8d, @@ -102,24 +94,6 @@ static const struct sst_spi_flash_params sst_spi_flash_table[] = { }; static int -sst_enable_writing(struct spi_flash *flash) -{ - int ret = spi_flash_cmd_write_enable(flash); - if (ret) - debug("SF: Enabling Write failed\n"); - return ret; -} - -static int -sst_disable_writing(struct spi_flash *flash) -{ - int ret = spi_flash_cmd_write_disable(flash); - if (ret) - debug("SF: Disabling Write failed\n"); - return ret; -} - -static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) { int ret; @@ -133,7 +107,7 @@ sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset); - ret = sst_enable_writing(flash); + ret = spi_flash_cmd_write_enable(flash); if (ret) return ret; @@ -166,7 +140,7 @@ sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, const void *buf) } offset += actual; - ret = sst_enable_writing(flash); + ret = spi_flash_cmd_write_enable(flash); if (ret) goto done; @@ -197,7 +171,7 @@ sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, const void *buf) } if (!ret) - ret = sst_disable_writing(flash); + ret = spi_flash_cmd_write_disable(flash); /* If there is a single trailing byte, write it out */ if (!ret && actual != len) @@ -211,32 +185,6 @@ sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, const void *buf) return ret; } -static int sst_erase(struct spi_flash *flash, u32 offset, size_t len) -{ - return spi_flash_cmd_erase(flash, CMD_SST_SE, offset, len); -} - -static int -sst_unlock(struct spi_flash *flash) -{ - int ret; - u8 cmd, status; - - ret = sst_enable_writing(flash); - if (ret) - return ret; - - cmd = CMD_WRITE_STATUS; - status = 0; - ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &status, 1); - if (ret) - debug("SF: Unable to set status byte\n"); - - debug("SF: sst: status = %x\n", spi_w8r8(flash->spi, CMD_READ_STATUS)); - - return ret; -} - struct spi_flash * spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) { @@ -269,14 +217,14 @@ spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) stm->flash.write = sst_write_wp; else stm->flash.write = spi_flash_cmd_write_multi; - stm->flash.erase = sst_erase; + stm->flash.erase = spi_flash_cmd_erase; stm->flash.read = spi_flash_cmd_read_fast; - stm->flash.page_size = SST_PAGE_SIZE; - stm->flash.sector_size = SST_SECTOR_SIZE; + stm->flash.page_size = 256; + stm->flash.sector_size = 4096; stm->flash.size = stm->flash.sector_size * params->nr_sectors; /* Flash powers up read-only, so clear BP# bits */ - sst_unlock(&stm->flash); + spi_flash_cmd_write_status(&stm->flash, 0); return &stm->flash; } diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index 5b684792d..dbd1fc185 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -34,13 +34,10 @@ #include "spi_flash_internal.h" /* M25Pxx-specific commands */ -#define CMD_M25PXX_SE 0xd8 /* Sector Erase */ -#define CMD_M25PXX_BE 0xc7 /* Bulk Erase */ #define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */ struct stmicro_spi_flash_params { u8 idcode1; - u16 page_size; u16 pages_per_sector; u16 nr_sectors; const char *name; @@ -49,67 +46,60 @@ struct stmicro_spi_flash_params { static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { { .idcode1 = 0x11, - .page_size = 256, .pages_per_sector = 128, .nr_sectors = 4, .name = "M25P10", }, { .idcode1 = 0x15, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 32, .name = "M25P16", }, { .idcode1 = 0x12, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 4, .name = "M25P20", }, { .idcode1 = 0x16, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 64, .name = "M25P32", }, { .idcode1 = 0x13, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 8, .name = "M25P40", }, { .idcode1 = 0x17, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 128, .name = "M25P64", }, { .idcode1 = 0x14, - .page_size = 256, .pages_per_sector = 256, .nr_sectors = 16, .name = "M25P80", }, { .idcode1 = 0x18, - .page_size = 256, .pages_per_sector = 1024, .nr_sectors = 64, .name = "M25P128", }, + { + .idcode1 = 0x19, + .pages_per_sector = 256, + .nr_sectors = 512, + .name = "N25Q256", + }, }; -static int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) -{ - return spi_flash_cmd_erase(flash, CMD_M25PXX_SE, offset, len); -} - struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) { const struct stmicro_spi_flash_params *params; @@ -151,10 +141,10 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) flash->name = params->name; flash->write = spi_flash_cmd_write_multi; - flash->erase = stmicro_erase; + flash->erase = spi_flash_cmd_erase; flash->read = spi_flash_cmd_read_fast; - flash->page_size = params->page_size; - flash->sector_size = params->page_size * params->pages_per_sector; + flash->page_size = 256; + flash->sector_size = 256 * params->pages_per_sector; flash->size = flash->sector_size * params->nr_sectors; return flash; diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index 0e126f40c..427b71fcd 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -10,17 +10,8 @@ #include "spi_flash_internal.h" -/* M25Pxx-specific commands */ -#define CMD_W25_SE 0x20 /* Sector (4K) Erase */ -#define CMD_W25_BE 0xd8 /* Block (64K) Erase */ -#define CMD_W25_CE 0xc7 /* Chip Erase */ - struct winbond_spi_flash_params { uint16_t id; - /* Log2 of page size in power-of-two mode */ - uint8_t l2_page_size; - uint16_t pages_per_sector; - uint16_t sectors_per_block; uint16_t nr_blocks; const char *name; }; @@ -28,89 +19,56 @@ struct winbond_spi_flash_params { static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { { .id = 0x3013, - .l2_page_size = 8, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 8, .name = "W25X40", }, { .id = 0x3015, - .l2_page_size = 8, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 32, .name = "W25X16", }, { .id = 0x3016, - .l2_page_size = 8, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 64, .name = "W25X32", }, { .id = 0x3017, - .l2_page_size = 8, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 128, .name = "W25X64", }, { .id = 0x4014, - .l2_page_size = 8, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 16, .name = "W25Q80BL", }, { .id = 0x4015, - .l2_page_size = 8, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 32, .name = "W25Q16", }, { .id = 0x4016, - .l2_page_size = 8, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 64, .name = "W25Q32", }, { .id = 0x4017, - .l2_page_size = 8, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 128, .name = "W25Q64", }, { .id = 0x4018, - .l2_page_size = 8, - .pages_per_sector = 16, - .sectors_per_block = 16, .nr_blocks = 256, .name = "W25Q128", }, }; -static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len) -{ - return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len); -} - struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) { const struct winbond_spi_flash_params *params; struct spi_flash *flash; unsigned int i; - unsigned page_size; for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) { params = &winbond_spi_flash_table[i]; @@ -133,17 +91,12 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) flash->spi = spi; flash->name = params->name; - /* Assuming power-of-two page size initially. */ - page_size = 1 << params->l2_page_size; - flash->write = spi_flash_cmd_write_multi; - flash->erase = winbond_erase; + flash->erase = spi_flash_cmd_erase; flash->read = spi_flash_cmd_read_fast; - flash->page_size = page_size; - flash->sector_size = page_size * params->pages_per_sector; - flash->size = page_size * params->pages_per_sector - * params->sectors_per_block - * params->nr_blocks; + flash->page_size = 4096; + flash->sector_size = 4096; + flash->size = 4096 * 16 * params->nr_blocks; return flash; } diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index c20f1f2da..cd3f9fa85 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -44,6 +44,8 @@ COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o COBJS-$(CONFIG_SH_SPI) += sh_spi.o COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o COBJS-$(CONFIG_TEGRA_SPI) += tegra_spi.o +COBJS-$(CONFIG_TEGRA2_SPI) += tegra2_spi.o +COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c new file mode 100644 index 000000000..e563c1905 --- /dev/null +++ b/drivers/spi/xilinx_spi.c @@ -0,0 +1,214 @@ +/* + * Xilinx SPI driver + * + * supports 8 bit SPI transfers only, with or w/o FIFO + * + * based on bfin_spi.c, by way of altera_spi.c + * Copyright (c) 2005-2008 Analog Devices Inc. + * Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw> + * Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca> + * Copyright (c) 2012 Stephan Linz <linz@li-pro.net> + * + * Licensed under the GPL-2 or later. + * + * [0]: http://www.xilinx.com/support/documentation + * + * [S]: [0]/ip_documentation/xps_spi.pdf + * [0]/ip_documentation/axi_spi_ds742.pdf + */ +#include <config.h> +#include <common.h> +#include <malloc.h> +#include <spi.h> + +#include "xilinx_spi.h" + +#ifndef CONFIG_SYS_XILINX_SPI_LIST +#define CONFIG_SYS_XILINX_SPI_LIST { CONFIG_SYS_SPI_BASE } +#endif + +#ifndef CONFIG_XILINX_SPI_IDLE_VAL +#define CONFIG_XILINX_SPI_IDLE_VAL 0xff +#endif + +#define XILSPI_SPICR_DFLT_ON (SPICR_MANUAL_SS | \ + SPICR_MASTER_MODE | \ + SPICR_SPE) + +#define XILSPI_SPICR_DFLT_OFF (SPICR_MASTER_INHIBIT | \ + SPICR_MANUAL_SS) + +#define XILSPI_MAX_XFER_BITS 8 + +static unsigned long xilinx_spi_base_list[] = CONFIG_SYS_XILINX_SPI_LIST; + +__attribute__((weak)) +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return bus < ARRAY_SIZE(xilinx_spi_base_list) && cs < 32; +} + +__attribute__((weak)) +void spi_cs_activate(struct spi_slave *slave) +{ + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave); + + writel(SPISSR_ACT(slave->cs), &xilspi->regs->spissr); +} + +__attribute__((weak)) +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave); + + writel(SPISSR_OFF, &xilspi->regs->spissr); +} + +void spi_init(void) +{ + /* do nothing */ +} + +void spi_set_speed(struct spi_slave *slave, uint hz) +{ + /* xilinx spi core does not support programmable speed */ +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct xilinx_spi_slave *xilspi; + struct xilinx_spi_reg *regs; + + if (!spi_cs_is_valid(bus, cs)) { + printf("XILSPI error: %s: unsupported bus %d / cs %d\n", + __func__, bus, cs); + return NULL; + } + + xilspi = malloc(sizeof(*xilspi)); + if (!xilspi) { + printf("XILSPI error: %s: malloc of SPI structure failed\n", + __func__); + return NULL; + } + xilspi->slave.bus = bus; + xilspi->slave.cs = cs; + xilspi->regs = (struct xilinx_spi_reg *)xilinx_spi_base_list[bus]; + xilspi->freq = max_hz; + xilspi->mode = mode; + debug("%s: bus:%i cs:%i base:%p mode:%x max_hz:%d\n", __func__, + bus, cs, xilspi->regs, xilspi->mode, xilspi->freq); + + return &xilspi->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave); + + free(xilspi); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave); + u32 spicr; + + debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); + writel(SPISSR_OFF, &xilspi->regs->spissr); + + spicr = XILSPI_SPICR_DFLT_ON; + if (xilspi->mode & SPI_LSB_FIRST) + spicr |= SPICR_LSB_FIRST; + if (xilspi->mode & SPI_CPHA) + spicr |= SPICR_CPHA; + if (xilspi->mode & SPI_CPOL) + spicr |= SPICR_CPOL; + if (xilspi->mode & SPI_LOOP) + spicr |= SPICR_LOOP; + + writel(spicr, &xilspi->regs->spicr); + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave); + + debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); + writel(SPISSR_OFF, &xilspi->regs->spissr); + writel(XILSPI_SPICR_DFLT_OFF, &xilspi->regs->spicr); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave); + /* assume spi core configured to do 8 bit transfers */ + unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS; + const unsigned char *txp = dout; + unsigned char *rxp = din; + unsigned rxecount = 17; /* max. 16 elements in FIFO, leftover 1 */ + + debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__, + slave->bus, slave->cs, bitlen, bytes, flags); + if (bitlen == 0) + goto done; + + if (bitlen % XILSPI_MAX_XFER_BITS) { + printf("XILSPI warning: %s: Not a multiple of %d bits\n", + __func__, XILSPI_MAX_XFER_BITS); + flags |= SPI_XFER_END; + goto done; + } + + /* empty read buffer */ + while (rxecount && !(readl(&xilspi->regs->spisr) & SPISR_RX_EMPTY)) { + readl(&xilspi->regs->spidrr); + rxecount--; + } + + if (!rxecount) { + printf("XILSPI error: %s: Rx buffer not empty\n", __func__); + return -1; + } + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + while (bytes--) { + unsigned timeout = /* at least 1usec or greater, leftover 1 */ + xilspi->freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 : + (XILSPI_MAX_XFER_BITS * 1000000 / xilspi->freq) + 1; + + /* get Tx element from data out buffer and count up */ + unsigned char d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL; + debug("%s: tx:%x ", __func__, d); + + /* write out and wait for processing (receive data) */ + writel(d & SPIDTR_8BIT_MASK, &xilspi->regs->spidtr); + while (timeout && readl(&xilspi->regs->spisr) + & SPISR_RX_EMPTY) { + timeout--; + udelay(1); + } + + if (!timeout) { + printf("XILSPI error: %s: Xfer timeout\n", __func__); + return -1; + } + + /* read Rx element and push into data in buffer */ + d = readl(&xilspi->regs->spidrr) & SPIDRR_8BIT_MASK; + if (rxp) + *rxp++ = d; + debug("rx:%x\n", d); + } + + done: + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + return 0; +} diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h new file mode 100644 index 000000000..32610d2a1 --- /dev/null +++ b/drivers/spi/xilinx_spi.h @@ -0,0 +1,135 @@ +/* + * Xilinx SPI driver + * + * XPS/AXI bus interface + * + * based on bfin_spi.c, by way of altera_spi.c + * Copyright (c) 2005-2008 Analog Devices Inc. + * Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw> + * Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca> + * Copyright (c) 2012 Stephan Linz <linz@li-pro.net> + * + * Licensed under the GPL-2 or later. + * + * [0]: http://www.xilinx.com/support/documentation + * + * [S]: [0]/ip_documentation/xps_spi.pdf + * [0]/ip_documentation/axi_spi_ds742.pdf + */ +#ifndef _XILINX_SPI_ +#define _XILINX_SPI_ + +#include <asm/types.h> +#include <asm/io.h> + +/* + * Xilinx SPI Register Definition + * + * [1]: [0]/ip_documentation/xps_spi.pdf + * page 8, Register Descriptions + * [2]: [0]/ip_documentation/axi_spi_ds742.pdf + * page 7, Register Overview Table + */ +struct xilinx_spi_reg { + u32 __space0__[7]; + u32 dgier; /* Device Global Interrupt Enable Register (DGIER) */ + u32 ipisr; /* IP Interrupt Status Register (IPISR) */ + u32 __space1__; + u32 ipier; /* IP Interrupt Enable Register (IPIER) */ + u32 __space2__[5]; + u32 srr; /* Softare Reset Register (SRR) */ + u32 __space3__[7]; + u32 spicr; /* SPI Control Register (SPICR) */ + u32 spisr; /* SPI Status Register (SPISR) */ + u32 spidtr; /* SPI Data Transmit Register (SPIDTR) */ + u32 spidrr; /* SPI Data Receive Register (SPIDRR) */ + u32 spissr; /* SPI Slave Select Register (SPISSR) */ + u32 spitfor; /* SPI Transmit FIFO Occupancy Register (SPITFOR) */ + u32 spirfor; /* SPI Receive FIFO Occupancy Register (SPIRFOR) */ +}; + +/* Device Global Interrupt Enable Register (dgier), [1] p15, [2] p15 */ +#define DGIER_GIE (1 << 31) + +/* IP Interrupt Status Register (ipisr), [1] p15, [2] p15 */ +#define IPISR_DRR_NOT_EMPTY (1 << 8) +#define IPISR_SLAVE_SELECT (1 << 7) +#define IPISR_TXF_HALF_EMPTY (1 << 6) +#define IPISR_DRR_OVERRUN (1 << 5) +#define IPISR_DRR_FULL (1 << 4) +#define IPISR_DTR_UNDERRUN (1 << 3) +#define IPISR_DTR_EMPTY (1 << 2) +#define IPISR_SLAVE_MODF (1 << 1) +#define IPISR_MODF (1 << 0) + +/* IP Interrupt Enable Register (ipier), [1] p17, [2] p18 */ +#define IPIER_DRR_NOT_EMPTY (1 << 8) +#define IPIER_SLAVE_SELECT (1 << 7) +#define IPIER_TXF_HALF_EMPTY (1 << 6) +#define IPIER_DRR_OVERRUN (1 << 5) +#define IPIER_DRR_FULL (1 << 4) +#define IPIER_DTR_UNDERRUN (1 << 3) +#define IPIER_DTR_EMPTY (1 << 2) +#define IPIER_SLAVE_MODF (1 << 1) +#define IPIER_MODF (1 << 0) + +/* Softare Reset Register (srr), [1] p9, [2] p8 */ +#define SRR_RESET_CODE 0x0000000A + +/* SPI Control Register (spicr), [1] p9, [2] p8 */ +#define SPICR_LSB_FIRST (1 << 9) +#define SPICR_MASTER_INHIBIT (1 << 8) +#define SPICR_MANUAL_SS (1 << 7) +#define SPICR_RXFIFO_RESEST (1 << 6) +#define SPICR_TXFIFO_RESEST (1 << 5) +#define SPICR_CPHA (1 << 4) +#define SPICR_CPOL (1 << 3) +#define SPICR_MASTER_MODE (1 << 2) +#define SPICR_SPE (1 << 1) +#define SPICR_LOOP (1 << 0) + +/* SPI Status Register (spisr), [1] p11, [2] p10 */ +#define SPISR_SLAVE_MODE_SELECT (1 << 5) +#define SPISR_MODF (1 << 4) +#define SPISR_TX_FULL (1 << 3) +#define SPISR_TX_EMPTY (1 << 2) +#define SPISR_RX_FULL (1 << 1) +#define SPISR_RX_EMPTY (1 << 0) + +/* SPI Data Transmit Register (spidtr), [1] p12, [2] p12 */ +#define SPIDTR_8BIT_MASK (0xff << 0) +#define SPIDTR_16BIT_MASK (0xffff << 0) +#define SPIDTR_32BIT_MASK (0xffffffff << 0) + +/* SPI Data Receive Register (spidrr), [1] p12, [2] p12 */ +#define SPIDRR_8BIT_MASK (0xff << 0) +#define SPIDRR_16BIT_MASK (0xffff << 0) +#define SPIDRR_32BIT_MASK (0xffffffff << 0) + +/* SPI Slave Select Register (spissr), [1] p13, [2] p13 */ +#define SPISSR_MASK(cs) (1 << (cs)) +#define SPISSR_ACT(cs) ~SPISSR_MASK(cs) +#define SPISSR_OFF ~0UL + +/* SPI Transmit FIFO Occupancy Register (spitfor), [1] p13, [2] p14 */ +#define SPITFOR_OCYVAL_POS 0 +#define SPITFOR_OCYVAL_MASK (0xf << SPITFOR_OCYVAL_POS) + +/* SPI Receive FIFO Occupancy Register (spirfor), [1] p14, [2] p14 */ +#define SPIRFOR_OCYVAL_POS 0 +#define SPIRFOR_OCYVAL_MASK (0xf << SPIRFOR_OCYVAL_POS) + +struct xilinx_spi_slave { + struct spi_slave slave; + struct xilinx_spi_reg *regs; + unsigned int freq; + unsigned int mode; +}; + +static inline struct xilinx_spi_slave *to_xilinx_spi_slave( + struct spi_slave *slave) +{ + return container_of(slave, struct xilinx_spi_slave, slave); +} + +#endif /* _XILINX_SPI_ */ |