From eb179907834bd936a5a4a48d259a203a1fe350e9 Mon Sep 17 00:00:00 2001 From: Troy Kisky <troy.kisky@boundarydevices.com> Date: Fri, 26 Jan 2018 18:04:25 -0800 Subject: [PATCH] mtd: spi: fix at45db041d Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com> --- drivers/mtd/spi/sf_internal.h | 9 ++++ drivers/mtd/spi/spi_flash.c | 74 ++++++++++++++++++++++++++++++--- drivers/mtd/spi/spi_flash_ids.c | 2 +- include/spi_flash.h | 5 +++ 4 files changed, 83 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 4f63cacc642..9a3d3350f9b 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -38,6 +38,7 @@ enum spi_nor_option_flags { #define SPI_FLASH_CFI_MFR_ATMEL 0x1f /* Erase commands */ +#define CMD_ERASE_2K 0x50 #define CMD_ERASE_4K 0x20 #define CMD_ERASE_CHIP 0xc7 #define CMD_ERASE_64K 0xd8 @@ -45,6 +46,10 @@ enum spi_nor_option_flags { /* Write commands */ #define CMD_WRITE_STATUS 0x01 #define CMD_PAGE_PROGRAM 0x02 +/* 0x84 followed by 3byte offset into buffer */ +#define CMD_BUFFER1_WRITE 0x84 +/* 0x88 followed by 2 byte page #, and 1 dummy byte */ +#define CMD_BUFFER1_PROGRAM 0x88 #define CMD_WRITE_DISABLE 0x04 #define CMD_WRITE_ENABLE 0x06 #define CMD_QUAD_PAGE_PROGRAM 0x32 @@ -59,6 +64,7 @@ enum spi_nor_option_flags { #define CMD_READ_ID 0x9f #define CMD_READ_STATUS 0x05 #define CMD_READ_STATUS1 0x35 +#define CMD_READ_STATUS2 0xd7 #define CMD_READ_CONFIG 0x35 #define CMD_FLAG_STATUS 0x70 @@ -75,6 +81,7 @@ enum spi_nor_option_flags { #define STATUS_QEB_WINSPAN BIT(1) #define STATUS_QEB_MXIC BIT(6) #define STATUS_PEC BIT(7) +#define STATUS2_READY BIT(7) #define SR_BP0 BIT(2) /* Block protect 0 */ #define SR_BP1 BIT(3) /* Block protect 1 */ #define SR_BP2 BIT(4) /* Block protect 2 */ @@ -143,6 +150,8 @@ struct spi_flash_info { #define RD_DUAL BIT(5) /* use Dual Read */ #define RD_QUADIO BIT(6) /* use Quad IO Read */ #define RD_DUALIO BIT(7) /* use Dual IO Read */ +#define ATMEL_REGS BIT(8) +#define SECT_2K BIT(9) /* CMD_ERASE_2K works */ #define RD_FULL (RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO) }; diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index dd93ff61d85..14c16a38580 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -31,15 +31,12 @@ static void spi_flash_addr(u32 addr, u8 *cmd) static int read_sr(struct spi_flash *flash, u8 *rs) { int ret; - u8 cmd; - cmd = CMD_READ_STATUS; - ret = spi_flash_read_common(flash, &cmd, 1, rs, 1); + ret = spi_flash_read_common(flash, &flash->status_cmd, 1, rs, 1); if (ret < 0) { debug("SF: fail to read status register\n"); return ret; } - return 0; } @@ -215,8 +212,7 @@ static int spi_flash_sr_ready(struct spi_flash *flash) ret = read_sr(flash, &sr); if (ret < 0) return ret; - - return !(sr & STATUS_WIP); + return (sr & flash->status_ready_mask) == flash->status_ready_level; } static int spi_flash_fsr_ready(struct spi_flash *flash) @@ -428,6 +424,50 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, return ret; } +#ifdef CONFIG_SPI_FLASH_ATMEL +int spi_flash_cmd_write_ops_atmel(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + unsigned long byte_addr, page_size; + size_t actual; + u8 cmd[4]; + int ret = -1; + + page_size = flash->page_size; + + byte_addr = offset % page_size; + if (byte_addr) + return -EINVAL; + + for (actual = 0; actual < len; actual += page_size) { + cmd[0] = CMD_BUFFER1_WRITE; + cmd[1] = 0; + cmd[2] = 0; + cmd[3] = 0; + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), + buf + actual, page_size); + if (ret < 0) { + debug("SF: write failed\n"); + break; + } + + cmd[0] = CMD_BUFFER1_PROGRAM; + spi_flash_addr(offset, cmd); + + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), + buf + actual, page_size); + if (ret < 0) { + debug("SF: write failed\n"); + break; + } + + offset += page_size; + } + + return ret; +} +#endif + int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, size_t cmd_len, void *data, size_t data_len) { @@ -1176,6 +1216,19 @@ int spi_flash_scan(struct spi_flash *flash) flash->write = sst_write_wp; } #endif + + flash->status_cmd = CMD_READ_STATUS; + flash->status_ready_mask = STATUS_WIP; + flash->status_ready_level = 0; + +#ifdef CONFIG_SPI_FLASH_ATMEL + if (info->flags & ATMEL_REGS) { + flash->write = spi_flash_cmd_write_ops_atmel; + flash->status_cmd = CMD_READ_STATUS2; + flash->status_ready_mask = STATUS2_READY; + flash->status_ready_level = STATUS2_READY; + } +#endif flash->erase = spi_flash_cmd_erase_ops; flash->read = spi_flash_cmd_read_ops; #endif @@ -1227,6 +1280,9 @@ int spi_flash_scan(struct spi_flash *flash) if (info->flags & SECT_4K) { flash->erase_cmd = CMD_ERASE_4K; flash->erase_size = 4096 << flash->shift; + } else if (info->flags & SECT_2K) { + flash->erase_cmd = CMD_ERASE_2K; + flash->erase_size = 2048 << flash->shift; } else #endif { @@ -1253,6 +1309,12 @@ int spi_flash_scan(struct spi_flash *flash) /* Go for default supported write cmd */ flash->write_cmd = CMD_PAGE_PROGRAM; + /* Flash powers up read-only, so clear BP# bits */ + if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_ATMEL || + JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_MACRONIX || + JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_SST) + write_sr(flash, 0); + /* Set the quad enable bit - only for quad commands */ if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || diff --git a/drivers/mtd/spi/spi_flash_ids.c b/drivers/mtd/spi/spi_flash_ids.c index 2d1f9ea8a12..4e77dd2f643 100644 --- a/drivers/mtd/spi/spi_flash_ids.c +++ b/drivers/mtd/spi/spi_flash_ids.c @@ -46,7 +46,7 @@ const struct spi_flash_info spi_flash_ids[] = { #ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ {"at45db011d", INFO(0x1f2200, 0x0, 64 * 1024, 4, SECT_4K) }, {"at45db021d", INFO(0x1f2300, 0x0, 64 * 1024, 8, SECT_4K) }, - {"at45db041d", INFO(0x1f2400, 0x0, 64 * 1024, 8, SECT_4K) }, + {"at45db041d", INFO(0x1f2400, 0x0, 64 * 1024, 8, SECT_2K | ATMEL_REGS) }, {"at45db081d", INFO(0x1f2500, 0x0, 64 * 1024, 16, SECT_4K) }, {"at45db161d", INFO(0x1f2600, 0x0, 64 * 1024, 32, SECT_4K) }, {"at45db321d", INFO(0x1f2700, 0x0, 64 * 1024, 64, SECT_4K) }, diff --git a/include/spi_flash.h b/include/spi_flash.h index 22533311c54..5edf4727926 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -83,6 +83,11 @@ struct spi_flash { u8 write_cmd; u8 dummy_byte; + u8 status_cmd; + u8 status_ready_mask; + u8 status_ready_level; + u8 spare1; + void *memory_map; int (*flash_lock)(struct spi_flash *flash, u32 ofs, size_t len); -- GitLab