From patchwork Thu Dec 8 12:41:37 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cyrille Pitchen X-Patchwork-Id: 9466353 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id C39436071E for ; Thu, 8 Dec 2016 12:46:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B860828526 for ; Thu, 8 Dec 2016 12:46:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AA03728537; Thu, 8 Dec 2016 12:46:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1CE5C28526 for ; Thu, 8 Dec 2016 12:46:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752316AbcLHMqi (ORCPT ); Thu, 8 Dec 2016 07:46:38 -0500 Received: from smtpout.microchip.com ([198.175.253.82]:42769 "EHLO email.microchip.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751702AbcLHMqf (ORCPT ); Thu, 8 Dec 2016 07:46:35 -0500 Received: from tenerife.corp.atmel.com (10.10.76.4) by chn-sv-exch05.mchp-main.com (10.10.76.106) with Microsoft SMTP Server id 14.3.181.6; Thu, 8 Dec 2016 05:42:57 -0700 From: Cyrille Pitchen To: CC: , , , , , , , Cyrille Pitchen Subject: [PATCH v2 2/2] mtd: spi-nor: add a stateless method to support memory size above 128Mib Date: Thu, 8 Dec 2016 13:41:37 +0100 Message-ID: <1362ba746fee8d8ad359d4fd67d2d6d8fd544a57.1481200454.git.cyrille.pitchen@atmel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: MIME-Version: 1.0 X-Brightmail-Tracker: H4sIAAAAAAAAC+NgFtrGrMTGxcLF5cOiGxTqGWHQ0PB+P4fF9Xn7mC06pqxisrh/7TSLxYb2tUwW9z5tY3RgDWCIYs3MS8qvSGDNuLbgHmPBPoWKZzevsTUwLpPqYuTiEBJYxyhx/tRr1i5GTg42AUOJtw+OgtkiApISG05cYAQpYhb4xSgxse8nC0hCWCBBovPNTTYQm0VAReLcxndgcV6BeIkVz9eyg9gSAnISN891MoPYnAK2Eo9nfAIbKiRgI/Hm/2tmiHpBiZMzn4D1MgtISBx88YIZokZNYmHLCmaIOYESk/oOM0HYThI7l09lgbDtJA5Pvwi1y0Fi6e857DA17UvfsELY2hLbX+2DsnUkth3sh+q1ldgzYyLUTHeJB4+WQ9m+ErMeNkDVREm8nXeKZQKjxCwkp85CcuoCRqZVjNLOHn66wWG6rhHOHgamernJGQW6uYmZeXrJ+bmbGCERlbWDsXeSv1QD44yJUdmp35e8PlRwu7yyp3xFs1fkbANZvnOXLyxZtvLWygN+xnIFl7qTNuzPdfQ7Nqn3xY/5r9Tf/b199vICxb12TUklf/8+F31ituZESNCeuaGtnncFvs/unaFkqa2n4rr6zsbSzlPpO/U8+dN3Cm76IJW1NNrVV0SwK6tjduXsxfoN1dw5q5VYijMSDbWYi4oTAYR9q3NJAgAA Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch provides an alternative mean to support memory above 16MiB (128Mib) by replacing 3byte address op codes by their associated 4byte address versions. Using the dedicated 4byte address op codes doesn't change the internal state of the SPI NOR memory as opposed to using other means such as updating a Base Address Register (BAR) and sending command to enter/leave the 4byte mode. Hence when a CPU reset occurs, early bootloaders don't need to be aware of BAR value or 4byte mode being enabled: they can still access the first 16MiB of the SPI NOR memory using the regular 3byte address op codes. Signed-off-by: Cyrille Pitchen Tested-by: Vignesh R --- drivers/mtd/spi-nor/spi-nor.c | 78 +++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 8abe134e174a..40b78ebb9900 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -75,6 +75,10 @@ struct flash_info { * bit. Must be used with * SPI_NOR_HAS_LOCK. */ +#define SPI_NOR_4B_OPCODES BIT(10) /* + * Use dedicated 4byte address op codes + * to support memory size above 128Mib. + */ }; #define JEDEC_MFR(info) ((info)->id[0]) @@ -188,6 +192,55 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) return mtd->priv; } + +static u8 spi_nor_3to4_opcode(u8 opcode) +{ +#define ENTRY_3TO4(_opcode) { _opcode, _opcode##_4B } + static const u8 spi_nor_3to4_table[][2] = { + ENTRY_3TO4(SPINOR_OP_READ), + ENTRY_3TO4(SPINOR_OP_READ_FAST), + ENTRY_3TO4(SPINOR_OP_READ_1_1_2), + ENTRY_3TO4(SPINOR_OP_READ_1_2_2), + ENTRY_3TO4(SPINOR_OP_READ_1_1_4), + ENTRY_3TO4(SPINOR_OP_READ_1_4_4), + ENTRY_3TO4(SPINOR_OP_PP), + ENTRY_3TO4(SPINOR_OP_PP_1_1_4), + ENTRY_3TO4(SPINOR_OP_PP_1_4_4), + ENTRY_3TO4(SPINOR_OP_BE_4K), + ENTRY_3TO4(SPINOR_OP_BE_32K), + ENTRY_3TO4(SPINOR_OP_SE), + }; +#undef ENTRY_3TO4 + size_t i; + + for (i = 0; i < ARRAY_SIZE(spi_nor_3to4_table); ++i) + if (spi_nor_3to4_table[i][0] == opcode) + return spi_nor_3to4_table[i][1]; + + /* No conversion found, keep input op code. */ + return opcode; +} + +static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, + const struct flash_info *info) +{ + /* Do some manufacturer fixups first */ + switch (JEDEC_MFR(info)) { + case SNOR_MFR_SPANSION: + /* No small sector erase for 4-byte command set */ + nor->erase_opcode = SPINOR_OP_SE; + nor->mtd.erasesize = info->sector_size; + break; + + default: + break; + } + + nor->read_opcode = spi_nor_3to4_opcode(nor->read_opcode); + nor->program_opcode = spi_nor_3to4_opcode(nor->program_opcode); + nor->erase_opcode = spi_nor_3to4_opcode(nor->erase_opcode); +} + /* Enable/disable 4-byte addressing mode. */ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, int enable) @@ -1486,27 +1539,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) else if (mtd->size > 0x1000000) { /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; - if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) { - /* Dedicated 4-byte command set */ - switch (nor->flash_read) { - case SPI_NOR_QUAD: - nor->read_opcode = SPINOR_OP_READ_1_1_4_4B; - break; - case SPI_NOR_DUAL: - nor->read_opcode = SPINOR_OP_READ_1_1_2_4B; - break; - case SPI_NOR_FAST: - nor->read_opcode = SPINOR_OP_READ_FAST_4B; - break; - case SPI_NOR_NORMAL: - nor->read_opcode = SPINOR_OP_READ_4B; - break; - } - nor->program_opcode = SPINOR_OP_PP_4B; - /* No small sector erase for 4-byte command set */ - nor->erase_opcode = SPINOR_OP_SE_4B; - mtd->erasesize = info->sector_size; - } else + if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || + info->flags & SPI_NOR_4B_OPCODES) + spi_nor_set_4byte_opcodes(nor, info); + else set_4byte(nor, info, 1); } else { nor->addr_width = 3;