From patchwork Wed Feb 10 19:08:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jagan Teki X-Patchwork-Id: 581556 X-Patchwork-Delegate: jagannadh.teki@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 1CD16140325 for ; Thu, 11 Feb 2016 06:11:41 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 5784EA7505; Wed, 10 Feb 2016 20:11:05 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id uSjvAnRu_9CY; Wed, 10 Feb 2016 20:11:05 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id DD3C4A7579; Wed, 10 Feb 2016 20:10:59 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 3A6D3A7528 for ; Wed, 10 Feb 2016 20:10:54 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id M_bPzFIlbTa0 for ; Wed, 10 Feb 2016 20:10:54 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-pa0-f65.google.com (mail-pa0-f65.google.com [209.85.220.65]) by theia.denx.de (Postfix) with ESMTPS id 2CC58A7531 for ; Wed, 10 Feb 2016 20:10:40 +0100 (CET) Received: by mail-pa0-f65.google.com with SMTP id fl4so1313919pad.2 for ; Wed, 10 Feb 2016 11:10:40 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=SCNPxyZ5PhJ4vu9qWADgzmVCEudMXpbsuJ76YMWNwZI=; b=SrQBQg937+DPle8dLTYSzornAupQDsnE8kt026kyEIF2T/BzKSJwSDxlarfCsOosj4 Xa7wwjP8hN2ITvh/TTs3jonKnLhmmXfdQBQZ19yShaOfnnAV0vGqTvsVJCsYc8Iu+4BB 6+VpJKclyyShfqfQP9oBSIkjLJLOsk341dWg9qLIfMCKDuTAe91g/Vz+D9sMZ8Luaq53 XLUiEUjjmlF66/ZoGA+tPaOOp6zBXZUJ9MCWkws4wIJXK6fvSibk1OmCAuizHVwX8QB2 5aNrgTc/qyL4kUtxPoxOExv5ttn1YU4QSID9Ifq1OWnsSCP+E8/MmhxvULZiBkpGE6W5 k1EA== X-Gm-Message-State: AG10YOQlHiuavKNDx9wbyFvelAqONYX0DMHvUfN5PO9TC/QgQU44hi1ak2+pqkxn5dHO8Q== X-Received: by 10.66.235.36 with SMTP id uj4mr61811880pac.85.1455131439158; Wed, 10 Feb 2016 11:10:39 -0800 (PST) Received: from localhost.localdomain ([123.236.183.254]) by smtp.gmail.com with ESMTPSA id n78sm6915903pfb.53.2016.02.10.11.10.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 10 Feb 2016 11:10:37 -0800 (PST) From: Jagan Teki To: u-boot@lists.denx.de Date: Thu, 11 Feb 2016 00:38:02 +0530 Message-Id: <1455131307-25406-8-git-send-email-jteki@openedev.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1455131307-25406-1-git-send-email-jteki@openedev.com> References: <1455131307-25406-1-git-send-email-jteki@openedev.com> Cc: Tom Rini , Michal Simek , Siva Durga Prasad Paladugu , Jagan Teki Subject: [U-Boot] [PATCH v5 07/32] mtd: spi-nor: Add MTD support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" This patch adds mtd_info support to spi-nor core instead of using legacy spi_flash{}. SPI-NOR with MTD: ------------------------------ cmd_sf.c ------------------------------ MTD core ------------------------------ spi-nor.c ------------------------------- m25p80.c spi nor drivers ------------------------------- spi-uclass SPI NOR chip ------------------------------- spi drivers ------------------------------- SPI NOR chip ------------------------------- Cc: Simon Glass Cc: Bin Meng Cc: Mugunthan V N Cc: Michal Simek Cc: Siva Durga Prasad Paladugu Signed-off-by: Jagan Teki --- drivers/mtd/spi-nor/spi-nor.c | 273 +++++++++++++++++++++++++----------------- 1 file changed, 165 insertions(+), 108 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index f142ae4..3b42b69 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -209,10 +211,11 @@ bar_end: static int spi_nor_read_bar(struct spi_nor *nor, const struct spi_nor_info *info) { + struct mtd_info *mtd = nor->mtd; u8 curr_bank = 0; int ret; - if (flash->size <= SNOR_16MB_BOUN) + if (mtd->size <= SNOR_16MB_BOUN) goto bar_end; switch (JEDEC_MFR(info)) { @@ -240,12 +243,12 @@ bar_end: #ifdef CONFIG_SF_DUAL_FLASH static void spi_nor_dual(struct spi_nor *nor, u32 *addr) { - struct spi_flash *flash = nor->flash; + struct mtd_info *mtd = nor->mtd; switch (nor->dual) { case SNOR_DUAL_STACKED: - if (*addr >= (flash->size >> 1)) { - *addr -= flash->size >> 1; + if (*addr >= (mtd->size >> 1)) { + *addr -= mtd->size >> 1; nor->flags |= SNOR_F_U_PAGE; } else { nor->flags &= ~SNOR_F_U_PAGE; @@ -263,8 +266,9 @@ static void spi_nor_dual(struct spi_nor *nor, u32 *addr) #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs, - u32 *len) + uint64_t *len) { + struct mtd_info *mtd = nor->mtd; u8 mask = SR_BP2 | SR_BP1 | SR_BP0; int shift = ffs(mask) - 1; int pow; @@ -275,18 +279,19 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs, *len = 0; } else { pow = ((sr & mask) ^ mask) >> shift; - *len = flash->size >> pow; - *ofs = flash->size - *len; + *len = mtd->size >> pow; + *ofs = mtd->size - *len; } } /* * Return 1 if the entire region is locked, 0 otherwise */ -static int stm_is_locked_sr(struct spi_nor *nor, u32 ofs, u32 len, u8 sr) +static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len, + u8 sr) { loff_t lock_offs; - u32 lock_len; + uint64_t lock_len; stm_get_locked_range(nor, sr, &lock_offs, &lock_len); @@ -294,24 +299,6 @@ static int stm_is_locked_sr(struct spi_nor *nor, u32 ofs, u32 len, u8 sr) } /* - * Check if a region of the flash is (completely) locked. See stm_lock() for - * more info. - * - * Returns 1 if entire region is locked, 0 if any portion is unlocked, and - * negative on errors. - */ -static int stm_is_locked(struct spi_nor *nor, u32 ofs, size_t len) -{ - int status; - - status = read_sr(nor); - if (status < 0) - return status; - - return stm_is_locked_sr(nor, ofs, len, status); -} - -/* * Lock a region of the flash. Compatible with ST Micro and similar flash. * Supports only the block protection bits BP{0,1,2} in the status register * (SR). Does not support these features found in newer SR bitfields: @@ -334,9 +321,10 @@ static int stm_is_locked(struct spi_nor *nor, u32 ofs, size_t len) * * Returns negative on errors, 0 on success. */ -static int stm_lock(struct spi_nor *nor, u32 ofs, size_t len) +static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) { - u8 status_old, status_new; + struct mtd_info *mtd = nor->mtd; + int status_old, status_new; u8 mask = SR_BP2 | SR_BP1 | SR_BP0; u8 shift = ffs(mask) - 1, pow, val; @@ -345,12 +333,12 @@ static int stm_lock(struct spi_nor *nor, u32 ofs, size_t len) return status_old; /* SPI NOR always locks to the end */ - if (ofs + len != flash->size) { + if (ofs + len != mtd->size) { /* Does combined region extend to end? */ - if (!stm_is_locked_sr(nor, ofs + len, flash->size - ofs - len, + if (!stm_is_locked_sr(nor, ofs + len, mtd->size - ofs - len, status_old)) return -EINVAL; - len = flash->size - ofs; + len = mtd->size - ofs; } /* @@ -362,11 +350,10 @@ static int stm_lock(struct spi_nor *nor, u32 ofs, size_t len) * * pow = ceil(log2(size / len)) = log2(size) - floor(log2(len)) */ - pow = ilog2(flash->size) - ilog2(len); + pow = ilog2(mtd->size) - ilog2(len); val = mask - (pow << shift); if (val & ~mask) return -EINVAL; - /* Don't "lock" with no region! */ if (!(val & mask)) return -EINVAL; @@ -386,20 +373,22 @@ static int stm_lock(struct spi_nor *nor, u32 ofs, size_t len) * * Returns negative on errors, 0 on success. */ -static int stm_unlock(struct spi_nor *nor, u32 ofs, size_t len) +static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) { - uint8_t status_old, status_new; + struct mtd_info *mtd = nor->mtd; + int status_old, status_new; u8 mask = SR_BP2 | SR_BP1 | SR_BP0; u8 shift = ffs(mask) - 1, pow, val; status_old = read_sr(nor); - if (status_old < 0) + if (status_old < 0) return status_old; /* Cannot unlock; would unlock larger region than requested */ - if (stm_is_locked_sr(nor, status_old, ofs - flash->erase_size, - nor->erase_size)) + if (stm_is_locked_sr(nor, status_old, ofs - mtd->erasesize, + mtd->erasesize)) return -EINVAL; + /* * Need largest pow such that: * @@ -409,8 +398,8 @@ static int stm_unlock(struct spi_nor *nor, u32 ofs, size_t len) * * pow = floor(log2(size / len)) = log2(size) - ceil(log2(len)) */ - pow = ilog2(flash->size) - order_base_2(flash->size - (ofs + len)); - if (ofs + len == flash->size) { + pow = ilog2(mtd->size) - order_base_2(mtd->size - (ofs + len)); + if (ofs + len == mtd->size) { val = 0; /* fully unlocked */ } else { val = mask - (pow << shift); @@ -428,8 +417,47 @@ static int stm_unlock(struct spi_nor *nor, u32 ofs, size_t len) write_enable(nor); return write_sr(nor, status_new); } + +/* + * Check if a region of the flash is (completely) locked. See stm_lock() for + * more info. + * + * Returns 1 if entire region is locked, 0 if any portion is unlocked, and + * negative on errors. + */ +static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + int status; + + status = read_sr(nor); + if (status < 0) + return status; + + return stm_is_locked_sr(nor, ofs, len, status); +} #endif +static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd->priv; + + return nor->flash_lock(nor, ofs, len); +} + +static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd->priv; + + return nor->flash_unlock(nor, ofs, len); +} + +static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd->priv; + + return nor->flash_is_locked(nor, ofs, len); +} + static const struct spi_nor_info *spi_nor_id(struct spi_nor *nor) { int tmp; @@ -455,30 +483,32 @@ static const struct spi_nor_info *spi_nor_id(struct spi_nor *nor) return ERR_PTR(-ENODEV); } -static int spi_nor_erase(struct spi_flash *flash, u32 offset, size_t len) +static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) { - struct spi_nor *nor = flash->nor; - u32 erase_size, erase_addr; + struct spi_nor *nor = mtd->priv; + u32 addr, len, erase_addr; u8 cmd[SNOR_MAX_CMD_SIZE]; + uint32_t rem; int ret = -1; - erase_size = nor->erase_size; - if (offset % erase_size || len % erase_size) { - debug("spi-nor: Erase offset/length not multiple of erase size\n"); - return -1; - } + div_u64_rem(instr->len, mtd->erasesize, &rem); + if (rem) + return -EINVAL; + + addr = instr->addr; + len = instr->len; - if (flash->flash_is_locked) { - if (flash->flash_is_locked(flash, offset, len) > 0) { + if (mtd->_is_locked) { + if (mtd->_is_locked(mtd, addr, len) > 0) { printf("offset 0x%x is protected and cannot be erased\n", - offset); + addr); return -EINVAL; } } - cmd[0] = flash->erase_opcode; + cmd[0] = nor->erase_opcode; while (len) { - erase_addr = offset; + erase_addr = addr; #ifdef CONFIG_SF_DUAL_FLASH if (nor->dual > SNOR_DUAL_SINGLE) @@ -498,39 +528,47 @@ static int spi_nor_erase(struct spi_flash *flash, u32 offset, size_t len) ret = nor->write(nor, cmd, sizeof(cmd), NULL, 0); if (ret < 0) - break; + goto erase_err; ret = spi_nor_wait_till_ready(nor, SNOR_READY_WAIT_ERASE); if (ret < 0) - return ret; + goto erase_err; - offset += erase_size; - len -= erase_size; + addr += mtd->erasesize; + len -= mtd->erasesize; } + write_disable(nor); + + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return ret; + +erase_err: + instr->state = MTD_ERASE_FAILED; return ret; } -int spi_nor_write(struct spi_flash *flash, u32 offset, - size_t len, const void *buf) +static int spi_nor_write(struct mtd_info *mtd, loff_t offset, size_t len, + size_t *retlen, const u_char *buf) { - struct spi_nor *nor = flash->nor; - unsigned long byte_addr, page_size; - u32 write_addr; + struct spi_nor *nor = mtd->priv; + u32 byte_addr, page_size, write_addr; size_t chunk_len, actual; u8 cmd[SNOR_MAX_CMD_SIZE]; int ret = -1; - page_size = nor->page_size; - - if (flash->flash_is_locked) { - if (flash->flash_is_locked(flash, offset, len) > 0) { - printf("offset 0x%x is protected and cannot be written\n", + if (mtd->_is_locked) { + if (mtd->_is_locked(mtd, offset, len) > 0) { + printf("offset 0x%llx is protected and cannot be written\n", offset); return -EINVAL; } } + page_size = nor->page_size; + cmd[0] = nor->program_opcode; for (actual = 0; actual < len; actual += chunk_len) { write_addr = offset; @@ -568,14 +606,16 @@ int spi_nor_write(struct spi_flash *flash, u32 offset, return ret; offset += chunk_len; + *retlen += chunk_len; } return ret; } -int spi_nor_read(struct spi_flash *flash, u32 offset, size_t len, void *data) +static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) { - struct spi_nor *nor = flash->nor; + struct spi_nor *nor = mtd->priv; u32 remain_len, read_len, read_addr; u8 *cmd, cmdsz; int bank_sel = 0; @@ -583,7 +623,7 @@ int spi_nor_read(struct spi_flash *flash, u32 offset, size_t len, void *data) /* Handle memory-mapped SPI */ if (nor->memory_map) { - ret = nor->read_mmap(nor, data, nor->memory_map + offset, len); + ret = nor->read_mmap(nor, buf, nor->memory_map + from, len); if (ret) { debug("spi-nor: mmap read failed\n"); return ret; @@ -601,7 +641,7 @@ int spi_nor_read(struct spi_flash *flash, u32 offset, size_t len, void *data) cmd[0] = nor->read_opcode; while (len) { - read_addr = offset; + read_addr = from; #ifdef CONFIG_SF_DUAL_FLASH if (nor->dual > SNOR_DUAL_SINGLE) @@ -614,7 +654,7 @@ int spi_nor_read(struct spi_flash *flash, u32 offset, size_t len, void *data) bank_sel = nor->bank_curr; #endif remain_len = ((SNOR_16MB_BOUN << nor->shift) * - (bank_sel + 1)) - offset; + (bank_sel + 1)) - from; if (len < remain_len) read_len = len; else @@ -622,13 +662,14 @@ int spi_nor_read(struct spi_flash *flash, u32 offset, size_t len, void *data) spi_nor_addr(read_addr, cmd); - ret = nor->read(nor, cmd, cmdsz, data, read_len); + ret = nor->read(nor, cmd, cmdsz, buf, read_len); if (ret < 0) break; - offset += read_len; + from += read_len; len -= read_len; - data += read_len; + buf += read_len; + *retlen += read_len; } free(cmd); @@ -636,7 +677,8 @@ int spi_nor_read(struct spi_flash *flash, u32 offset, size_t len, void *data) } #ifdef CONFIG_SPI_FLASH_SST -static int sst_byte_write(struct spi_nor *nor, u32 offset, const void *buf) +static int sst_byte_write(struct spi_nor *nor, u32 offset, + const void *buf, size_t *retlen) { int ret; u8 cmd[4] = { @@ -657,12 +699,15 @@ static int sst_byte_write(struct spi_nor *nor, u32 offset, const void *buf) if (ret) return ret; + *retlen += 1; + return spi_nor_wait_till_ready(nor, SNOR_READY_WAIT_PROG); } -int sst_write_wp(struct spi_nor *nor, u32 offset, size_t len, const void *buf) +static int sst_write_wp(struct mtd_info *mtd, loff_t offset, size_t len, + size_t *retlen, const u_char *buf) { - struct spi_nor *nor = flash->nor; + struct spi_nor *nor = mtd->priv; size_t actual, cmd_len; int ret; u8 cmd[4]; @@ -670,7 +715,7 @@ int sst_write_wp(struct spi_nor *nor, u32 offset, size_t len, const void *buf) /* If the data is not word aligned, write out leading single byte */ actual = offset % 2; if (actual) { - ret = sst_byte_write(nor, offset, buf); + ret = sst_byte_write(nor, offset, buf, retlen); if (ret) goto done; } @@ -687,7 +732,7 @@ int sst_write_wp(struct spi_nor *nor, u32 offset, size_t len, const void *buf) cmd[3] = offset; for (; actual < len - 1; actual += 2) { - debug("spi-nor: 0x%p => cmd = { 0x%02x 0x%06x }\n", + debug("spi-nor: 0x%p => cmd = { 0x%02x 0x%06llx }\n", buf + actual, cmd[0], offset); ret = nor->write(nor, cmd, cmd_len, buf + actual, 2); @@ -702,6 +747,7 @@ int sst_write_wp(struct spi_nor *nor, u32 offset, size_t len, const void *buf) cmd_len = 1; offset += 2; + *retlen += 2; } if (!ret) @@ -715,14 +761,15 @@ int sst_write_wp(struct spi_nor *nor, u32 offset, size_t len, const void *buf) return ret; } -int sst_write_bp(struct spi_nor *nor, u32 offset, size_t len, const void *buf) +static int sst_write_bp(struct mtd_info *mtd, loff_t offset, size_t len, + size_t *retlen, const u_char *buf) { - struct spi_nor *nor = flash->nor; + struct spi_nor *nor = mtd->priv; size_t actual; int ret; for (actual = 0; actual < len; actual++) { - ret = sst_byte_write(nor, offset, buf + actual); + ret = sst_byte_write(nor, offset, buf + actual, retlen); if (ret) { debug("spi-nor: sst byte program failed\n"); break; @@ -853,6 +900,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct spi_nor_info *info) #if CONFIG_IS_ENABLED(OF_CONTROL) int spi_nor_decode_fdt(const void *blob, struct spi_nor *nor) { + struct mtd_info *mtd = nor->mtd; fdt_addr_t addr; fdt_size_t size; int node; @@ -868,7 +916,7 @@ int spi_nor_decode_fdt(const void *blob, struct spi_nor *nor) return 0; } - if (flash->size != size) { + if (mtd->size != size) { debug("%s: Memory map must cover entire device\n", __func__); return -1; } @@ -891,6 +939,7 @@ static int spi_nor_check(struct spi_nor *nor) int spi_nor_scan(struct spi_nor *nor) { + struct mtd_info *mtd = nor->mtd; const struct spi_nor_info *info = NULL; static u8 flash_read_cmd[] = { SNOR_OP_READ, @@ -921,7 +970,13 @@ int spi_nor_scan(struct spi_nor *nor) write_sr(nor, 0); } - flash->name = info->name; + mtd->name = info->name; + mtd->priv = nor; + mtd->type = MTD_NORFLASH; + mtd->writesize = 1; + mtd->flags = MTD_CAP_NORFLASH; + mtd->_erase = spi_nor_erase; + mtd->_read = spi_nor_read; if (info->flags & USE_FSR) nor->flags |= SNOR_F_USE_FSR; @@ -929,15 +984,13 @@ int spi_nor_scan(struct spi_nor *nor) if (info->flags & SST_WRITE) nor->flags |= SNOR_F_SST_WRITE; - flash->write = spi_nor_write; - flash->erase = spi_nor_erase; - flash->read = spi_nor_read; + mtd->_write = spi_nor_write; #if defined(CONFIG_SPI_FLASH_SST) if (nor->flags & SNOR_F_SST_WRITE) { if (nor->mode & SNOR_WRITE_1_1_BYTE) - flash->write = sst_write_bp; + mtd->_write = sst_write_bp; else - flash->write = sst_write_wp; + mtd->_write = sst_write_wp; } #endif @@ -951,10 +1004,10 @@ int spi_nor_scan(struct spi_nor *nor) } #endif - if (flash->flash_lock && flash->flash_unlock && flash->flash_is_locked) { - flash->flash_lock = spi_nor_lock; - flash->flash_unlock = spi_nor_unlock; - flash->flash_is_locked = spi_nor_is_locked; + if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) { + mtd->_lock = spi_nor_lock; + mtd->_unlock = spi_nor_unlock; + mtd->_is_locked = spi_nor_is_locked; } /* Compute the flash size */ @@ -972,30 +1025,30 @@ int spi_nor_scan(struct spi_nor *nor) nor->page_size = 512; } nor->page_size <<= nor->shift; - flash->sector_size = info->sector_size << nor->shift; - flash->size = flash->sector_size * info->n_sectors << nor->shift; + mtd->writebufsize = nor->page_size; + mtd->size = (info->sector_size * info->n_sectors) << nor->shift; #ifdef CONFIG_SF_DUAL_FLASH if (nor->dual & SNOR_DUAL_STACKED) - flash->size <<= 1; + mtd->size <<= 1; #endif #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS /* prefer "small sector" erase if possible */ if (info->flags & SECT_4K) { nor->erase_opcode = SNOR_OP_BE_4K; - nor->erase_size = 4096 << nor->shift; + mtd->erasesize = 4096 << nor->shift; } else if (info->flags & SECT_4K_PMC) { nor->erase_opcode = SNOR_OP_BE_4K_PMC; - nor->erase_size = 4096; + mtd->erasesize = 4096; } else #endif { nor->erase_opcode = SNOR_OP_SE; - nor->erase_size = flash->sector_size; + mtd->erasesize = info->sector_size << nor->shift; } - /* Now erase size becomes valid sector size */ - flash->sector_size = nor->erase_size; + if (info->flags & SPI_NOR_NO_ERASE) + mtd->flags |= MTD_NO_ERASE; /* Look for the fastest read cmd */ cmd = fls(info->flash_read & nor->read_mode); @@ -1007,6 +1060,10 @@ int spi_nor_scan(struct spi_nor *nor) nor->read_opcode = SNOR_OP_READ_FAST; } + /* Some devices cannot do fast-read */ + if (info->flags & SPI_NOR_NO_FR) + nor->read_opcode = SNOR_OP_READ; + /* Not require to look for fastest only two write cmds yet */ if (info->flags & SNOR_WRITE_QUAD && nor->mode & SNOR_WRITE_1_1_4) nor->program_opcode = SNOR_OP_QPP; @@ -1061,10 +1118,10 @@ int spi_nor_scan(struct spi_nor *nor) #endif #ifndef CONFIG_SPL_BUILD - printf("spi-nor: detected %s with page size ", flash->name); + printf("spi-nor: detected %s with page size ", mtd->name); print_size(nor->page_size, ", erase size "); - print_size(nor->erase_size, ", total "); - print_size(flash->size, ""); + print_size(mtd->erasesize, ", total "); + print_size(mtd->size, ""); if (nor->memory_map) printf(", mapped at %p", nor->memory_map); puts("\n"); @@ -1072,9 +1129,9 @@ int spi_nor_scan(struct spi_nor *nor) #ifndef CONFIG_SPI_FLASH_BAR if (((nor->dual == SNOR_DUAL_SINGLE) && - (flash->size > SNOR_16MB_BOUN)) || + (mtd->size > SNOR_16MB_BOUN)) || ((nor->dual > SNOR_DUAL_SINGLE) && - (flash->size > SNOR_16MB_BOUN << 1))) { + (mtd->size > SNOR_16MB_BOUN << 1))) { puts("spi-nor: Warning - Only lower 16MiB accessible,"); puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); }