From 4e09cc1e2c5d22735d0fa3d2d1eaecd27e19948e Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sat, 11 Jan 2014 15:10:28 +0530 Subject: sf: Add extended read commands support Current sf uses FAST_READ command, this patch adds support to use the different/extended read command. This implementation will determine the fastest command by taking the supported commands from the flash and the controller, controller is always been a priority. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index e316a692a..49ceef0ed 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -285,7 +285,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, return 0; } - cmd[0] = CMD_READ_ARRAY_FAST; + cmd[0] = flash->read_cmd; cmd[4] = 0x00; while (len) { -- cgit v1.2.3-70-g09d2 From 3163aaa63fced54bbd6fd190ece0f89b473076ab Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sat, 11 Jan 2014 15:13:11 +0530 Subject: sf: Add quad read/write commands support This patch add quad commands support like - QUAD_PAGE_PROGRAM => for write program - QUAD_OUTPUT_FAST ->> for read program Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_internal.h | 2 + drivers/mtd/spi/sf_ops.c | 2 +- drivers/mtd/spi/sf_probe.c | 178 ++++++++++++++++++++++-------------------- include/spi.h | 9 ++- include/spi_flash.h | 11 ++- 5 files changed, 113 insertions(+), 89 deletions(-) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 938a78efc..dcc9014e5 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -28,6 +28,7 @@ #define CMD_PAGE_PROGRAM 0x02 #define CMD_WRITE_DISABLE 0x04 #define CMD_READ_STATUS 0x05 +#define CMD_QUAD_PAGE_PROGRAM 0x32 #define CMD_READ_STATUS1 0x35 #define CMD_WRITE_ENABLE 0x06 #define CMD_READ_CONFIG 0x35 @@ -38,6 +39,7 @@ #define CMD_READ_ARRAY_FAST 0x0b #define CMD_READ_DUAL_OUTPUT_FAST 0x3b #define CMD_READ_DUAL_IO_FAST 0xbb +#define CMD_READ_QUAD_OUTPUT_FAST 0x6b #define CMD_READ_ID 0x9f /* Bank addr access commands */ diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 49ceef0ed..3d304ce6a 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -210,7 +210,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, page_size = flash->page_size; - cmd[0] = CMD_PAGE_PROGRAM; + cmd[0] = flash->write_cmd; for (actual = 0; actual < len; actual += chunk_len) { #ifdef CONFIG_SPI_FLASH_BAR ret = spi_flash_bank(flash, offset); diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index c0baac620..3fa7363da 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -42,105 +42,105 @@ 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, 0, SECT_4K}, - {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, 0, SECT_4K}, - {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, 0, SECT_4K}, - {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, 0, SECT_4K}, - {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, 0, SECT_4K}, - {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, 0, SECT_4K}, - {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, 0, SECT_4K}, - {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, 0, SECT_4K}, + {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, 0, SECT_4K}, + {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, 0, SECT_4K}, + {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, 0, SECT_4K}, + {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, 0, SECT_4K}, + {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, 0, SECT_4K}, + {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, 0, SECT_4K}, + {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, 0, SECT_4K}, + {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, 0, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_EON /* EON */ - {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0, 0}, - {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, 0, SECT_4K}, - {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0, 0}, - {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0, 0}, + {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0, 0}, + {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, 0, SECT_4K}, + {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0, 0}, + {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0, 0}, #endif #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ - {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, 0, SECT_4K}, - {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, 0, SECT_4K}, + {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, 0, SECT_4K}, + {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, 0, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ - {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0, 0}, - {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0, 0}, - {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0, 0}, - {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0, 0}, - {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0, 0}, - {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0, 0}, - {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0, 0}, - {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0, 0}, - {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, 0, 0}, - {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0, 0}, + {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0, 0}, + {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0, 0}, + {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0, 0}, + {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0, 0}, + {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0, 0}, + {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0, 0}, + {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0, 0}, + {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0, 0}, + {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, 0, 0}, + {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0, 0}, #endif #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ - {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0, 0}, - {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0, 0}, - {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0, 0}, - {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0, 0}, - {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0, 0}, - {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0, 0}, - {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0, 0}, - {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0, 0}, - {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0, 0}, - {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, RD_EXTN, 0}, - {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_EXTN, 0}, - {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, 0, 0}, - {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0, 0}, + {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0, 0}, + {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0, 0}, + {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0, 0}, + {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0, 0}, + {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0, 0}, + {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0, 0}, + {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0, 0}, + {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0, 0}, + {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0, 0}, + {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, RD_FULL, WR_QPP}, + {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_FULL, WR_QPP}, + {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, 0, 0}, + {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0, 0}, #endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0, 0}, - {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0, 0}, - {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0, 0}, - {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0, 0}, - {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0, 0}, - {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0, 0}, - {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0, 0}, - {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0, 0}, - {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, 0, SECT_4K}, - {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, 0, SECT_4K}, - {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, 0, SECT_4K}, - {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, 0, SECT_4K}, - {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, 0, SECT_4K}, - {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, 0, SECT_4K}, - {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, 0, SECT_4K}, - {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, 0, SECT_4K}, - {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, 0, E_FSR | SECT_4K}, - {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, 0, E_FSR | SECT_4K}, - {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, 0, E_FSR | SECT_4K}, - {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, 0, E_FSR | SECT_4K}, + {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0, 0}, + {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0, 0}, + {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0, 0}, + {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0, 0}, + {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0, 0}, + {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0, 0}, + {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0, 0}, + {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0, 0}, + {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, 0, SECT_4K}, + {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, 0, SECT_4K}, + {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, 0, SECT_4K}, + {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, 0, SECT_4K}, + {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, 0, SECT_4K}, + {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, 0, SECT_4K}, + {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, 0, SECT_4K}, + {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, 0, SECT_4K}, + {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, 0, E_FSR | SECT_4K}, + {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, 0, E_FSR | SECT_4K}, + {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, 0, E_FSR | SECT_4K}, + {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, 0, E_FSR | SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ - {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP}, - {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP}, - {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, 0, SECT_4K | SST_WP}, - {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, 0, SECT_4K | SST_WP}, - {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, 0, SECT_4K}, - {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, 0, SECT_4K | SST_WP}, - {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, 0, SECT_4K | SST_WP}, - {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, 0, SECT_4K | SST_WP}, - {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP}, - {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP}, + {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP}, + {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP}, + {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, 0, SECT_4K | SST_WP}, + {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, 0, SECT_4K | SST_WP}, + {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, 0, SECT_4K}, + {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, 0, SECT_4K | SST_WP}, + {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, 0, SECT_4K | SST_WP}, + {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, 0, SECT_4K | SST_WP}, + {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP}, + {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP}, #endif #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ - {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0, 0}, - {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0, 0}, - {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0, 0}, - {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, 0, SECT_4K}, - {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, 0, SECT_4K}, - {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, 0, SECT_4K}, - {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 0, SECT_4K}, - {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, 0, SECT_4K}, - {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, 0, SECT_4K}, - {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, 0, SECT_4K}, - {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, 0, SECT_4K}, - {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, 0, SECT_4K}, - {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, 0, SECT_4K}, - {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, 0, SECT_4K}, - {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, 0, SECT_4K}, - {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, 0, SECT_4K}, - {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, 0, SECT_4K}, - {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, 0, SECT_4K}, + {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0, 0}, + {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0, 0}, + {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0, 0}, + {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, 0, SECT_4K}, + {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, 0, SECT_4K}, + {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, 0, SECT_4K}, + {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 0, SECT_4K}, + {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, 0, SECT_4K}, + {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, 0, SECT_4K}, + {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, 0, SECT_4K}, + {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, 0, SECT_4K}, + {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, 0, SECT_4K}, + {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, 0, SECT_4K}, + {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, 0, SECT_4K}, + {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, 0, SECT_4K}, + {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, 0, SECT_4K}, + {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, 0, SECT_4K}, + {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, 0, SECT_4K}, #endif /* * Note: @@ -162,6 +162,7 @@ static u8 spi_read_cmds_array[] = { CMD_READ_ARRAY_SLOW, CMD_READ_DUAL_OUTPUT_FAST, CMD_READ_DUAL_IO_FAST, + CMD_READ_QUAD_OUTPUT_FAST, }; static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, @@ -242,6 +243,13 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, flash->read_cmd = CMD_READ_ARRAY_FAST; } + /* Not require to look for fastest only two write cmds yet */ + if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) + flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; + else + /* Go for default supported write cmd */ + flash->write_cmd = CMD_PAGE_PROGRAM; + /* Poll cmd seclection */ flash->poll_cmd = CMD_READ_STATUS; #ifdef CONFIG_SPI_FLASH_STMICRO diff --git a/include/spi.h b/include/spi.h index 31195a307..5dd490a66 100644 --- a/include/spi.h +++ b/include/spi.h @@ -31,11 +31,16 @@ #define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */ #define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END) +/* SPI TX operation modes */ +#define SPI_OPM_TX_QPP 1 << 0 + /* SPI RX operation modes */ #define SPI_OPM_RX_AS 1 << 0 #define SPI_OPM_RX_DOUT 1 << 1 #define SPI_OPM_RX_DIO 1 << 2 -#define SPI_OPM_RX_EXTN SPI_OPM_RX_AS | SPI_OPM_RX_DOUT | SPI_OPM_RX_DIO +#define SPI_OPM_RX_QOF 1 << 3 +#define SPI_OPM_RX_EXTN SPI_OPM_RX_AS | SPI_OPM_RX_DOUT | \ + SPI_OPM_RX_DIO | SPI_OPM_RX_QOF /* Header byte that marks the start of the message */ #define SPI_PREAMBLE_END_BYTE 0xec @@ -50,6 +55,7 @@ * @bus: ID of the bus that the slave is attached to. * @cs: ID of the chip select connected to the slave. * @op_mode_rx: SPI RX operation mode. + * @op_mode_tx: SPI TX operation mode. * @wordlen: Size of SPI word in number of bits * @max_write_size: If non-zero, the maximum number of bytes which can * be written at once, excluding command bytes. @@ -59,6 +65,7 @@ struct spi_slave { unsigned int bus; unsigned int cs; u8 op_mode_rx; + u8 op_mode_tx; unsigned int wordlen; unsigned int max_write_size; void *memory_map; diff --git a/include/spi_flash.h b/include/spi_flash.h index 692e143b6..9fd9d3bd5 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -19,13 +19,18 @@ #include #include -/* Enum list - Extended read commands */ +/* No enum list for write commands only QPP */ +#define WR_QPP 1 << 4 + +/* Enum list - Full read commands */ enum spi_read_cmds { ARRAY_SLOW = 1 << 0, DUAL_OUTPUT_FAST = 1 << 1, DUAL_IO_FAST = 1 << 2, + QUAD_OUTPUT_FAST = 1 << 3, }; #define RD_EXTN ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST +#define RD_FULL RD_EXTN | QUAD_OUTPUT_FAST /** * struct spi_flash - SPI flash structure @@ -41,7 +46,8 @@ enum spi_read_cmds { * @bank_curr: Current flash bank * @poll_cmd: Poll cmd - for flash erase/program * @erase_cmd: Erase cmd 4K, 32K, 64K - * @read_cmd: Read cmd - Array Fast and Extn read + * @read_cmd: Read cmd - Array Fast, Extn read and quad read. + * @write_cmd: Write cmd - page and quad program. * @memory_map: Address of read-only SPI flash access * @read: Flash read ops: Read len bytes at offset into buf * Supported cmds: Fast Array Read @@ -67,6 +73,7 @@ struct spi_flash { u8 poll_cmd; u8 erase_cmd; u8 read_cmd; + u8 write_cmd; void *memory_map; int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf); -- cgit v1.2.3-70-g09d2 From 6cba6fdf96f13a0533187b9c16608d9ca44add40 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Mon, 23 Dec 2013 15:47:48 +0530 Subject: sf: ops: Add configuration register writing support This patch provides support to program a flash config register. Configuration register contains the control bits used to configure the different configurations and security features of a device. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_ops.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 3d304ce6a..39e06ecae 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -38,6 +38,30 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) return 0; } +static int spi_flash_cmd_write_config(struct spi_flash *flash, u8 cr) +{ + u8 data[2]; + u8 cmd; + int ret; + + cmd = CMD_READ_STATUS; + ret = spi_flash_read_common(flash, &cmd, 1, &data[0], 1); + if (ret < 0) { + debug("SF: fail to read status register\n"); + return ret; + } + + cmd = CMD_WRITE_STATUS; + data[1] = cr; + ret = spi_flash_write_common(flash, &cmd, 1, &data, 2); + if (ret) { + debug("SF: fail to write config register\n"); + return ret; + } + + return 0; +} + #ifdef CONFIG_SPI_FLASH_BAR static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) { -- cgit v1.2.3-70-g09d2 From d08a1baf617a8b7f1959c6b24c1ee7590a0c06a5 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Thu, 26 Dec 2013 13:54:57 +0530 Subject: sf: Set quad enable bit support This patch provides support to set the quad enable bit on flash. quad enable bit needs to set before performing any quad IO operations on respective SPI flashes. Currently added set quad enable bit for winbond and spansion flash devices. stmicro flash doesn't require to set as qeb is volatile. remaining flash devices support will add in future patches. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_internal.h | 10 ++++++++-- drivers/mtd/spi/sf_ops.c | 26 ++++++++++++++++++++++++++ drivers/mtd/spi/sf_probe.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index dcc9014e5..dca34f7a7 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -12,6 +12,11 @@ #define SPI_FLASH_16MB_BOUN 0x1000000 +/* CFI Manufacture ID's */ +#define SPI_FLASH_CFI_MFR_SPANSION 0x01 +#define SPI_FLASH_CFI_MFR_STMICRO 0x20 +#define SPI_FLASH_CFI_MFR_WINBOND 0xef + /* SECT flags */ #define SECT_4K (1 << 1) #define SECT_32K (1 << 2) @@ -52,6 +57,7 @@ /* Common status */ #define STATUS_WIP 0x01 +#define STATUS_QEB_WINSPAN (1 << 1) #define STATUS_PEC 0x80 /* Flash timeout values */ @@ -93,8 +99,8 @@ 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); +/* Set quad enbale bit for winbond and spansion flashes */ +int spi_flash_set_qeb_winspan(struct spi_flash *flash); /* Enable writing on the SPI flash */ static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 39e06ecae..827f71912 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -38,6 +38,7 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) return 0; } +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) static int spi_flash_cmd_write_config(struct spi_flash *flash, u8 cr) { u8 data[2]; @@ -62,6 +63,31 @@ static int spi_flash_cmd_write_config(struct spi_flash *flash, u8 cr) return 0; } +int spi_flash_set_qeb_winspan(struct spi_flash *flash) +{ + u8 qeb_status; + u8 cmd; + int ret; + + cmd = CMD_READ_CONFIG; + ret = spi_flash_read_common(flash, &cmd, 1, &qeb_status, 1); + if (ret < 0) { + debug("SF: fail to read config register\n"); + return ret; + } + + if (qeb_status & STATUS_QEB_WINSPAN) { + debug("SF: Quad enable bit is already set\n"); + } else { + ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN); + if (ret < 0) + return ret; + } + + return ret; +} +#endif + #ifdef CONFIG_SPI_FLASH_BAR static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) { diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 3fa7363da..8b2972c7a 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -165,6 +165,25 @@ static u8 spi_read_cmds_array[] = { CMD_READ_QUAD_OUTPUT_FAST, }; +static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) +{ + switch (idcode0) { +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) + case SPI_FLASH_CFI_MFR_SPANSION: + case SPI_FLASH_CFI_MFR_WINBOND: + return spi_flash_set_qeb_winspan(flash); +#endif +#ifdef CONFIG_SPI_FLASH_STMICRO + case SPI_FLASH_CFI_MFR_STMICRO: + debug("SF: QEB is volatile for %02x flash\n", idcode0); + return 0; +#endif + default: + printf("SF: Need set QEB func for %02x flash\n", idcode0); + return -1; + } +} + static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, u8 *idcode) { @@ -250,6 +269,15 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, /* Go for default supported write cmd */ flash->write_cmd = CMD_PAGE_PROGRAM; + /* Set the quad enable bit - only for quad commands */ + if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || + (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { + if (spi_flash_set_qeb(flash, idcode[0])) { + debug("SF: Fail to set QEB for %02x\n", idcode[0]); + return NULL; + } + } + /* Poll cmd seclection */ flash->poll_cmd = CMD_READ_STATUS; #ifdef CONFIG_SPI_FLASH_STMICRO -- cgit v1.2.3-70-g09d2 From ff063ed4808e4ead3021eaf53ee4fdb80c9e91f8 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sat, 11 Jan 2014 16:50:45 +0530 Subject: sf: Discover read dummy_byte Discovered the read dummy_byte based on the configured read command. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_internal.h | 2 ++ drivers/mtd/spi/sf_ops.c | 16 +++++++++------- drivers/mtd/spi/sf_probe.c | 19 +++++++++++++++++++ include/spi_flash.h | 2 ++ 4 files changed, 32 insertions(+), 7 deletions(-) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 7be02925c..a9f5a8111 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -10,6 +10,8 @@ #ifndef _SF_INTERNAL_H_ #define _SF_INTERNAL_H_ +#define SPI_FLASH_3B_ADDR_LEN 3 +#define SPI_FLASH_CMD_LEN (1 + SPI_FLASH_3B_ADDR_LEN) #define SPI_FLASH_16MB_BOUN 0x1000000 /* CFI Manufacture ID's */ diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 827f71912..6adee325c 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -216,7 +217,7 @@ 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; - u8 cmd[4]; + u8 cmd[SPI_FLASH_CMD_LEN]; int ret = -1; erase_size = flash->erase_size; @@ -255,7 +256,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, { unsigned long byte_addr, page_size; size_t chunk_len, actual; - u8 cmd[4]; + u8 cmd[SPI_FLASH_CMD_LEN]; int ret = -1; page_size = flash->page_size; @@ -317,7 +318,7 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data) { - u8 cmd[5], bank_sel = 0; + u8 *cmd, cmdsz, bank_sel = 0; u32 remain_len, read_len; int ret = -1; @@ -335,9 +336,11 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, return 0; } - cmd[0] = flash->read_cmd; - cmd[4] = 0x00; + cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte; + cmd = malloc(cmdsz); + memset(cmd, 0, cmdsz); + cmd[0] = flash->read_cmd; while (len) { #ifdef CONFIG_SPI_FLASH_BAR bank_sel = offset / SPI_FLASH_16MB_BOUN; @@ -356,8 +359,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, spi_flash_addr(offset, cmd); - ret = spi_flash_read_common(flash, cmd, sizeof(cmd), - data, read_len); + ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len); if (ret < 0) { debug("SF: read failed\n"); break; diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index a049e729a..8bd06eea6 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -140,6 +140,25 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, } } + /* Read dummy_byte: dummy byte is determined based on the + * dummy cycles of a particular command. + * Fast commands - dummy_byte = dummy_cycles/8 + * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 + * For I/O commands except cmd[0] everything goes on no.of lines + * based on particular command but incase of fast commands except + * data all go on single line irrespective of command. + */ + switch (flash->read_cmd) { + case CMD_READ_QUAD_IO_FAST: + flash->dummy_byte = 2; + break; + case CMD_READ_ARRAY_SLOW: + flash->dummy_byte = 0; + break; + default: + flash->dummy_byte = 1; + } + /* Poll cmd seclection */ flash->poll_cmd = CMD_READ_STATUS; #ifdef CONFIG_SPI_FLASH_STMICRO diff --git a/include/spi_flash.h b/include/spi_flash.h index 99724a0d3..437937cfc 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -72,6 +72,7 @@ extern const struct spi_flash_params spi_flash_params_table[]; * @erase_cmd: Erase cmd 4K, 32K, 64K * @read_cmd: Read cmd - Array Fast, Extn read and quad read. * @write_cmd: Write cmd - page and quad program. + * @dummy_byte: Dummy cycles for read operation. * @memory_map: Address of read-only SPI flash access * @read: Flash read ops: Read len bytes at offset into buf * Supported cmds: Fast Array Read @@ -98,6 +99,7 @@ struct spi_flash { u8 erase_cmd; u8 read_cmd; u8 write_cmd; + u8 dummy_byte; void *memory_map; int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf); -- cgit v1.2.3-70-g09d2 From 067951223e3305fce3df972c1970f6ab1ef15e98 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Thu, 26 Dec 2013 14:13:36 +0530 Subject: sf: Add macronix set QEB support This patch adds set QEB support for macronix flash devices which are trying to program/read quad operations. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_internal.h | 5 +++++ drivers/mtd/spi/sf_ops.c | 26 ++++++++++++++++++++++++++ drivers/mtd/spi/sf_probe.c | 4 ++++ 3 files changed, 35 insertions(+) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index a9f5a8111..c69b53de1 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -17,6 +17,7 @@ /* CFI Manufacture ID's */ #define SPI_FLASH_CFI_MFR_SPANSION 0x01 #define SPI_FLASH_CFI_MFR_STMICRO 0x20 +#define SPI_FLASH_CFI_MFR_MACRONIX 0xc2 #define SPI_FLASH_CFI_MFR_WINBOND 0xef /* SECT flags */ @@ -61,6 +62,7 @@ /* Common status */ #define STATUS_WIP 0x01 #define STATUS_QEB_WINSPAN (1 << 1) +#define STATUS_QEB_MXIC (1 << 6) #define STATUS_PEC 0x80 /* Flash timeout values */ @@ -102,6 +104,9 @@ 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 for macronix flashes */ +int spi_flash_set_qeb_mxic(struct spi_flash *flash); + /* Set quad enbale bit for winbond and spansion flashes */ int spi_flash_set_qeb_winspan(struct spi_flash *flash); diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 6adee325c..05fbcbd43 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -39,6 +39,32 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) return 0; } +#ifdef CONFIG_SPI_FLASH_MACRONIX +int spi_flash_set_qeb_mxic(struct spi_flash *flash) +{ + u8 qeb_status; + u8 cmd; + int ret; + + cmd = CMD_READ_STATUS; + ret = spi_flash_read_common(flash, &cmd, 1, &qeb_status, 1); + if (ret < 0) { + debug("SF: fail to read status register\n"); + return ret; + } + + if (qeb_status & STATUS_QEB_MXIC) { + debug("SF: Quad enable bit is already set\n"); + } else { + ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC); + if (ret < 0) + return ret; + } + + return ret; +} +#endif + #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) static int spi_flash_cmd_write_config(struct spi_flash *flash, u8 cr) { diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 8bd06eea6..88d1d0a88 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -31,6 +31,10 @@ static u8 spi_read_cmds_array[] = { static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) { switch (idcode0) { +#ifdef CONFIG_SPI_FLASH_MACRONIX + case SPI_FLASH_CFI_MFR_MACRONIX: + return spi_flash_set_qeb_mxic(flash); +#endif #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) case SPI_FLASH_CFI_MFR_SPANSION: case SPI_FLASH_CFI_MFR_WINBOND: -- cgit v1.2.3-70-g09d2 From 9f4322fd2281d9736b9fd208a5e2ecaec49e21e0 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Mon, 30 Dec 2013 22:16:23 +0530 Subject: sf: Divide flash register ops from QEB code QEB code comprises of couple of flash register read/write operations, this patch moved flash register operations on to sf_op Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_internal.h | 11 ++++--- drivers/mtd/spi/sf_ops.c | 75 +++++++++++++++---------------------------- drivers/mtd/spi/sf_probe.c | 44 +++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 53 deletions(-) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index c69b53de1..c77961fde 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -101,14 +101,17 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, /* Flash erase(sectors) operation, support all possible erase commands */ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); +/* Read the status register */ +int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); + /* Program the status register */ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); -/* Set quad enbale bit for macronix flashes */ -int spi_flash_set_qeb_mxic(struct spi_flash *flash); +/* Read the config register */ +int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc); -/* Set quad enbale bit for winbond and spansion flashes */ -int spi_flash_set_qeb_winspan(struct spi_flash *flash); +/* Program the config register */ +int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc); /* Enable writing on the SPI flash */ static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 05fbcbd43..28527fa82 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -24,94 +24,71 @@ static void spi_flash_addr(u32 addr, u8 *cmd) cmd[3] = addr >> 0; } -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) +int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs) { - u8 cmd; int ret; + u8 cmd; - cmd = CMD_WRITE_STATUS; - ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); + cmd = CMD_READ_STATUS; + ret = spi_flash_read_common(flash, &cmd, 1, rs, 1); if (ret < 0) { - debug("SF: fail to write status register\n"); + debug("SF: fail to read status register\n"); return ret; } return 0; } -#ifdef CONFIG_SPI_FLASH_MACRONIX -int spi_flash_set_qeb_mxic(struct spi_flash *flash) +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) { - u8 qeb_status; u8 cmd; int ret; - cmd = CMD_READ_STATUS; - ret = spi_flash_read_common(flash, &cmd, 1, &qeb_status, 1); + cmd = CMD_WRITE_STATUS; + ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); if (ret < 0) { - debug("SF: fail to read status register\n"); + debug("SF: fail to write status register\n"); return ret; } - if (qeb_status & STATUS_QEB_MXIC) { - debug("SF: Quad enable bit is already set\n"); - } else { - ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC); - if (ret < 0) - return ret; - } - - return ret; + return 0; } -#endif #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) -static int spi_flash_cmd_write_config(struct spi_flash *flash, u8 cr) +int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc) { - u8 data[2]; - u8 cmd; int ret; + u8 cmd; - cmd = CMD_READ_STATUS; - ret = spi_flash_read_common(flash, &cmd, 1, &data[0], 1); + cmd = CMD_READ_CONFIG; + ret = spi_flash_read_common(flash, &cmd, 1, rc, 1); if (ret < 0) { - debug("SF: fail to read status register\n"); - return ret; - } - - cmd = CMD_WRITE_STATUS; - data[1] = cr; - ret = spi_flash_write_common(flash, &cmd, 1, &data, 2); - if (ret) { - debug("SF: fail to write config register\n"); + debug("SF: fail to read config register\n"); return ret; } return 0; } -int spi_flash_set_qeb_winspan(struct spi_flash *flash) +int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) { - u8 qeb_status; + u8 data[2]; u8 cmd; int ret; - cmd = CMD_READ_CONFIG; - ret = spi_flash_read_common(flash, &cmd, 1, &qeb_status, 1); - if (ret < 0) { - debug("SF: fail to read config register\n"); + ret = spi_flash_cmd_read_status(flash, &data[0]); + if (ret < 0) return ret; - } - if (qeb_status & STATUS_QEB_WINSPAN) { - debug("SF: Quad enable bit is already set\n"); - } else { - ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN); - if (ret < 0) - return ret; + cmd = CMD_WRITE_STATUS; + data[1] = wc; + ret = spi_flash_write_common(flash, &cmd, 1, &data, 2); + if (ret) { + debug("SF: fail to write config register\n"); + return ret; } - return ret; + return 0; } #endif diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 88d1d0a88..6b59f2a71 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -28,6 +28,50 @@ static u8 spi_read_cmds_array[] = { CMD_READ_QUAD_IO_FAST, }; +#ifdef CONFIG_SPI_FLASH_MACRONIX +static int spi_flash_set_qeb_mxic(struct spi_flash *flash) +{ + u8 qeb_status; + int ret; + + ret = spi_flash_cmd_read_status(flash, &qeb_status); + if (ret < 0) + return ret; + + if (qeb_status & STATUS_QEB_MXIC) { + debug("SF: mxic: QEB is already set\n"); + } else { + ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC); + if (ret < 0) + return ret; + } + + return ret; +} +#endif + +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) +static int spi_flash_set_qeb_winspan(struct spi_flash *flash) +{ + u8 qeb_status; + int ret; + + ret = spi_flash_cmd_read_config(flash, &qeb_status); + if (ret < 0) + return ret; + + if (qeb_status & STATUS_QEB_WINSPAN) { + debug("SF: winspan: QEB is already set\n"); + } else { + ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN); + if (ret < 0) + return ret; + } + + return ret; +} +#endif + static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) { switch (idcode0) { -- cgit v1.2.3-70-g09d2 From 2ba863fae628bb5fe2ec4b803f639c1edb55ea33 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sun, 12 Jan 2014 21:38:21 +0530 Subject: sf: Code cleanups - comment typo's - func args have a proper names Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_internal.h | 11 +++-------- drivers/mtd/spi/sf_ops.c | 6 +++--- drivers/mtd/spi/sf_probe.c | 4 ++-- include/spi_flash.h | 5 ++++- 4 files changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index c77961fde..6bcd52204 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -20,11 +20,6 @@ #define SPI_FLASH_CFI_MFR_MACRONIX 0xc2 #define SPI_FLASH_CFI_MFR_WINBOND 0xef -/* SECT flags */ -#define SECT_4K (1 << 1) -#define SECT_32K (1 << 2) -#define E_FSR (1 << 3) - /* Erase commands */ #define CMD_ERASE_4K 0x20 #define CMD_ERASE_32K 0x52 @@ -60,10 +55,10 @@ #endif /* Common status */ -#define STATUS_WIP 0x01 +#define STATUS_WIP (1 << 0) #define STATUS_QEB_WINSPAN (1 << 1) #define STATUS_QEB_MXIC (1 << 6) -#define STATUS_PEC 0x80 +#define STATUS_PEC (1 << 7) /* Flash timeout values */ #define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) @@ -105,7 +100,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); /* Program the status register */ -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); /* Read the config register */ int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc); diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 28527fa82..bc4a822fb 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -39,13 +39,13 @@ int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs) return 0; } -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws) { u8 cmd; int ret; cmd = CMD_WRITE_STATUS; - ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); + ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1); if (ret < 0) { debug("SF: fail to write status register\n"); return ret; @@ -279,7 +279,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, spi_flash_addr(offset, cmd); - debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", + debug("SF: 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); ret = spi_flash_write_common(flash, cmd, sizeof(cmd), diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 6b59f2a71..ac42b60c8 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -167,7 +167,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, cmd = spi_read_cmds_array[cmd - 1]; flash->read_cmd = cmd; } else { - /* Go for for default supported read cmd */ + /* Go for default supported read cmd */ flash->read_cmd = CMD_READ_ARRAY_FAST; } @@ -207,7 +207,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, flash->dummy_byte = 1; } - /* Poll cmd seclection */ + /* Poll cmd selection */ flash->poll_cmd = CMD_READ_STATUS; #ifdef CONFIG_SPI_FLASH_STMICRO if (params->flags & E_FSR) diff --git a/include/spi_flash.h b/include/spi_flash.h index 437937cfc..213d6592b 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -19,7 +19,10 @@ #include #include -/* No enum list for write commands only QPP */ +/* sf param flags */ +#define SECT_4K 1 << 1 +#define SECT_32K 1 << 2 +#define E_FSR 1 << 3 #define WR_QPP 1 << 4 /* Enum list - Full read commands */ -- cgit v1.2.3-70-g09d2 From ab92224f4550f9677be32dd903e99acf1475dbf7 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sat, 11 Jan 2014 16:57:07 +0530 Subject: sf: ops: Unify read_ops bank configuration Unified the bar code from read_ops into a spi_flash_bar() Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_ops.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index bc4a822fb..7ae958211 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -127,7 +127,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset) return ret; } - return 0; + return bank_sel; } #endif @@ -321,8 +321,9 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data) { - u8 *cmd, cmdsz, bank_sel = 0; + u8 *cmd, cmdsz; u32 remain_len, read_len; + int bank_sel = 0; int ret = -1; /* Handle memory-mapped SPI */ @@ -346,13 +347,9 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, cmd[0] = flash->read_cmd; while (len) { #ifdef CONFIG_SPI_FLASH_BAR - bank_sel = offset / 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); + bank_sel = spi_flash_bank(flash, offset); + if (bank_sel < 0) return ret; - } #endif remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset; if (len < remain_len) -- cgit v1.2.3-70-g09d2 From f77f469117ab3184ac45683a50dc446265be28cc Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sun, 12 Jan 2014 21:40:11 +0530 Subject: sf: Add dual memories support - DUAL_STACKED This patch added support for accessing dual memories in stacked connection with single chipselect line from controller. For more info - see doc/SPI/README.dual-flash Signed-off-by: Jagannadha Sutradharudu Teki --- doc/SPI/README.dual-flash | 65 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/mtd/spi/sf.c | 3 +++ drivers/mtd/spi/sf_ops.c | 57 +++++++++++++++++++++++++++++++++------- drivers/mtd/spi/sf_probe.c | 8 +++++- include/spi.h | 8 ++++++ include/spi_flash.h | 8 ++++++ 6 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 doc/SPI/README.dual-flash (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/doc/SPI/README.dual-flash b/doc/SPI/README.dual-flash new file mode 100644 index 000000000..ba0aa265e --- /dev/null +++ b/doc/SPI/README.dual-flash @@ -0,0 +1,65 @@ +SPI/QSPI Dual flash connection modes: +===================================== + +This describes how SPI/QSPI flash memories are connected to a given +controller in a single chip select line. + +Current spi_flash framework supports, single flash memory connected +to a given controller with single chip select line, but there are some +hw logics(ex: xilinx zynq qspi) that describes two/dual memories are +connected with a single chip select line from a controller. + +"dual_flash" from include/spi.h describes these types of connection mode + +Possible connections: +-------------------- +SF_SINGLE_FLASH: + - single spi flash memory connected with single chip select line. + + +------------+ CS +---------------+ + | |----------------------->| | + | Controller | I0[3:0] | Flash memory | + | SPI/QSPI |<======================>| (SPI/QSPI) | + | | CLK | | + | |----------------------->| | + +------------+ +---------------+ + +SF_DUAL_STACKED_FLASH: + - dual spi/qspi flash memories are connected with a single chipselect + line and these two memories are operating stacked fasion with shared buses. + - xilinx zynq qspi controller has implemented this feature [1] + + +------------+ CS +---------------+ + | |---------------------->| | + | | I0[3:0] | Upper Flash | + | | +=========>| memory | + | | | CLK | (SPI/QSPI) | + | | | +---->| | + | Controller | CS | | +---------------+ + | SPI/QSPI |------------|----|---->| | + | | I0[3:0] | | | Lower Flash | + | |<===========+====|====>| memory | + | | CLK | | (SPI/QSPI) | + | |-----------------+---->| | + +------------+ +---------------+ + + - two memory flash devices should has same hw part attributes (like size, + vendor..etc) + - Configurations: + on LQSPI_CFG register, Enable TWO_MEM[BIT:30] on LQSPI_CFG + Enable U_PAGE[BIT:28] if U_PAGE flag set - upper memory + Disable U_PAGE[BIT:28] if U_PAGE flag unset - lower memory + - Operation: + accessing memories serially like one after another. + by default, if U_PAGE is unset lower memory should accessible, + once user wants to access upper memory need to set U_PAGE. + +Note: Technically there is only one CS line from the controller, but +zynq qspi controller has an internal hw logic to enable additional CS +when controller is configured for dual memories. + +[1] http://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf + +-- +Jagannadha Sutradharudu Teki +05-01-2014. diff --git a/drivers/mtd/spi/sf.c b/drivers/mtd/spi/sf.c index d5e175ca0..c780a81c5 100644 --- a/drivers/mtd/spi/sf.c +++ b/drivers/mtd/spi/sf.c @@ -18,6 +18,9 @@ static int spi_flash_read_write(struct spi_slave *spi, unsigned long flags = SPI_XFER_BEGIN; int ret; + if (spi->flags & SPI_XFER_U_PAGE) + flags |= SPI_XFER_U_PAGE; + if (data_len == 0) flags |= SPI_XFER_END; diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 7ae958211..e877858a9 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -131,10 +131,28 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset) } #endif +static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr) +{ + switch (flash->dual_flash) { + case SF_DUAL_STACKED_FLASH: + if (*addr >= (flash->size >> 1)) { + *addr -= flash->size >> 1; + flash->spi->flags |= SPI_XFER_U_PAGE; + } else { + flash->spi->flags &= ~SPI_XFER_U_PAGE; + } + break; + default: + debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash); + break; + } +} + int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) { struct spi_slave *spi = flash->spi; unsigned long timebase; + unsigned long flags = SPI_XFER_BEGIN; int ret; u8 status; u8 check_status = 0x0; @@ -146,7 +164,10 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) check_status = poll_bit; } - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); + if (spi->flags & SPI_XFER_U_PAGE) + flags |= SPI_XFER_U_PAGE; + + ret = spi_xfer(spi, 8, &cmd, NULL, flags); if (ret) { debug("SF: fail to read %s status register\n", cmd == CMD_READ_STATUS ? "read" : "flag"); @@ -219,7 +240,7 @@ 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[SPI_FLASH_CMD_LEN]; int ret = -1; @@ -231,15 +252,20 @@ 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 (flash->dual_flash > SF_SINGLE_FLASH) + spi_flash_dual_flash(flash, &erase_addr); + #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) { @@ -258,6 +284,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, size_t len, const void *buf) { unsigned long byte_addr, page_size; + u32 write_addr; size_t chunk_len, actual; u8 cmd[SPI_FLASH_CMD_LEN]; int ret = -1; @@ -266,8 +293,13 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, cmd[0] = flash->write_cmd; for (actual = 0; actual < len; actual += chunk_len) { + write_addr = offset; + + if (flash->dual_flash > SF_SINGLE_FLASH) + spi_flash_dual_flash(flash, &write_addr); + #ifdef CONFIG_SPI_FLASH_BAR - ret = spi_flash_bank(flash, offset); + ret = spi_flash_bank(flash, write_addr); if (ret < 0) return ret; #endif @@ -277,7 +309,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("SF: 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); @@ -322,7 +354,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data) { u8 *cmd, cmdsz; - u32 remain_len, read_len; + u32 remain_len, read_len, read_addr; int bank_sel = 0; int ret = -1; @@ -346,8 +378,13 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, cmd[0] = flash->read_cmd; while (len) { + read_addr = offset; + + if (flash->dual_flash > SF_SINGLE_FLASH) + spi_flash_dual_flash(flash, &read_addr); + #ifdef CONFIG_SPI_FLASH_BAR - bank_sel = spi_flash_bank(flash, offset); + bank_sel = spi_flash_bank(flash, read_addr); if (bank_sel < 0) return ret; #endif @@ -357,7 +394,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, else read_len = remain_len; - spi_flash_addr(offset, cmd); + spi_flash_addr(read_addr, cmd); ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len); if (ret < 0) { diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index ac42b60c8..b9e14c5a2 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -134,6 +134,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, flash->spi = spi; flash->name = params->name; flash->memory_map = spi->memory_map; + flash->dual_flash = flash->spi->option; /* Assign spi_flash ops */ flash->write = spi_flash_cmd_write_ops; @@ -148,6 +149,8 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; flash->sector_size = params->sector_size; flash->size = flash->sector_size * params->nr_sectors; + if (flash->dual_flash & SF_DUAL_STACKED_FLASH) + flash->size <<= 1; /* Compute erase sector and command */ if (params->flags & SECT_4K) { @@ -324,7 +327,10 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi) puts("\n"); #endif #ifndef CONFIG_SPI_FLASH_BAR - if (flash->size > SPI_FLASH_16MB_BOUN) { + if (((flash->dual_flash == SF_SINGLE_FLASH) && + (flash->size > SPI_FLASH_16MB_BOUN)) || + ((flash->dual_flash > SF_SINGLE_FLASH) && + (flash->size > SPI_FLASH_16MB_BOUN << 1))) { puts("SF: Warning - Only lower 16MiB accessible,"); puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); } diff --git a/include/spi.h b/include/spi.h index c8a9d87b5..d214d8292 100644 --- a/include/spi.h +++ b/include/spi.h @@ -30,6 +30,7 @@ #define SPI_XFER_MMAP 0x08 /* Memory Mapped start */ #define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */ #define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END) +#define SPI_XFER_U_PAGE (1 << 5) /* SPI TX operation modes */ #define SPI_OPM_TX_QPP 1 << 0 @@ -44,6 +45,9 @@ SPI_OPM_RX_DIO | SPI_OPM_RX_QOF | \ SPI_OPM_RX_QIOF +/* SPI bus connection options */ +#define SPI_CONN_DUAL_SHARED 1 << 0 + /* Header byte that marks the start of the message */ #define SPI_PREAMBLE_END_BYTE 0xec @@ -62,6 +66,8 @@ * @max_write_size: If non-zero, the maximum number of bytes which can * be written at once, excluding command bytes. * @memory_map: Address of read-only SPI flash access. + * @option: Varies SPI bus options - separate bus. + * @flags: Indication of SPI flags. */ struct spi_slave { unsigned int bus; @@ -71,6 +77,8 @@ struct spi_slave { unsigned int wordlen; unsigned int max_write_size; void *memory_map; + u8 option; + u8 flags; }; /** diff --git a/include/spi_flash.h b/include/spi_flash.h index 213d6592b..36f1f033c 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -36,6 +36,12 @@ enum spi_read_cmds { #define RD_EXTN ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST #define RD_FULL RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST +/* Dual SPI flash memories */ +enum spi_dual_flash { + SF_SINGLE_FLASH = 0, + SF_DUAL_STACKED_FLASH = 1 << 0, +}; + /** * struct spi_flash_params - SPI/QSPI flash device params structure * @@ -64,6 +70,7 @@ extern const struct spi_flash_params spi_flash_params_table[]; * * @spi: SPI slave * @name: Name of SPI flash + * @dual_flash: Indicates dual flash memories - dual stacked * @size: Total flash size * @page_size: Write (page) size * @sector_size: Sector size @@ -88,6 +95,7 @@ extern const struct spi_flash_params spi_flash_params_table[]; struct spi_flash { struct spi_slave *spi; const char *name; + u8 dual_flash; u32 size; u32 page_size; -- cgit v1.2.3-70-g09d2 From 056fbc73d54df64adcb93c513cba708acb2683bd Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Tue, 7 Jan 2014 00:11:35 +0530 Subject: sf: Add dual memories support - DUAL_PARALLEL This patch added support for accessing dual memories in parallel connection with single chipselect line from controller. For more info - see doc/SPI/README.dual-flash Signed-off-by: Jagannadha Sutradharudu Teki --- doc/SPI/README.dual-flash | 27 +++++++++++++++++++++++++++ drivers/mtd/spi/sf_ops.c | 8 ++++++-- drivers/mtd/spi/sf_probe.c | 11 ++++++----- include/spi.h | 3 ++- include/spi_flash.h | 5 ++++- 5 files changed, 45 insertions(+), 9 deletions(-) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/doc/SPI/README.dual-flash b/doc/SPI/README.dual-flash index ba0aa265e..6c88d65dd 100644 --- a/doc/SPI/README.dual-flash +++ b/doc/SPI/README.dual-flash @@ -54,6 +54,33 @@ SF_DUAL_STACKED_FLASH: by default, if U_PAGE is unset lower memory should accessible, once user wants to access upper memory need to set U_PAGE. +SPI_FLASH_CONN_DUALPARALLEL: + - dual spi/qspi flash memories are connected with a single chipselect + line and these two memories are operating parallel with separate buses. + - xilinx zynq qspi controller has implemented this feature [1] + + +-------------+ CS +---------------+ + | |---------------------->| | + | | I0[3:0] | Upper Flash | + | |<=====================>| memory | + | | CLK | (SPI/QSPI) | + | |---------------------->| | + | Controller | CS +---------------+ + | SPI/QSPI |---------------------->| | + | | I0[3:0] | Lower Flash | + | |<=====================>| memory | + | | CLK | (SPI/QSPI) | + | |---------------------->| | + +-------------+ +---------------+ + + - two memory flash devices should has same hw part attributes (like size, + vendor..etc) + - Configurations: + Need to enable SEP_BUS[BIT:29],TWO_MEM[BIT:30] on LQSPI_CFG register. + - Operation: + Even bits, i.e. bit 0, 2, 4 ., of a data word is located in the lower memory + and odd bits, i.e. bit 1, 3, 5, ., of a data word is located in the upper memory. + Note: Technically there is only one CS line from the controller, but zynq qspi controller has an internal hw logic to enable additional CS when controller is configured for dual memories. diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index e877858a9..843f379ef 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -119,7 +119,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset) u8 bank_sel; int ret; - bank_sel = offset / SPI_FLASH_16MB_BOUN; + bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift); ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); if (ret) { @@ -142,6 +142,9 @@ static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr) flash->spi->flags &= ~SPI_XFER_U_PAGE; } break; + case SF_DUAL_PARALLEL_FLASH: + *addr >>= flash->shift; + break; default: debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash); break; @@ -388,7 +391,8 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, if (bank_sel < 0) return ret; #endif - remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset; + remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) * + (bank_sel + 1)) - offset; if (len < remain_len) read_len = len; else diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index b9e14c5a2..48de7c198 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -146,19 +146,20 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, flash->read = spi_flash_cmd_read_ops; /* Compute the flash size */ - flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; - flash->sector_size = params->sector_size; - flash->size = flash->sector_size * params->nr_sectors; + flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; + flash->page_size = ((ext_jedec == 0x4d00) ? 512 : 256) << flash->shift; + flash->sector_size = params->sector_size << flash->shift; + flash->size = flash->sector_size * params->nr_sectors << flash->shift; if (flash->dual_flash & SF_DUAL_STACKED_FLASH) flash->size <<= 1; /* Compute erase sector and command */ if (params->flags & SECT_4K) { flash->erase_cmd = CMD_ERASE_4K; - flash->erase_size = 4096; + flash->erase_size = 4096 << flash->shift; } else if (params->flags & SECT_32K) { flash->erase_cmd = CMD_ERASE_32K; - flash->erase_size = 32768; + flash->erase_size = 32768 << flash->shift; } else { flash->erase_cmd = CMD_ERASE_64K; flash->erase_size = flash->sector_size; diff --git a/include/spi.h b/include/spi.h index d214d8292..ffd66478b 100644 --- a/include/spi.h +++ b/include/spi.h @@ -47,6 +47,7 @@ /* SPI bus connection options */ #define SPI_CONN_DUAL_SHARED 1 << 0 +#define SPI_CONN_DUAL_SEPARATED 1 << 1 /* Header byte that marks the start of the message */ #define SPI_PREAMBLE_END_BYTE 0xec @@ -66,7 +67,7 @@ * @max_write_size: If non-zero, the maximum number of bytes which can * be written at once, excluding command bytes. * @memory_map: Address of read-only SPI flash access. - * @option: Varies SPI bus options - separate bus. + * @option: Varies SPI bus options - separate, shared bus. * @flags: Indication of SPI flags. */ struct spi_slave { diff --git a/include/spi_flash.h b/include/spi_flash.h index 36f1f033c..f79f0eacc 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -40,6 +40,7 @@ enum spi_read_cmds { enum spi_dual_flash { SF_SINGLE_FLASH = 0, SF_DUAL_STACKED_FLASH = 1 << 0, + SF_DUAL_PARALLEL_FLASH = 1 << 1, }; /** @@ -70,7 +71,8 @@ extern const struct spi_flash_params spi_flash_params_table[]; * * @spi: SPI slave * @name: Name of SPI flash - * @dual_flash: Indicates dual flash memories - dual stacked + * @dual_flash: Indicates dual flash memories - dual stacked, parallel + * @shift: Flash shift useful in dual parallel * @size: Total flash size * @page_size: Write (page) size * @sector_size: Sector size @@ -96,6 +98,7 @@ struct spi_flash { struct spi_slave *spi; const char *name; u8 dual_flash; + u8 shift; u32 size; u32 page_size; -- cgit v1.2.3-70-g09d2 From b902e07cea51e33fbe36453f7b1412dd7bbe760f Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sat, 11 Jan 2014 15:25:04 +0530 Subject: sf: Add CONFIG_SF_DUAL_FLASH This config will use for defining greater than single flash support. currently - DUAL_STACKED and DUAL_PARALLEL. Signed-off-by: Jagannadha Sutradharudu Teki --- README | 6 ++++++ drivers/mtd/spi/sf.c | 3 ++- drivers/mtd/spi/sf_ops.c | 14 ++++++++++---- drivers/mtd/spi/sf_probe.c | 2 ++ 4 files changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers/mtd/spi/sf_ops.c') diff --git a/README b/README index a0646c366..aea82be5b 100644 --- a/README +++ b/README @@ -2756,6 +2756,12 @@ CBFS (Coreboot Filesystem) support Define this option to use the Bank addr/Extended addr support on SPI flashes which has size > 16Mbytes. + CONFIG_SF_DUAL_FLASH Dual flash memories + + Define this option to use dual flash support where two flash + memories can be connected with a given cs line. + currently Xilinx Zynq qspi support these type of connections. + - SystemACE Support: CONFIG_SYSTEMACE diff --git a/drivers/mtd/spi/sf.c b/drivers/mtd/spi/sf.c index c780a81c5..664e86082 100644 --- a/drivers/mtd/spi/sf.c +++ b/drivers/mtd/spi/sf.c @@ -18,9 +18,10 @@ static int spi_flash_read_write(struct spi_slave *spi, unsigned long flags = SPI_XFER_BEGIN; int ret; +#ifdef CONFIG_SF_DUAL_FLASH if (spi->flags & SPI_XFER_U_PAGE) flags |= SPI_XFER_U_PAGE; - +#endif if (data_len == 0) flags |= SPI_XFER_END; diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 843f379ef..1f1bb3606 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -131,6 +131,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset) } #endif +#ifdef CONFIG_SF_DUAL_FLASH static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr) { switch (flash->dual_flash) { @@ -150,6 +151,7 @@ static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr) break; } } +#endif int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) { @@ -167,9 +169,10 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) check_status = poll_bit; } +#ifdef CONFIG_SF_DUAL_FLASH if (spi->flags & SPI_XFER_U_PAGE) flags |= SPI_XFER_U_PAGE; - +#endif ret = spi_xfer(spi, 8, &cmd, NULL, flags); if (ret) { debug("SF: fail to read %s status register\n", @@ -257,9 +260,10 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) while (len) { erase_addr = offset; +#ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash > SF_SINGLE_FLASH) spi_flash_dual_flash(flash, &erase_addr); - +#endif #ifdef CONFIG_SPI_FLASH_BAR ret = spi_flash_bank(flash, erase_addr); if (ret < 0) @@ -298,9 +302,10 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, for (actual = 0; actual < len; actual += chunk_len) { write_addr = offset; +#ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash > SF_SINGLE_FLASH) spi_flash_dual_flash(flash, &write_addr); - +#endif #ifdef CONFIG_SPI_FLASH_BAR ret = spi_flash_bank(flash, write_addr); if (ret < 0) @@ -383,9 +388,10 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, while (len) { read_addr = offset; +#ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash > SF_SINGLE_FLASH) spi_flash_dual_flash(flash, &read_addr); - +#endif #ifdef CONFIG_SPI_FLASH_BAR bank_sel = spi_flash_bank(flash, read_addr); if (bank_sel < 0) diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 48de7c198..bc3cf6cc6 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -150,8 +150,10 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, flash->page_size = ((ext_jedec == 0x4d00) ? 512 : 256) << flash->shift; flash->sector_size = params->sector_size << flash->shift; flash->size = flash->sector_size * params->nr_sectors << flash->shift; +#ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash & SF_DUAL_STACKED_FLASH) flash->size <<= 1; +#endif /* Compute erase sector and command */ if (params->flags & SECT_4K) { -- cgit v1.2.3-70-g09d2