From: Boris Brezillon <boris.brezillon@bootlin.com>
To: David Woodhouse <dwmw2@infradead.org>,
Brian Norris <computersforpeace@gmail.com>,
Boris Brezillon <boris.brezillon@bootlin.com>,
Marek Vasut <marek.vasut@gmail.com>,
Richard Weinberger <richard@nod.at>,
linux-mtd@lists.infradead.org,
Yogesh Gaur <yogeshnarayan.gaur@nxp.com>,
Vignesh R <vigneshr@ti.com>,
Cyrille Pitchen <cyrille.pitchen@wedev4u.fr>
Cc: Julien Su <juliensu@mxic.com.tw>, Mark Brown <broonie@kernel.org>,
Mason Yang <masonccyang@mxic.com.tw>,
linux-spi@vger.kernel.org, zhengxunli@mxic.com.tw
Subject: [PATCH RFC 10/18] mtd: spi-nor: Add support for X-X-X modes
Date: Fri, 12 Oct 2018 10:48:17 +0200 [thread overview]
Message-ID: <20181012084825.23697-11-boris.brezillon@bootlin.com> (raw)
In-Reply-To: <20181012084825.23697-1-boris.brezillon@bootlin.com>
Some NORs only support 1-1-1 and X-X-X modes, and in the case, the
benefit of using X-X-X mode is obvious, even if this implies extra
complexity in the core logic, since now the protocol used for a given
operation depends on the mode the NOR is currently operating in.
To deal with this stateful aspect, we add a ->mode field which keeps
track of the current mode. We also add a ->change_mode() hook, so that
NORs can have their own procedure to switch from one mode to another,
and ->adjust_op() is here to live patch spi_mem_op when a given
operation is executed (depending on the mode, it might involve extending
the number of dummy cycle, adding address or cmd cycles, ...).
Finally, ->preferred_mode is here let the core know what mode it should
enter when resuming or at init time. The preferred mode selection logic
(spi_nor_select_preferred_mode()) is pretty basic and might be extended
at some point.
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
drivers/mtd/spi-nor/spi-nor.c | 96 +++++++++++++++++++++++++++++++++++++++++--
include/linux/mtd/spi-nor.h | 12 ++++++
2 files changed, 105 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 42f299a0b76f..33a07d9eb7a8 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -93,10 +93,18 @@ struct flash_info {
#define USE_CLSR BIT(14) /* use CLSR command */
int (*quad_enable)(struct spi_nor *nor);
+ int (*change_mode)(struct spi_nor *nor, u32 newmode);
+ void (*adjust_op)(struct spi_nor *nor, struct spi_mem_op *op);
};
#define JEDEC_MFR(info) ((info)->id[0])
+static void spi_nor_adjust_op(struct spi_nor *nor, struct spi_mem_op *op)
+{
+ if (nor->adjust_op)
+ nor->adjust_op(nor, op);
+}
+
static int spi_nor_exec_op(struct spi_nor *nor, struct spi_mem_op *op,
u64 *addr, void *buf, unsigned int len)
{
@@ -106,6 +114,8 @@ static int spi_nor_exec_op(struct spi_nor *nor, struct spi_mem_op *op,
if (!op || (len && !buf))
return -EINVAL;
+ spi_nor_adjust_op(nor, op);
+
if (op->addr.nbytes && addr)
op->addr.val = *addr;
@@ -150,11 +160,17 @@ static int spi_nor_nodata_op(struct spi_nor *nor, struct spi_mem_op *op)
static int spi_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *val, int len)
{
+ if (WARN_ON_ONCE(nor->mode != SPI_NOR_MODE_SPI))
+ return -ENOTSUPP;
+
return nor->read_reg(nor, opcode, val, len);
}
static int spi_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *val, int len)
{
+ if (WARN_ON_ONCE(nor->mode != SPI_NOR_MODE_SPI))
+ return -ENOTSUPP;
+
return nor->write_reg(nor, opcode, val, len);
}
@@ -184,6 +200,8 @@ static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t ofs,
/* convert the dummy cycles to the number of bytes */
op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
+ spi_nor_adjust_op(nor, &op);
+
while (remaining) {
op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
if (!usebouncebuf)
@@ -243,6 +261,8 @@ static ssize_t spi_nor_spimem_write_data(struct spi_nor *nor, loff_t ofs,
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
op.addr.nbytes = 0;
+ spi_nor_adjust_op(nor, &op);
+
op.data.nbytes = len < UINT_MAX ? len : UINT_MAX;
if (!usebouncebuf) {
@@ -422,6 +442,25 @@ static int write_disable(struct spi_nor *nor)
return spi_nor_write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
}
+static int spi_nor_change_mode(struct spi_nor *nor, u32 newmode)
+{
+ int ret;
+
+ if (newmode == nor->mode)
+ return 0;
+
+ if (!nor->change_mode)
+ return -ENOTSUPP;
+
+ ret = nor->change_mode(nor, newmode);
+ if (ret)
+ return ret;
+
+ nor->mode = newmode;
+
+ return 0;
+}
+
static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
{
return mtd->priv;
@@ -2902,9 +2941,6 @@ spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor,
/* 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;
-
/* Start with read commands. */
for (cap = 0; cap < 32; cap++) {
int idx;
@@ -3884,6 +3920,46 @@ static int spi_nor_select_erase(struct spi_nor *nor, u32 wanted_size)
return 0;
}
+static void spi_nor_select_preferred_mode(struct spi_nor *nor, u32 hwcaps)
+{
+ nor->preferred_mode = SPI_NOR_MODE_SPI;
+
+ /*
+ * Let's just avoid using stateful modes when SNOR_F_BROKEN_RESET is
+ * set.
+ */
+ if (nor->flags & SNOR_F_BROKEN_RESET)
+ return;
+
+ /*
+ * Stateless (1-n-n or 1-1-n) opcodes should always be preferred to
+ * stateful (n-n-n) ones if supported.
+ */
+ if (hwcaps & SNOR_HWCPAS_READ_OCTO && hwcaps & SNOR_HWCAPS_PP_OCTO)
+ return;
+
+ if (hwcaps & SNOR_HWCAPS_OPI) {
+ nor->preferred_mode = SPI_NOR_MODE_OPI;
+ return;
+ }
+
+ if (hwcaps & SNOR_HWCAPS_READ_QUAD && hwcaps & SNOR_HWCAPS_PP_QUAD)
+ return;
+
+ if (hwcaps & SNOR_HWCAPS_QPI) {
+ nor->preferred_mode = SPI_NOR_MODE_QPI;
+ return;
+ }
+
+ if (hwcaps & SNOR_HWCAPS_READ_DUAL)
+ return;
+
+ if (hwcaps & SNOR_HWCAPS_DPI) {
+ nor->preferred_mode = SPI_NOR_MODE_DPI;
+ return;
+ }
+}
+
static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
const struct spi_nor_flash_parameter *params,
const struct spi_nor_hwcaps *hwcaps)
@@ -3892,6 +3968,10 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
bool enable_quad_io;
int err;
+ /* Set ->adjust_op() and ->change_mode(). */
+ nor->adjust_op = info->adjust_op;
+ nor->change_mode = info->change_mode;
+
/*
* Keep only the hardware capabilities supported by both the SPI
* controller and the SPI flash memory.
@@ -3951,6 +4031,8 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
else
nor->quad_enable = NULL;
+ spi_nor_select_preferred_mode(nor, shared_mask);
+
return 0;
}
@@ -3971,6 +4053,11 @@ static int spi_nor_init(struct spi_nor *nor)
spi_nor_wait_till_ready(nor);
}
+ err = spi_nor_change_mode(nor, nor->preferred_mode);
+ if (err)
+ dev_err(nor->dev, "failed to switch to mode %x",
+ nor->preferred_mode);
+
if (nor->quad_enable) {
err = nor->quad_enable(nor);
if (err) {
@@ -4011,6 +4098,9 @@ static void spi_nor_resume(struct mtd_info *mtd)
void spi_nor_restore(struct spi_nor *nor)
{
+ /* Restore the NOR to SPI mode. */
+ spi_nor_change_mode(nor, SPI_NOR_MODE_SPI);
+
/* restore the addressing mode */
if ((nor->addr_width == 4) &&
!(nor->info->flags & SPI_NOR_4B_OPCODES) &&
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index f2154672f75a..f80aba464eb2 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -333,6 +333,14 @@ struct spi_nor_erase_map {
*/
struct flash_info;
+enum spi_nor_mode {
+ SPI_NOR_MODE_SPI,
+ SPI_NOR_MODE_DPI,
+ SPI_NOR_MODE_QPI,
+ SPI_NOR_MODE_OPI,
+ SPI_NOR_NUM_MODES,
+};
+
/**
* struct spi_nor - Structure for defining a the SPI NOR layer
* @mtd: point to a mtd_info structure
@@ -381,6 +389,8 @@ struct spi_nor {
struct spi_mem *spimem;
void *bouncebuf;
unsigned int bouncebuf_size;
+ enum spi_nor_mode preferred_mode;
+ enum spi_nor_mode mode;
const struct flash_info *info;
u32 page_size;
u8 addr_width;
@@ -412,6 +422,8 @@ struct spi_nor {
int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*quad_enable)(struct spi_nor *nor);
int (*set_4byte)(struct spi_nor *nor, bool enable);
+ int (*change_mode)(struct spi_nor *nor, enum spi_nor_mode newmode);
+ void (*adjust_op)(struct spi_nor *nor, struct spi_mem_op *op);
void *priv;
};
--
2.14.1
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
next prev parent reply other threads:[~2018-10-12 8:48 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-10-12 8:48 [PATCH RFC 00/18] mtd: spi-nor: Proposal for 8-8-8 mode support Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 01/18] mtd: spi-nor: Add a flash_info entry for Macronix mx25uw51245g Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 02/18] spi: Prepare things for octo mode support Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 03/18] spi: spi-mem: Prepare things for DTR " Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 04/18] spi: spi-mem: Prepare things for dual bytes opcodes support Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 05/18] spi: spi-mem: mxic: Add support for DTR and Octo mode Boris Brezillon
2018-11-18 17:21 ` Miquel Raynal
2018-11-18 17:32 ` Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 06/18] mtd: spi-nor: Move m25p80 code in spi-nor.c Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 07/18] mtd: spi-nor: Rework hwcaps selection for the spi-mem case Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 08/18] mtd: spi-nor: Define the DPI, QPI and OPI hwcaps Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 09/18] mtd: spi-nor: Add spi_nor_{read, write}_reg() helpers Boris Brezillon
2018-10-12 8:48 ` Boris Brezillon [this message]
2018-10-12 8:48 ` [PATCH RFC 11/18] mtd: spi-nor: Prepare things for 2byte opcodes Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 12/18] mtd: spi-nor: Provide a hook to tweak flash parameters Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 13/18] mtd: spi-nor: Add 8-8-8 mode support to Macronix mx25uw51245g Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 14/18] mtd: spi-nor: Clarify where DTR mode applies Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 15/18] mtd: spi-nor: Add DTR support to the spi-mem logic Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 16/18] mtd: spi-nor: Add the concept of full DTR modes Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 17/18] mtd: spi-nor: Add 8D-8D-8D mode Boris Brezillon
2018-10-12 8:48 ` [PATCH RFC 18/18] mtd: spi-nor: Make sure the 8D-8D-8D can be selected on mx25uw51245g Boris Brezillon
[not found] ` <OF300145A1.D60E7B33-ON48258376.002EDC4B-48258376.0031A14C@LocalDomain>
[not found] ` <OF3005248A.454B9B59-ON48258382.002767AE-48258382.00293E8D@mxic.com.tw>
2019-01-14 8:39 ` Boris Brezillon
2018-10-19 12:25 ` [PATCH RFC 00/18] mtd: spi-nor: Proposal for 8-8-8 mode support Mark Brown
2018-10-19 12:59 ` Boris Brezillon
2018-10-21 13:36 ` Mark Brown
2018-10-22 8:21 ` Boris Brezillon
2018-10-22 12:01 ` Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181012084825.23697-11-boris.brezillon@bootlin.com \
--to=boris.brezillon@bootlin.com \
--cc=broonie@kernel.org \
--cc=computersforpeace@gmail.com \
--cc=cyrille.pitchen@wedev4u.fr \
--cc=dwmw2@infradead.org \
--cc=juliensu@mxic.com.tw \
--cc=linux-mtd@lists.infradead.org \
--cc=linux-spi@vger.kernel.org \
--cc=marek.vasut@gmail.com \
--cc=masonccyang@mxic.com.tw \
--cc=richard@nod.at \
--cc=vigneshr@ti.com \
--cc=yogeshnarayan.gaur@nxp.com \
--cc=zhengxunli@mxic.com.tw \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).