From patchwork Mon Aug 27 10:26:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tudor Ambarus X-Patchwork-Id: 10576889 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C50BD920 for ; Mon, 27 Aug 2018 10:30:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AF8D2296FF for ; Mon, 27 Aug 2018 10:30:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A413429714; Mon, 27 Aug 2018 10:30:27 +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=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id DE80A296FF for ; Mon, 27 Aug 2018 10:30:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Mvy0fm4mitG+XcLEMA0sNLafEMPMDzV7OmyFX8//WOo=; b=e+b1ni8gm3kbvt B7049tM/EIxkUCJTYcWChwwr04fvcLPA05AOsHfB0hSZraQ80FZEBqGEJUxvl4/vIJIGrGpCI9qzq DV54FZQWaX1Gx8xVdSRTKvHsz0cMAypHPBU92jys4iDPpnebrSmnA+YHGade0cQ7N1rb/6qzrCALI UwrE3frrYXm9Hf6iiyLrBizxvLtu6ETa+dlhRAbIxlYU/lWTKdLvA77axWqBTENLTWhbmaj725wFD eTkQzfTs72CRRHs7ViP2OfhKs9Bk4OyGbhItU2ENYmZWwj1KEv2Mg3IiqfXJuJRD3nJiT8ZCfWdpE bILLs19+NBJWMipqanHw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fuEmn-0005bK-7s; Mon, 27 Aug 2018 10:30:17 +0000 Received: from esa4.microchip.iphmx.com ([68.232.154.123]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fuEjh-0003Vk-QU; Mon, 27 Aug 2018 10:27:07 +0000 X-IronPort-AV: E=Sophos;i="5.53,294,1531810800"; d="scan'208";a="18441297" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/DHE-RSA-AES256-SHA; 27 Aug 2018 03:26:59 -0700 Received: from localhost.localdomain.com (10.10.76.4) by chn-sv-exch04.mchp-main.com (10.10.76.105) with Microsoft SMTP Server id 14.3.352.0; Mon, 27 Aug 2018 03:26:59 -0700 From: Tudor Ambarus To: , , , , , Subject: [RESEND PATCH v2 3/3] mtd: spi-nor: parse SFDP 4-byte Address Instruction Table Date: Mon, 27 Aug 2018 13:26:44 +0300 Message-ID: <20180827102644.7323-4-tudor.ambarus@microchip.com> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20180827102644.7323-1-tudor.ambarus@microchip.com> References: <20180827102644.7323-1-tudor.ambarus@microchip.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180827_032705_915511_6F467619 X-CRM114-Status: GOOD ( 14.03 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Tudor Ambarus , linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, Cristian.Birsan@microchip.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Cyrille Pitchen Add support 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 Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spi-nor.c | 148 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 522d5aa..4e69d47 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2196,6 +2196,7 @@ struct sfdp_parameter_header { #define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ #define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ +#define SFDP_4BAIT_ID 0xff84u /* 4-byte Address Instruction Table */ #define SFDP_SIGNATURE 0x50444653U #define SFDP_JESD216_MAJOR 1 @@ -2883,6 +2884,149 @@ static int spi_nor_parse_smpt(struct spi_nor *nor, return ret; } +struct sfdp_4bait { + /* The hardware capability. */ + u32 hwcaps; + + /* + * The bit in DWORD1 of the 4BAIT tells us whether + * the associated 4-byte address op code is supported. + */ + u32 supported_bit; +}; + +static int spi_nor_parse_4bait(struct spi_nor *nor, + const struct sfdp_parameter_header *param_header, + struct spi_nor_flash_parameter *params) +{ + static const struct sfdp_4bait reads[] = { + { SNOR_HWCAPS_READ, BIT(0) }, + { SNOR_HWCAPS_READ_FAST, BIT(1) }, + { SNOR_HWCAPS_READ_1_1_2, BIT(2) }, + { SNOR_HWCAPS_READ_1_2_2, BIT(3) }, + { SNOR_HWCAPS_READ_1_1_4, BIT(4) }, + { SNOR_HWCAPS_READ_1_4_4, BIT(5) }, + { SNOR_HWCAPS_READ_1_1_1_DTR, BIT(13) }, + { SNOR_HWCAPS_READ_1_2_2_DTR, BIT(14) }, + { SNOR_HWCAPS_READ_1_4_4_DTR, BIT(15) }, + }; + static const struct sfdp_4bait programs[] = { + { SNOR_HWCAPS_PP, BIT(6) }, + { SNOR_HWCAPS_PP_1_1_4, BIT(7) }, + { SNOR_HWCAPS_PP_1_4_4, BIT(8) }, + }; + static const struct sfdp_4bait erases[SNOR_ERASE_TYPE_MAX] = { + { 0u /* not used */, BIT(9) }, + { 0u /* not used */, BIT(10) }, + { 0u /* not used */, BIT(11) }, + { 0u /* not used */, BIT(12) }, + }; + u32 dwords[2], addr, discard_hwcaps, read_hwcaps, pp_hwcaps, erase_mask; + struct spi_nor_erase_map *map = &nor->erase_map; + int i, err; + + if (param_header->major != SFDP_JESD216_MAJOR || + param_header->length < ARRAY_SIZE(dwords)) + return -EINVAL; + + /* Read the 4-byte Address Instruction Table. */ + addr = SFDP_PARAM_HEADER_PTP(param_header); + err = spi_nor_read_sfdp(nor, addr, sizeof(dwords), dwords); + if (err) + return err; + + /* Fix endianness of the 4BAIT DWORDs. */ + for (i = 0; i < ARRAY_SIZE(dwords); i++) + dwords[i] = le32_to_cpu(dwords[i]); + + /* + * Compute the subset of (Fast) Read commands for which the 4-byte + * version is supported. + */ + discard_hwcaps = 0; + read_hwcaps = 0; + for (i = 0; i < ARRAY_SIZE(reads); i++) { + const struct sfdp_4bait *read = &reads[i]; + + discard_hwcaps |= read->hwcaps; + if ((params->hwcaps.mask & read->hwcaps) && + (dwords[0] & read->supported_bit)) + read_hwcaps |= read->hwcaps; + } + + /* + * Compute the subset of Page Program commands for which the 4-byte + * version is supported. + */ + pp_hwcaps = 0; + for (i = 0; i < ARRAY_SIZE(programs); i++) { + const struct sfdp_4bait *program = &programs[i]; + + discard_hwcaps |= program->hwcaps; + if ((params->hwcaps.mask & program->hwcaps) && + (dwords[0] & program->supported_bit)) + pp_hwcaps |= program->hwcaps; + } + + /* + * Compute the subet of Sector Erase commands for which the 4-byte + * version is supported. + */ + erase_mask = 0; + for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) { + const struct sfdp_4bait *erase = &erases[i]; + + if (map->erase_type[i].size > 0 && + (dwords[0] & erase->supported_bit)) + erase_mask |= 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 (!read_hwcaps || !pp_hwcaps || !erase_mask) + return 0; + + /* + * Discard all operations from the 4-byte instruction set which are + * not supported by this memory. + */ + params->hwcaps.mask &= ~discard_hwcaps; + params->hwcaps.mask |= (read_hwcaps | pp_hwcaps); + + /* Use the 4-byte address instruction set. */ + for (i = 0; i < SNOR_CMD_READ_MAX; i++) { + struct spi_nor_read_command *read_cmd = ¶ms->reads[i]; + + read_cmd->opcode = spi_nor_convert_3to4_read(read_cmd->opcode); + } + for (i = 0; i < SNOR_CMD_PP_MAX; i++) { + struct spi_nor_pp_command *pp_cmd = ¶ms->page_programs[i]; + + pp_cmd->opcode = spi_nor_convert_3to4_program(pp_cmd->opcode); + } + for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) { + struct spi_nor_erase_type *erase = &map->erase_type[i]; + + if (erase_mask & BIT(erase->idx)) + erase->opcode = (dwords[1] >> (erase->idx * 8)) & 0xFF; + else + spi_nor_set_erase_type(erase, 0u, 0xFF); + } + + /* + * We set nor->addr_width here to skip spi_nor_set_4byte_opcodes() + * later because this latest function implements a legacy quirk for + * the erase size of Spansion memory. However this quirk is no longer + * needed with new SFDP compliant memories. + */ + nor->addr_width = 4; + nor->flags |= SPI_NOR_4B_OPCODES; + return 0; +} + /** * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' @@ -2980,6 +3124,10 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, err = spi_nor_parse_smpt(nor, param_header); break; + case SFDP_4BAIT_ID: + err = spi_nor_parse_4bait(nor, param_header, params); + break; + default: break; }