From patchwork Thu Jul 12 17:32:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tudor Ambarus X-Patchwork-Id: 943142 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.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=microchip.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="fujNqwT2"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41RNMb48Vnz9ryt for ; Fri, 13 Jul 2018 03:33:47 +1000 (AEST) 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=RBjmFPsUrGbiI77z6Ta2MC+kGeqqB8+SyYHFJmcaHyU=; b=fujNqwT2eMghZQ kmG9//O0l1cXzcU5A8QYqS6800JrkNxpdPfdMDa2j6axcWhaB6sM4vZY+T+mqCwGlp8S8hLMqNVRT RiFeahsLYTpodwwIbZ15/GbWv7jC2zcRYlyB6nzQeddCZQsf3LSsALGFFolG6KY+JHOdbS5tS4RG3 /tUNo3G65L28ASEGz2KHBGhZNTt4kcivcecCJPkoGf9ynEVdGkw5EN6P5PpiZY7RIRUra4G3gnE0b /qkpuKHNHXV8OQsV3gDD4RTNeVbZ4SA6eE5CLbxJf1XBA8X3h7gXhN7ljBkUzEvACdGGfbEHrToZS 0mo5hhkZCk+7RImETt7A==; 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 1fdfTL-0004xu-Rg; Thu, 12 Jul 2018 17:33:43 +0000 Received: from esa1.microchip.iphmx.com ([68.232.147.91]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fdfSu-0004D8-Fh; Thu, 12 Jul 2018 17:33:32 +0000 X-IronPort-AV: E=Sophos;i="5.51,344,1526367600"; d="scan'208";a="16975547" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/DHE-RSA-AES256-SHA; 12 Jul 2018 10:32:57 -0700 Received: from localhost.localdomain.com (10.10.76.4) by chn-sv-exch06.mchp-main.com (10.10.76.107) with Microsoft SMTP Server id 14.3.352.0; Thu, 12 Jul 2018 10:32:56 -0700 From: Tudor Ambarus To: , , , , , Subject: [PATCH v2 3/3] mtd: spi-nor: parse SFDP 4-byte Address Instruction Table Date: Thu, 12 Jul 2018 20:32:35 +0300 Message-ID: <20180712173235.7901-4-tudor.ambarus@microchip.com> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20180712173235.7901-1-tudor.ambarus@microchip.com> References: <20180712173235.7901-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-20180712_103317_238141_0B210ADF X-CRM114-Status: GOOD ( 14.66 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [68.232.147.91 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Tudor Ambarus , linux-kernel@vger.kernel.org, nicolas.ferre@microchip.com, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, Cristian.Birsan@microchip.com Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org 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 7c6291c..74f9b46 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; }