From patchwork Mon Mar 30 15:45:41 2020
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Pratyush Yadav
X-Patchwork-Id: 1264031
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=pass (sender SPF authorized)
smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61;
helo=phobos.denx.de;
envelope-from=u-boot-bounces@lists.denx.de;
receiver=)
Authentication-Results: ozlabs.org; dmarc=pass (p=quarantine dis=none)
header.from=ti.com
Authentication-Results: ozlabs.org; dkim=pass (1024-bit key;
unprotected) header.d=ti.com header.i=@ti.com header.a=rsa-sha256
header.s=ti-com-17Q1 header.b=h5KErUck;
dkim-atps=neutral
Received: from phobos.denx.de (phobos.denx.de [85.214.62.61])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (4096 bits))
(No client certificate requested)
by ozlabs.org (Postfix) with ESMTPS id 48rcLD40hDz9sPk
for ;
Tue, 31 Mar 2020 02:48:04 +1100 (AEDT)
Received: from h2850616.stratoserver.net (localhost [IPv6:::1])
by phobos.denx.de (Postfix) with ESMTP id 2292381930;
Mon, 30 Mar 2020 17:46:41 +0200 (CEST)
Authentication-Results: phobos.denx.de; dmarc=pass (p=quarantine dis=none)
header.from=ti.com
Authentication-Results: phobos.denx.de;
spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de
Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key;
unprotected) header.d=ti.com header.i=@ti.com header.b="h5KErUck";
dkim-atps=neutral
Received: by phobos.denx.de (Postfix, from userid 109)
id 1461B818F1; Mon, 30 Mar 2020 17:46:18 +0200 (CEST)
X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de
X-Spam-Level:
X-Spam-Status: No, score=-2.2 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED
autolearn=ham autolearn_force=no version=3.4.2
Received: from lelv0142.ext.ti.com (lelv0142.ext.ti.com [198.47.23.249])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256
bits)) (No client certificate requested)
by phobos.denx.de (Postfix) with ESMTPS id 1719F818FC
for ; Mon, 30 Mar 2020 17:46:11 +0200 (CEST)
Authentication-Results: phobos.denx.de;
dmarc=pass (p=quarantine dis=none) header.from=ti.com
Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=p.yadav@ti.com
Received: from lelv0265.itg.ti.com ([10.180.67.224])
by lelv0142.ext.ti.com (8.15.2/8.15.2) with ESMTP id 02UFkAx3089109;
Mon, 30 Mar 2020 10:46:10 -0500
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com;
s=ti-com-17Q1; t=1585583170;
bh=csGkKwpXt7C0vy3/wk3GjBepVbz4M9Bl1791uM1WcHw=;
h=From:To:CC:Subject:Date:In-Reply-To:References;
b=h5KErUck+vR5mSOfAPGorPBvrY3qCeMKGKFPat7VStW4XUxKnfzzxGgtgfIG+bvGl
+rWQbh9pD3KEcQ1X4Qao9eifFaAJ1Y6DiqTnKX4KH/98ITgMdmiB1JH77Eh4CR4a3n
oS8WnCYbjYcFNEHarD9arivkglaYoqwVT3teK3rg=
Received: from DFLE111.ent.ti.com (dfle111.ent.ti.com [10.64.6.32])
by lelv0265.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 02UFkAQh019509
(version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL);
Mon, 30 Mar 2020 10:46:10 -0500
Received: from DFLE115.ent.ti.com (10.64.6.36) by DFLE111.ent.ti.com
(10.64.6.32) with Microsoft SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1847.3;
Mon, 30 Mar 2020 10:46:10 -0500
Received: from lelv0326.itg.ti.com (10.180.67.84) by DFLE115.ent.ti.com
(10.64.6.36) with Microsoft SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1847.3 via
Frontend Transport; Mon, 30 Mar 2020 10:46:09 -0500
Received: from pratyush-OptiPlex-790.dhcp.ti.com (ileax41-snat.itg.ti.com
[10.172.224.153])
by lelv0326.itg.ti.com (8.15.2/8.15.2) with ESMTP id 02UFjpAq044920;
Mon, 30 Mar 2020 10:46:08 -0500
From: Pratyush Yadav
To: Jagan Teki , Vignesh Raghavendra
CC: Pratyush Yadav , , Sekhar Nori
Subject: [PATCH v3 08/17] mtd: spi-nor-core: Rework hwcaps selection
Date: Mon, 30 Mar 2020 21:15:41 +0530
Message-ID: <20200330154550.21179-9-p.yadav@ti.com>
X-Mailer: git-send-email 2.25.0
In-Reply-To: <20200330154550.21179-1-p.yadav@ti.com>
References: <20200330154550.21179-1-p.yadav@ti.com>
MIME-Version: 1.0
X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180
X-BeenThere: u-boot@lists.denx.de
X-Mailman-Version: 2.1.30rc1
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"
X-Virus-Scanned: clamav-milter 0.102.2 at phobos.denx.de
X-Virus-Status: Clean
The spi-mem layer provides a spi_mem_supports_op() function to check
whether a specific operation is supported by the controller or not.
This is much more accurate than the hwcaps selection logic based on
SPI_{RX,TX}_ flags.
Rework the hwcaps selection logic to use spi_mem_supports_op() when
nor->spimem != NULL.
Based on the Linux commit c76f5089796a (mtd: spi-nor: Rework hwcaps
selection for the spi-mem case, 2019-08-06)
Based-on-patch-by: Boris Brezillon
Signed-off-by: Pratyush Yadav
---
drivers/mtd/spi/spi-nor-core.c | 168 +++++++++++++++++++++++++--------
include/linux/mtd/spi-nor.h | 14 +++
2 files changed, 144 insertions(+), 38 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 88b19978ed..f324d3c483 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2285,6 +2285,124 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
ARRAY_SIZE(hwcaps_pp2cmd));
}
+/**
+ * spi_nor_check_op - check if the operation is supported by controller
+ * @nor: pointer to a 'struct spi_nor'
+ * @op: pointer to op template to be checked
+ *
+ * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ */
+static int spi_nor_check_op(struct spi_nor *nor,
+ struct spi_mem_op *op)
+{
+ /*
+ * First test with 4 address bytes. The opcode itself might be a 3B
+ * addressing opcode but we don't care, because SPI controller
+ * implementation should not check the opcode, but just the sequence.
+ */
+ op->addr.nbytes = 4;
+ if (!spi_mem_supports_op(nor->spi, op)) {
+ if (nor->mtd.size > SZ_16M)
+ return -ENOTSUPP;
+
+ /* If flash size <= 16MB, 3 address bytes are sufficient */
+ op->addr.nbytes = 3;
+ if (!spi_mem_supports_op(nor->spi, op))
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+/**
+ * spi_nor_check_readop - check if the read op is supported by controller
+ * @nor: pointer to a 'struct spi_nor'
+ * @read: pointer to op template to be checked
+ *
+ * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ */
+static int spi_nor_check_readop(struct spi_nor *nor,
+ const struct spi_nor_read_command *read)
+{
+ struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 1),
+ SPI_MEM_OP_ADDR(3, 0, 1),
+ SPI_MEM_OP_DUMMY(0, 1),
+ SPI_MEM_OP_DATA_IN(0, NULL, 1));
+
+ op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(read->proto);
+ op.addr.buswidth = spi_nor_get_protocol_addr_nbits(read->proto);
+ op.data.buswidth = spi_nor_get_protocol_data_nbits(read->proto);
+ op.dummy.buswidth = op.addr.buswidth;
+ op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) *
+ op.dummy.buswidth / 8;
+
+ return spi_nor_check_op(nor, &op);
+}
+
+/**
+ * spi_nor_check_pp - check if the page program op is supported by controller
+ * @nor: pointer to a 'struct spi_nor'
+ * @pp: pointer to op template to be checked
+ *
+ * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ */
+static int spi_nor_check_pp(struct spi_nor *nor,
+ const struct spi_nor_pp_command *pp)
+{
+ struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 1),
+ SPI_MEM_OP_ADDR(3, 0, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(0, NULL, 1));
+
+ op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(pp->proto);
+ op.addr.buswidth = spi_nor_get_protocol_addr_nbits(pp->proto);
+ op.data.buswidth = spi_nor_get_protocol_data_nbits(pp->proto);
+
+ return spi_nor_check_op(nor, &op);
+}
+
+/**
+ * spi_nor_adjust_hwcaps - Find optimal Read/Write protocol based on SPI
+ * controller capabilities
+ * @nor: pointer to a 'struct spi_nor'
+ * @params: pointer to the 'struct spi_nor_flash_parameter'
+ * representing SPI NOR flash capabilities
+ * @hwcaps: pointer to resulting capabilities after adjusting
+ * according to controller and flash's capability
+ */
+static void
+spi_nor_adjust_hwcaps(struct spi_nor *nor,
+ const struct spi_nor_flash_parameter *params,
+ u32 *hwcaps)
+{
+ unsigned int cap;
+
+ /* DTR modes are not supported yet, mask them all. */
+ *hwcaps &= ~SNOR_HWCAPS_DTR;
+
+ /* X-X-X modes are not supported yet, mask them all. */
+ *hwcaps &= ~SNOR_HWCAPS_X_X_X;
+
+ for (cap = 0; cap < sizeof(*hwcaps) * BITS_PER_BYTE; cap++) {
+ int rdidx, ppidx;
+
+ if (!(*hwcaps & BIT(cap)))
+ continue;
+
+ rdidx = spi_nor_hwcaps_read2cmd(BIT(cap));
+ if (rdidx >= 0 &&
+ spi_nor_check_readop(nor, ¶ms->reads[rdidx]))
+ *hwcaps &= ~BIT(cap);
+
+ ppidx = spi_nor_hwcaps_pp2cmd(BIT(cap));
+ if (ppidx < 0)
+ continue;
+
+ if (spi_nor_check_pp(nor, ¶ms->page_programs[ppidx]))
+ *hwcaps &= ~BIT(cap);
+ }
+}
+
static int spi_nor_select_read(struct spi_nor *nor,
const struct spi_nor_flash_parameter *params,
u32 shared_hwcaps)
@@ -2368,7 +2486,7 @@ static int spi_nor_default_setup(struct spi_nor *nor,
const struct spi_nor_flash_parameter *params,
const struct spi_nor_hwcaps *hwcaps)
{
- u32 ignored_mask, shared_mask;
+ u32 shared_mask;
bool enable_quad_io;
int err;
@@ -2378,17 +2496,12 @@ static int spi_nor_default_setup(struct spi_nor *nor,
*/
shared_mask = hwcaps->mask & params->hwcaps.mask;
- /* SPI n-n-n protocols are not supported yet. */
- ignored_mask = (SNOR_HWCAPS_READ_2_2_2 |
- SNOR_HWCAPS_READ_4_4_4 |
- SNOR_HWCAPS_READ_8_8_8 |
- SNOR_HWCAPS_PP_4_4_4 |
- SNOR_HWCAPS_PP_8_8_8);
- if (shared_mask & ignored_mask) {
- dev_dbg(nor->dev,
- "SPI n-n-n protocols are not supported yet.\n");
- shared_mask &= ~ignored_mask;
- }
+ /*
+ * When called from spi_nor_probe(), all caps are set and we need to
+ * discard some of them based on what the SPI controller actually
+ * supports (using spi_mem_supports_op()).
+ */
+ spi_nor_adjust_hwcaps(nor, params, &shared_mask);
/* Select the (Fast) Read command. */
err = spi_nor_select_read(nor, params, shared_mask);
@@ -2483,12 +2596,12 @@ int spi_nor_scan(struct spi_nor *nor)
struct spi_nor_flash_parameter params;
const struct flash_info *info = NULL;
struct mtd_info *mtd = &nor->mtd;
- struct spi_nor_hwcaps hwcaps = {
- .mask = SNOR_HWCAPS_READ |
- SNOR_HWCAPS_READ_FAST |
- SNOR_HWCAPS_PP,
- };
struct spi_slave *spi = nor->spi;
+ /*
+ * Enable all caps by default. The core will mask them after
+ * checking what's really supported using spi_mem_supports_op().
+ */
+ const struct spi_nor_hwcaps hwcaps = { .mask = SNOR_HWCAPS_ALL };
int ret;
/* Reset SPI protocol for all commands. */
@@ -2502,27 +2615,6 @@ int spi_nor_scan(struct spi_nor *nor)
nor->setup = spi_nor_default_setup;
- if (spi->mode & SPI_RX_OCTAL) {
- hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
-
- if (spi->mode & SPI_TX_OCTAL)
- hwcaps.mask |= (SNOR_HWCAPS_READ_1_8_8 |
- SNOR_HWCAPS_PP_1_1_8 |
- SNOR_HWCAPS_PP_1_8_8);
- } else if (spi->mode & SPI_RX_QUAD) {
- hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
-
- if (spi->mode & SPI_TX_QUAD)
- hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |
- SNOR_HWCAPS_PP_1_1_4 |
- SNOR_HWCAPS_PP_1_4_4);
- } else if (spi->mode & SPI_RX_DUAL) {
- hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
-
- if (spi->mode & SPI_TX_DUAL)
- hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
- }
-
info = spi_nor_read_id(nor);
if (IS_ERR_OR_NULL(info))
return -ENOENT;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index eb5d2794f3..4a11999eeb 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -311,6 +311,20 @@ struct spi_nor_hwcaps {
#define SNOR_HWCAPS_PP_1_8_8 BIT(21)
#define SNOR_HWCAPS_PP_8_8_8 BIT(22)
+#define SNOR_HWCAPS_X_X_X (SNOR_HWCAPS_READ_2_2_2 | \
+ SNOR_HWCAPS_READ_4_4_4 | \
+ SNOR_HWCAPS_READ_8_8_8 | \
+ SNOR_HWCAPS_PP_4_4_4 | \
+ SNOR_HWCAPS_PP_8_8_8)
+
+#define SNOR_HWCAPS_DTR (SNOR_HWCAPS_READ_1_1_1_DTR | \
+ SNOR_HWCAPS_READ_1_2_2_DTR | \
+ SNOR_HWCAPS_READ_1_4_4_DTR | \
+ SNOR_HWCAPS_READ_1_8_8_DTR)
+
+#define SNOR_HWCAPS_ALL (SNOR_HWCAPS_READ_MASK | \
+ SNOR_HWCAPS_PP_MASK)
+
struct spi_nor_read_command {
u8 num_mode_clocks;
u8 num_wait_states;