From patchwork Tue Oct 4 16:37:09 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cyrille Pitchen X-Patchwork-Id: 678164 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2001:1868:205::9]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3spPm000dDz9t0t for ; Wed, 5 Oct 2016 03:40:16 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1brSj7-0001A9-8f; Tue, 04 Oct 2016 16:37:57 +0000 Received: from exsmtp01.microchip.com ([198.175.253.37] helo=email.microchip.com) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1brSiO-0000Gw-D4 for linux-mtd@lists.infradead.org; Tue, 04 Oct 2016 16:37:15 +0000 Received: from tenerife.corp.atmel.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.181.6; Tue, 4 Oct 2016 09:36:37 -0700 From: Cyrille Pitchen To: , Subject: [PATCH 7/9] mtd: spi-nor: parse SFDP 4-byte Address Instruction Table Date: Tue, 4 Oct 2016 18:37:09 +0200 Message-ID: <72325c04339d456b1702404e7c70ade4693a5cfc.1475597385.git.cyrille.pitchen@atmel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161004_093712_731685_97CBA504 X-CRM114-Status: GOOD ( 17.18 ) X-Spam-Score: -1.2 (-) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-1.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [198.175.253.37 listed in list.dnswl.org] 0.7 SPF_SOFTFAIL SPF: sender does not match SPF record (softfail) -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: marex@denx.de, boris.brezillon@free-electrons.com, Cyrille Pitchen , nicolas.ferre@atmel.com, linux-kernel@vger.kernel.org Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org This patch adds supports for SFDP (JESD216B) 4-byte Address Instruction Table. This table is optional but when available, we parse it to get the 4-byte address op codes supported by the memory. Using these op codes is stateless as opposed to entering the 4-byte address mode or setting the Base Address Register (BAR). Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 140 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index e91b3c39b68e..879b98ef1d80 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1481,6 +1481,7 @@ struct sfdp_parameter_header { #define SFDP_BFPT_ID 0xff00u /* Basic Flash Parameter Table */ +#define SFDP_4BAIT_ID 0xff84u /* 4-byte Address Instruction Table */ #define SFDP_SIGNATURE 0x50444653u #define SFDP_JESD216_MAJOR 1 @@ -1728,6 +1729,124 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, return 0; } +struct sfdp_4bait { + enum spi_nor_protocol_index pindex; + int wbit; +}; + +static int spi_nor_parse_4bait(struct spi_nor *nor, + const struct sfdp_parameter_header *param_header, + struct spi_nor_basic_flash_parameter *params) +{ + static const struct sfdp_4bait reads[] = { + {SNOR_PINDEX_SLOW, 0}, /* 0x13 */ + {SNOR_PINDEX_1_1_1, 1}, /* 0x0c */ + {SNOR_PINDEX_1_1_2, 2}, /* 0x3c */ + {SNOR_PINDEX_1_2_2, 3}, /* 0xbc */ + {SNOR_PINDEX_1_1_4, 4}, /* 0x6c */ + {SNOR_PINDEX_1_4_4, 5}, /* 0xec */ + }; + static const struct sfdp_4bait programs[] = { + {SNOR_PINDEX_1_1_1, 6}, /* 0x12 */ + {SNOR_PINDEX_1_1_4, 7}, /* 0x34 */ + {SNOR_PINDEX_1_4_4, 8}, /* 0x3e */ + }; + static const struct sfdp_4bait erases[SNOR_MAX_ERASE_TYPES] = { + {SNOR_PINDEX_1_1_1, 9}, + {SNOR_PINDEX_1_1_1, 10}, + {SNOR_PINDEX_1_1_1, 11}, + {SNOR_PINDEX_1_1_1, 12}, + }; + u32 word[2], addr, rd_modes, wr_modes, erase_modes; + int i, err; + + if (param_header->major != SFDP_JESD216_MAJOR || + param_header->length < 2) + return -EINVAL; + + /* Read the 4-byte Address Instruction Table. */ + addr = SFDP_PARAM_HEADER_PTP(param_header); + err = spi_nor_read_sfdp(nor, addr, sizeof(word), word); + if (err) + return err; + + for (i = 0; i < 2; ++i) + word[i] = le32_to_cpu(word[i]); + + /* + * Compute the subset of (Fast) Read commands for which the 4-byte + * version is supported. + */ + rd_modes = 0; + for (i = 0; i < ARRAY_SIZE(reads); ++i) { + const struct sfdp_4bait *read = &reads[i]; + + if ((params->rd_modes & BIT(read->pindex)) && + (word[0] & BIT(read->wbit))) + rd_modes |= BIT(read->pindex); + } + + /* + * Compute the subset of Page Program commands for which the 4-byte + * version is supported. + */ + wr_modes = 0; + for (i = 0; i < ARRAY_SIZE(programs); ++i) { + const struct sfdp_4bait *program = &programs[i]; + + if ((params->wr_modes & BIT(program->pindex)) && + (word[0] & BIT(program->wbit))) + wr_modes |= BIT(program->pindex); + } + + /* + * Compute the subet of Sector Erase commands for which the 4-byte + * version is supported. + */ + erase_modes = 0; + for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) { + const struct sfdp_4bait *erase = &erases[i]; + + if ((params->erase_types[i].size > 0) && + (word[0] & BIT(erase->wbit))) + erase_modes |= BIT(i); + } + + /* + * We need at least one 4-byte op code per read, program and erase + * operation; the .read(), .write() and .erase() hooks share the + * nor->addr_width value. + */ + if (!rd_modes || !wr_modes || !erase_modes) + return 0; + + /* + * Discard all operations from the 4-byte instruction set which are + * not supported by this memory. + */ + params->rd_modes = rd_modes; + params->wr_modes = wr_modes; + for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) + if (!(erase_modes & BIT(i))) + params->erase_types[i].size = 0; + + /* Use the 4-byte address instruction set. */ + params->reads[SNOR_PINDEX_SLOW].opcode = SPINOR_OP_READ_4B; + params->reads[SNOR_PINDEX_1_1_1].opcode = SPINOR_OP_READ_FAST_4B; + params->reads[SNOR_PINDEX_1_1_2].opcode = SPINOR_OP_READ_1_1_2_4B; + params->reads[SNOR_PINDEX_1_2_2].opcode = SPINOR_OP_READ_1_2_2_4B; + params->reads[SNOR_PINDEX_1_1_4].opcode = SPINOR_OP_READ_1_1_4_4B; + params->reads[SNOR_PINDEX_1_4_4].opcode = SPINOR_OP_READ_1_4_4_4B; + params->page_programs[SNOR_PINDEX_1_1_1] = SPINOR_OP_PP_4B; + params->page_programs[SNOR_PINDEX_1_1_4] = SPINOR_OP_PP_1_1_4_4B; + params->page_programs[SNOR_PINDEX_1_4_4] = SPINOR_OP_PP_1_4_4_4B; + for (i = 0; i < SNOR_MAX_ERASE_TYPES; ++i) + params->erase_types[i].opcode = (word[1] >> (i * 8)) & 0xff; + + nor->addr_width = 4; + return 0; +} + static int spi_nor_parse_sfdp(struct spi_nor *nor, struct spi_nor_basic_flash_parameter *params) { @@ -1795,6 +1914,23 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, if (err) goto exit; + /* Parse other parameter headers. */ + for (i = 0; i < header.nph; ++i) { + param_header = ¶m_headers[i]; + + switch (SFDP_PARAM_HEADER_ID(param_header)) { + case SFDP_4BAIT_ID: + err = spi_nor_parse_4bait(nor, param_header, params); + break; + + default: + break; + } + + if (err) + goto exit; + } + exit: kfree(param_headers); return (err) ? err : bfpt_header->minor; @@ -2149,7 +2285,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; - if (info->addr_width) + if (nor->addr_width) + ; /* already configured by spi_nor_setup(). */ + else if (info->addr_width) nor->addr_width = info->addr_width; else if (mtd->size > 0x1000000) { /* enable 4-byte addressing if the device exceeds 16MiB */