From patchwork Tue Feb 5 05:59:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vignesh Raghavendra X-Patchwork-Id: 1036445 X-Patchwork-Delegate: jagannadh.teki@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=ti.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ti.com header.i=@ti.com header.b="Xey9vzfu"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 43tvFn5vnxz9sN9 for ; Tue, 5 Feb 2019 17:05:49 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 5976FC21E68; Tue, 5 Feb 2019 06:03:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_DNSWL_BLOCKED, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 4B65EC21F16; Tue, 5 Feb 2019 06:00:44 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id BE192C21F5E; Tue, 5 Feb 2019 05:59:59 +0000 (UTC) Received: from lelv0143.ext.ti.com (lelv0143.ext.ti.com [198.47.23.248]) by lists.denx.de (Postfix) with ESMTPS id E6768C21ECC for ; Tue, 5 Feb 2019 05:59:55 +0000 (UTC) Received: from fllv0035.itg.ti.com ([10.64.41.0]) by lelv0143.ext.ti.com (8.15.2/8.15.2) with ESMTP id x155xkqB029717; Mon, 4 Feb 2019 23:59:46 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549346386; bh=cj6Nev5uqAyOymBcyQ+Oa0sf6BdssXfqUxJZZPDL4dI=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=Xey9vzfux0GQTXJkjaN8x4z68pII+wpYlC69607Ez6BgahWfgpmEsH5CX7xeJPgdT Bg/QybGNzap9p9af8likYZP8yNiv0Y237OnLwqljHstC2NV5VoWSGPVxUaTIvfqGh0 YkF6NyE6RWUAlX0kJ9Yp7aedq18rAqYhSl5Ur/po= Received: from DLEE114.ent.ti.com (dlee114.ent.ti.com [157.170.170.25]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x155xkqM082159 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 4 Feb 2019 23:59:46 -0600 Received: from DLEE113.ent.ti.com (157.170.170.24) by DLEE114.ent.ti.com (157.170.170.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 4 Feb 2019 23:59:46 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE113.ent.ti.com (157.170.170.24) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 4 Feb 2019 23:59:46 -0600 Received: from a0132425.india.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x155wVWF006226; Mon, 4 Feb 2019 23:59:41 -0600 From: Vignesh R To: Jagan Teki Date: Tue, 5 Feb 2019 11:29:21 +0530 Message-ID: <20190205055929.24168-13-vigneshr@ti.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190205055929.24168-1-vigneshr@ti.com> References: <20190205055929.24168-1-vigneshr@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Cc: Marek Vasut , Tom Rini , Stefan Roese , Nobuhiro Iwamatsu , Boris Brezillon , Michal Simek , u-boot@lists.denx.de, Rajat Srivastava , Miquel Raynal Subject: [U-Boot] [PATCH v4 12/20] mtd: spi: spi-nor-core: Add back U-Boot specific features X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" For legacy reasons, we will have to keep around U-Boot specific SPI_FLASH_BAR and SPI_TX_BYTE. Add them back to the new framework Signed-off-by: Vignesh R Reviewed-by: Jagan Teki Tested-by: Jagan Teki #zynq-microzed --- drivers/mtd/spi/spi-nor-core.c | 162 ++++++++++++++++++++++++++++++++- include/linux/mtd/spi-nor.h | 9 ++ 2 files changed, 168 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 2b39aaedead4..13c6236d623a 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -291,6 +291,7 @@ static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) return mtd->priv; } +#ifndef CONFIG_SPI_FLASH_BAR static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size) { size_t i; @@ -365,6 +366,7 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode); nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode); } +#endif /* !CONFIG_SPI_FLASH_BAR */ /* Enable/disable 4-byte addressing mode. */ static int set_4byte(struct spi_nor *nor, const struct flash_info *info, @@ -499,6 +501,79 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor) DEFAULT_READY_WAIT_JIFFIES); } +#ifdef CONFIG_SPI_FLASH_BAR +/* + * This "clean_bar" is necessary in a situation when one was accessing + * spi flash memory > 16 MiB by using Bank Address Register's BA24 bit. + * + * After it the BA24 bit shall be cleared to allow access to correct + * memory region after SW reset (by calling "reset" command). + * + * Otherwise, the BA24 bit may be left set and then after reset, the + * ROM would read/write/erase SPL from 16 MiB * bank_sel address. + */ +static int clean_bar(struct spi_nor *nor) +{ + u8 cmd, bank_sel = 0; + + if (nor->bank_curr == 0) + return 0; + cmd = nor->bank_write_cmd; + nor->bank_curr = 0; + write_enable(nor); + + return nor->write_reg(nor, cmd, &bank_sel, 1); +} + +static int write_bar(struct spi_nor *nor, u32 offset) +{ + u8 cmd, bank_sel; + int ret; + + bank_sel = offset / SZ_16M; + if (bank_sel == nor->bank_curr) + goto bar_end; + + cmd = nor->bank_write_cmd; + write_enable(nor); + ret = nor->write_reg(nor, cmd, &bank_sel, 1); + if (ret < 0) { + debug("SF: fail to write bank register\n"); + return ret; + } + +bar_end: + nor->bank_curr = bank_sel; + return nor->bank_curr; +} + +static int read_bar(struct spi_nor *nor, const struct flash_info *info) +{ + u8 curr_bank = 0; + int ret; + + switch (JEDEC_MFR(info)) { + case SNOR_MFR_SPANSION: + nor->bank_read_cmd = SPINOR_OP_BRRD; + nor->bank_write_cmd = SPINOR_OP_BRWR; + break; + default: + nor->bank_read_cmd = SPINOR_OP_RDEAR; + nor->bank_write_cmd = SPINOR_OP_WREAR; + } + + ret = nor->read_reg(nor, nor->bank_read_cmd, + &curr_bank, 1); + if (ret) { + debug("SF: fail to read bank addr register\n"); + return ret; + } + nor->bank_curr = curr_bank; + + return 0; +} +#endif + /* * Initiate the erasure of a single sector */ @@ -543,6 +618,11 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) len = instr->len; while (len) { +#ifdef CONFIG_SPI_FLASH_BAR + ret = write_bar(nor, addr); + if (ret < 0) + return ret; +#endif write_enable(nor); ret = spi_nor_erase_sector(nor, addr); @@ -557,9 +637,12 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) goto erase_err; } +erase_err: +#ifdef CONFIG_SPI_FLASH_BAR + ret = clean_bar(nor); +#endif write_disable(nor); -erase_err: return ret; } @@ -1144,8 +1227,23 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, while (len) { loff_t addr = from; + size_t read_len = len; - ret = nor->read(nor, addr, len, buf); +#ifdef CONFIG_SPI_FLASH_BAR + u32 remain_len; + + ret = write_bar(nor, addr); + if (ret < 0) + return log_ret(ret); + remain_len = (SZ_16M * (nor->bank_curr + 1)) - addr; + + if (len < remain_len) + read_len = len; + else + read_len = remain_len; +#endif + + ret = nor->read(nor, addr, read_len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ ret = -EIO; @@ -1162,18 +1260,49 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, ret = 0; read_err: +#ifdef CONFIG_SPI_FLASH_BAR + ret = clean_bar(nor); +#endif return ret; } #ifdef CONFIG_SPI_FLASH_SST +static int sst_write_byteprogram(struct spi_nor *nor, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + size_t actual; + int ret = 0; + + for (actual = 0; actual < len; actual++) { + nor->program_opcode = SPINOR_OP_BP; + + write_enable(nor); + /* write one byte. */ + ret = nor->write(nor, to, 1, buf + actual); + if (ret < 0) + goto sst_write_err; + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto sst_write_err; + to++; + } + +sst_write_err: + write_disable(nor); + return ret; +} + static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); + struct spi_slave *spi = nor->spi; size_t actual; int ret; dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); + if (spi->mode & SPI_TX_BYTE) + return sst_write_byteprogram(nor, to, len, retlen, buf); write_enable(nor); @@ -1271,6 +1400,11 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, page_remain = min_t(size_t, nor->page_size - page_offset, len - i); +#ifdef CONFIG_SPI_FLASH_BAR + ret = write_bar(nor, addr); + if (ret < 0) + return ret; +#endif write_enable(nor); ret = nor->write(nor, addr, page_remain, buf + i); if (ret < 0) @@ -1289,6 +1423,9 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, } write_err: +#ifdef CONFIG_SPI_FLASH_BAR + ret = clean_bar(nor); +#endif return ret; } @@ -2532,12 +2669,20 @@ int spi_nor_scan(struct spi_nor *nor) /* already configured from SFDP */ } else if (info->addr_width) { nor->addr_width = info->addr_width; - } else if (mtd->size > 0x1000000) { + } else if (mtd->size > SZ_16M) { +#ifndef CONFIG_SPI_FLASH_BAR /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || info->flags & SPI_NOR_4B_OPCODES) spi_nor_set_4byte_opcodes(nor, info); +#else + /* Configure the BAR - discover bank cmds and read current bank */ + nor->addr_width = 3; + ret = read_bar(nor, info); + if (ret < 0) + return ret; +#endif } else { nor->addr_width = 3; } @@ -2569,3 +2714,14 @@ int spi_nor_scan(struct spi_nor *nor) return 0; } + +/* U-Boot specific functions, need to extend MTD to support these */ +int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor) +{ + int sr = read_sr(nor); + + if (sr < 0) + return sr; + + return (sr >> 2) & 7; +} diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 507458a76076..88e80af57941 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -105,6 +105,7 @@ /* Used for Spansion flashes only. */ #define SPINOR_OP_BRWR 0x17 /* Bank register write */ +#define SPINOR_OP_BRRD 0x16 /* Bank register read */ #define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */ /* Used for Micron flashes only. */ @@ -256,6 +257,9 @@ struct flash_info; * @read_opcode: the read opcode * @read_dummy: the dummy needed by the read operation * @program_opcode: the program opcode + * @bank_read_cmd: Bank read cmd + * @bank_write_cmd: Bank write cmd + * @bank_curr: Current flash bank * @sst_write_second: used by the SST write operation * @flags: flag options for the current SPI-NOR (SNOR_F_*) * @read_proto: the SPI protocol for read operations @@ -291,6 +295,11 @@ struct spi_nor { u8 read_opcode; u8 read_dummy; u8 program_opcode; +#ifdef CONFIG_SPI_FLASH_BAR + u8 bank_read_cmd; + u8 bank_write_cmd; + u8 bank_curr; +#endif enum spi_nor_protocol read_proto; enum spi_nor_protocol write_proto; enum spi_nor_protocol reg_proto;