Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1630962 > unrolled thread
| Started by | Cyrille Pitchen <cyrille.pitchen@wedev4u.fr> |
|---|---|
| First post | 2017-04-25 22:20 +0200 |
| Last post | 2017-04-25 22:50 +0200 |
| Articles | 5 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v8 0/4] mtd: spi-nor: parse SFDP tables to setup (Q)SPI memories Cyrille Pitchen <cyrille.pitchen@wedev4u.fr> - 2017-04-25 22:20 +0200
[PATCH v8 4/4] mtd: spi-nor: introduce Octo SPI protocols Cyrille Pitchen <cyrille.pitchen@wedev4u.fr> - 2017-04-25 22:20 +0200
Re: [PATCH v8 1/4] mtd: spi-nor: introduce SPI 1-2-2 and SPI 1-4-4 protocols Marek Vasut <marek.vasut@gmail.com> - 2017-04-25 22:30 +0200
Re: [PATCH v8 1/4] mtd: spi-nor: introduce SPI 1-2-2 and SPI 1-4-4 protocols Cyrille Pitchen <cyrille.pitchen@wedev4u.fr> - 2017-04-25 23:50 +0200
[PATCH v8 2/4] mtd: m25p80: add support of SPI 1-2-2 and 1-4-4 protocols Cyrille Pitchen <cyrille.pitchen@wedev4u.fr> - 2017-04-25 22:50 +0200
| From | Cyrille Pitchen <cyrille.pitchen@wedev4u.fr> |
|---|---|
| Date | 2017-04-25 22:20 +0200 |
| Subject | [PATCH v8 0/4] mtd: spi-nor: parse SFDP tables to setup (Q)SPI memories |
| Message-ID | <tAf6h-Vi-3@gated-at.bofh.it> |
Hi all,
based on git-hub/spi-nor.
The 4 patches have passed the checkpatch test.
DISCLAIMER: despite what the subjet claims, I've removed the SFDP patches from this
version since they are still RFC/WIP. However I've chosen not to change the subjet
line so it's easier to make the link between this series and its pervious versions.
You can still find the SFDP patches in v5.
Some words about the reason why I kept the quad_enable() hook inside the
'struct spi_nor_flash_parameter':
Before patch 1:
static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
{
int status;
switch (JEDEC_MFR(info)) {
case SNOR_MFR_MACRONIX:
status = macronix_quad_enable(nor);
if (status) {
dev_err(nor->dev, "Macronix quad-read not enabled\n");
return -EINVAL;
}
return status;
case SNOR_MFR_MICRON:
return 0;
default:
status = spansion_quad_enable(nor);
if (status) {
dev_err(nor->dev, "Spansion quad-read not enabled\n");
return -EINVAL;
}
return status;
}
}
[...]
int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
{
[...]
if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
ret = set_quad_mode(nor, info);
if (ret) {
dev_err(dev, "quad mode not supported\n");
return ret;
}
nor->flash_read = SPI_NOR_QUAD;
[...]
}
Since the 'enum read_mode' has been replaced by the
'struct spi_nor_hwcaps', we have to update the if () statement from
spi_nor_scan() because SPI_NOR_QUAD no longer exists.
The original if () statement, checked the memory hardware capabilities
(info->flags & SPI_NOR_QUAD_READ) and the controller harware capabilities
(mode == SPI_NOR_QUAD) to decide whether or not some *_quad_enable()
function had to be called.
After patch 1, things are split into 2 phases:
- phase 1 handled by spi_nor_init_params() to discover the hardware
capabilities of the SPI flash memory and to initilize the
'struct spi_nor_flash_parameter' accordingly. For now this structure
is iniatlized only base on info and JEDEC_MFR(info).
However we already know that later some flash parameters will be
overridden when parsing the SFDP tables from spi_nor_init_params().
Especially the choice of the *_quad_enable() function will be
directly given by a dedicated field within the Basic Flash Parameter
Table. That's why params->quad_enable() is set from
spi_nor_init_params() and not later. It's one of the flash parameters
after all!
However at this step, we don't know yet whether or not
params->quad_enable() should be called.
- phase 2 handled by spi_nor_setup() selects the right settings (best
matches) for Fast Read, Page Program and Sector Erase operations
based on the hardware capabilities supported by both the (Q)SPI flash
memory and the (Q)SPI controller.
If any Quad SPI protocol (SPI x-y-4) is selected either for Fast Read
or for Page Progam or for both operations, we must set the QE bit by
calling params->quad_enable().
I've chosen to integrate ->quad_enable() in the
'struct spi_nor_flash_parameter' also in patch 1 and not in a dedicated
patch because I think we should stay backward compatible and keep the same
features as befor: adding quad_enable() in a dedicated patch would have
not respect the logic of spi_nor_init_params() VS spi_nor_setup() and/or
may have introduce bug if bisecting between patch 1 and patch 1-bis.
Sorry for this LONG explaination but it seemed that some of my choices
needed to be justified some more. I hope those detailed explainations
whould help to clarify what I've done :)
original cover-letter:
"""
This new series of patchs aims to upgrade to spi-nor framework. We need to
take into account latest SPI memories which cannot be handled correctly by
the current implementation.
For instance, SPI NOR memories like Spansion S25FS512S or Macronix
MX25U4035 support only the Fast Read 1-4-4 (EBh) command but not the
Fast Read 1-1-4 (6Bh) command. However the current spi-nor framework
supports only Fast Read 1-1-4 (6Bh).
Also the Spansion S25FS512S memory (and others) may use a non-uniform
sector erase map, whereas the spi-nor framework assumes that a single
sector erase size and opcode can be used anywhere inside the data array.
This assumption is no longer valid.
Then parsing SFDP tables is an attempt to solve many of those issues by
discovering dynamically most of the parameters and settings of the SPI NOR
memory:
- the flash size
- the page size for Page Program commands
- the supported Fast Read commands with the associated opcodes and number
of mode/wait-state (dummy) cycles.
- the supported Sector/Block Erase commands with the associated opcodes
and sizes.
- the erase sector map (for non-uniform memory).
Besides, most QSPI controllers from the different vendors are capable to
support the SPI 1-2-2 and 1-4-4 protocols but the spi-nor framework was
not ready to use them. This series also fixes this issue and computes the
best match between the hardware capabilies of both the SPI memory and the
SPI controler (master) to select the right opcodes and dummy cycles for
Fast Read and Page Program operations.
The new 'struct spi_nor_hwcaps' uses a bitmask to describe all the
supported hardware capabilies and makes the difference between Fast Read
and Page Program operations and also between the different SPI protocols
(SPI 1-1-2 vs SPI 1-2-2 or SPI 1-1-4 vs SPI 1-4-4).
"""
Best Regards,
Cyrille
ChangeLog:
v7 -> v8
- patch 1: replace (u32) casts by (unsigned long) casts in spi-nor.h
- patch 2: no change
- patch 3: rework spi_nor_protocol_is_dtr() a little bit to avoid a
potential signed/unsigned comparision warning on some architectures.
- patch 4: add "Reviewed-by" tag from Marek.
v6 -> v7
- add "Reviewed-by" tag in patch 2 from Marek.
- split patch 1 from v6 into patches 1, 3 and 4 in v7:
+ Double Transfer Rate (DTR) protocols are introduced in the dedicated
patch 3.
+ Octo SPI protocols are introduced in the dedicated patch 4.
- reword commit message of patch 1 to better explain the purpose of
spi_nor_init_params() and spi_nor_setup().
- remove some extra empty lines.
- simplify the code of the m25p80_rx_nbits() function in patch 1:
this function directly calls spi_nor_get_protocol_data_nbits().
Anyway, the m25p80_rx_nbits() function is completely removed later
in patch 2.
v5 -> v6
- rebase onto the 'next' branch of github/spi-nor to patch the new
stm32_quadspi driver.
- remove many unnecessary parentheses and add some new lines.
- add the 'const' keywork to some 'struct spi_nor_hwcaps' initialized on
the stack.
- fix a typo in some comment.
- change the encoding scheme of the 'enum spi_nor_protocol' as suggested
by Marek to simplify the extraction of the number of bits (I/O lines)
for instruction, address and data clock cycles.
- extact the nor->flash_quad_enable() hook from spi-nor.h from patch 1 and
place it into the new dedicated patch 3 as suggested by Marek.
Patch 3 is a tiny transitionnal patch needed by patch 4 which is based
on an original patch from Kamal Dasu.
v4 -> v5
- rework the whole series.
- introduce support for Octo SPI protocols.
- introduce support for Double Transfer Rate (DTR) protocols.
- introduce support for memories with non-uniform sector erase sizes.
v3 -> v4
- replace dev_info() by dev_dbg() in patch 1.
- split former patch 2 into 2 patches:
+ new patch 2 deals with the rename of SPINOR_OP_READ4_* macros
+ new patch 3 deals with the alternative methode to support memory
> 16MiB
- add comment in patch 3 to describe the dichotomic search performed by
spi_nor_convert_opcode().
- change return type from int to void for m25p80_proto2nbits() in patch 6.
- remove former patches 8 & 9 from the v2 series: the support of the
Macronix mx66l1g45g memory will be sent in a separated patch.
v2 -> v3
- tested with new samples: Micron n25q512, n25q01g and Macronix
mx25v1635f, mx25l3235f, mx25l3273f.
- add "Reviewed-by: Jagan Teki <jagan@openedev.com>" on patch 1.
- add "Tested-by: Vignesh R <vigneshr@ti.com>" on patch 2.
- fix some checkpatch warnings.
- add call of spi_nor_wait_till_ready() in spansion_new_quad_enable()
and sr2_bit7_quad_enable(), as suggested by Joel Esponde on patch 6.
- test JESD216 rev A (minor 5) instead of rev B (minor 6) with the return
code of spi_nor_parse_sfdp() from spi_nor_init_params() on patch 6.
The seven additional DWORDs of the Basic Flash Parameter Table were
introduced in rev A, not rev B, so the 15th DWORD was already available
in rev A. The 15th DWORD provides us with the Quad Enable Requirements
(QER) bits.
Basic Flash Parameter Table size:
+ JESD216 : 9 DWORDS
+ JESD216A: 16 DWORDS
+ JESD216B: 16 DWORDS
v1 -> v2
- fix patch 3 to resolve compiler errors on hisi-sfc.c and cadence-quadspi.c
drivers
Cyrille Pitchen (4):
mtd: spi-nor: introduce SPI 1-2-2 and SPI 1-4-4 protocols
mtd: m25p80: add support of SPI 1-2-2 and 1-4-4 protocols
mtd: spi-nor: introduce Double Transfer Rate (DTR) SPI protocols
mtd: spi-nor: introduce Octo SPI protocols
drivers/mtd/devices/m25p80.c | 121 ++++++---
drivers/mtd/spi-nor/aspeed-smc.c | 23 +-
drivers/mtd/spi-nor/atmel-quadspi.c | 83 ++++--
drivers/mtd/spi-nor/cadence-quadspi.c | 18 +-
drivers/mtd/spi-nor/fsl-quadspi.c | 6 +-
drivers/mtd/spi-nor/hisi-sfc.c | 31 ++-
drivers/mtd/spi-nor/intel-spi.c | 7 +-
drivers/mtd/spi-nor/mtk-quadspi.c | 15 +-
drivers/mtd/spi-nor/nxp-spifi.c | 22 +-
drivers/mtd/spi-nor/spi-nor.c | 470 +++++++++++++++++++++++++++-------
drivers/mtd/spi-nor/stm32-quadspi.c | 27 +-
include/linux/mtd/spi-nor.h | 161 +++++++++++-
12 files changed, 763 insertions(+), 221 deletions(-)
--
2.9.3
[toc] | [next] | [standalone]
| From | Cyrille Pitchen <cyrille.pitchen@wedev4u.fr> |
|---|---|
| Date | 2017-04-25 22:20 +0200 |
| Subject | [PATCH v8 4/4] mtd: spi-nor: introduce Octo SPI protocols |
| Message-ID | <tAf6i-Vi-17@gated-at.bofh.it> |
| In reply to | #1630962 |
From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
This patch starts adding support to Octo SPI protocols (SPI x-y-8).
Op codes for Fast Read and/or Page Program operations using Octo SPI
protocols are not known yet (no JEDEC specification has defined them yet)
but we'd rather introduce the Octo SPI protocols now so it's done as it
should be.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Reviewed-by: Marek Vasut <marek.vasut@gmail.com>
---
drivers/mtd/spi-nor/spi-nor.c | 22 +++++++++++++++++++++-
include/linux/mtd/spi-nor.h | 26 +++++++++++++++++++++-----
2 files changed, 42 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 9f0956d56dc9..5e664f80f3be 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1527,6 +1527,12 @@ enum spi_nor_read_command_index {
SNOR_CMD_READ_4_4_4,
SNOR_CMD_READ_1_4_4_DTR,
+ /* Octo SPI */
+ SNOR_CMD_READ_1_1_8,
+ SNOR_CMD_READ_1_8_8,
+ SNOR_CMD_READ_8_8_8,
+ SNOR_CMD_READ_1_8_8_DTR,
+
SNOR_CMD_READ_MAX
};
@@ -1538,6 +1544,11 @@ enum spi_nor_pp_command_index {
SNOR_CMD_PP_1_4_4,
SNOR_CMD_PP_4_4_4,
+ /* Octo SPI */
+ SNOR_CMD_PP_1_1_8,
+ SNOR_CMD_PP_1_8_8,
+ SNOR_CMD_PP_8_8_8,
+
SNOR_CMD_PP_MAX
};
@@ -1662,6 +1673,10 @@ static int spi_nor_hwcaps_read2cmd(u32 hwcaps)
{ SNOR_HWCAPS_READ_1_4_4, SNOR_CMD_READ_1_4_4 },
{ SNOR_HWCAPS_READ_4_4_4, SNOR_CMD_READ_4_4_4 },
{ SNOR_HWCAPS_READ_1_4_4_DTR, SNOR_CMD_READ_1_4_4_DTR },
+ { SNOR_HWCAPS_READ_1_1_8, SNOR_CMD_READ_1_1_8 },
+ { SNOR_HWCAPS_READ_1_8_8, SNOR_CMD_READ_1_8_8 },
+ { SNOR_HWCAPS_READ_8_8_8, SNOR_CMD_READ_8_8_8 },
+ { SNOR_HWCAPS_READ_1_8_8_DTR, SNOR_CMD_READ_1_8_8_DTR },
};
return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd,
@@ -1675,6 +1690,9 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
{ SNOR_HWCAPS_PP_1_1_4, SNOR_CMD_PP_1_1_4 },
{ SNOR_HWCAPS_PP_1_4_4, SNOR_CMD_PP_1_4_4 },
{ SNOR_HWCAPS_PP_4_4_4, SNOR_CMD_PP_4_4_4 },
+ { SNOR_HWCAPS_PP_1_1_8, SNOR_CMD_PP_1_1_8 },
+ { SNOR_HWCAPS_PP_1_8_8, SNOR_CMD_PP_1_8_8 },
+ { SNOR_HWCAPS_PP_8_8_8, SNOR_CMD_PP_8_8_8 },
};
return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd,
@@ -1772,7 +1790,9 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
/* 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_PP_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");
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 313dbe56f31a..55faa2f07cca 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -161,14 +161,18 @@ enum spi_nor_protocol {
SNOR_PROTO_1_1_1 = SNOR_PROTO_STR(1, 1, 1),
SNOR_PROTO_1_1_2 = SNOR_PROTO_STR(1, 1, 2),
SNOR_PROTO_1_1_4 = SNOR_PROTO_STR(1, 1, 4),
+ SNOR_PROTO_1_1_8 = SNOR_PROTO_STR(1, 1, 8),
SNOR_PROTO_1_2_2 = SNOR_PROTO_STR(1, 2, 2),
SNOR_PROTO_1_4_4 = SNOR_PROTO_STR(1, 4, 4),
+ SNOR_PROTO_1_8_8 = SNOR_PROTO_STR(1, 8, 8),
SNOR_PROTO_2_2_2 = SNOR_PROTO_STR(2, 2, 2),
SNOR_PROTO_4_4_4 = SNOR_PROTO_STR(4, 4, 4),
+ SNOR_PROTO_8_8_8 = SNOR_PROTO_STR(8, 8, 8),
SNOR_PROTO_1_1_1_DTR = SNOR_PROTO_DTR(1, 1, 1),
SNOR_PROTO_1_2_2_DTR = SNOR_PROTO_DTR(1, 2, 2),
SNOR_PROTO_1_4_4_DTR = SNOR_PROTO_DTR(1, 4, 4),
+ SNOR_PROTO_1_8_8_DTR = SNOR_PROTO_DTR(1, 8, 8),
};
static inline bool spi_nor_protocol_is_dtr(enum spi_nor_protocol proto)
@@ -308,10 +312,11 @@ struct spi_nor_hwcaps {
/*
*(Fast) Read capabilities.
* MUST be ordered by priority: the higher bit position, the higher priority.
- * As a matter of performances, it is relevant to use Quad SPI protocols first,
- * then Dual SPI protocols before Fast Read and lastly (Slow) Read.
+ * As a matter of performances, it is relevant to use Octo SPI protocols first,
+ * then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
+ * (Slow) Read.
*/
-#define SNOR_HWCAPS_READ_MASK GENMASK(10, 0)
+#define SNOR_HWCAPS_READ_MASK GENMASK(14, 0)
#define SNOR_HWCAPS_READ BIT(0)
#define SNOR_HWCAPS_READ_FAST BIT(1)
#define SNOR_HWCAPS_READ_1_1_1_DTR BIT(2)
@@ -328,16 +333,22 @@ struct spi_nor_hwcaps {
#define SNOR_HWCAPS_READ_4_4_4 BIT(9)
#define SNOR_HWCAPS_READ_1_4_4_DTR BIT(10)
+#define SNOR_HWCPAS_READ_OCTO GENMASK(14, 11)
+#define SNOR_HWCAPS_READ_1_1_8 BIT(11)
+#define SNOR_HWCAPS_READ_1_8_8 BIT(12)
+#define SNOR_HWCAPS_READ_8_8_8 BIT(13)
+#define SNOR_HWCAPS_READ_1_8_8_DTR BIT(14)
+
/*
* Page Program capabilities.
* MUST be ordered by priority: the higher bit position, the higher priority.
- * Like (Fast) Read capabilities, Quad SPI protocols are preferred to the
+ * Like (Fast) Read capabilities, Octo/Quad SPI protocols are preferred to the
* legacy SPI 1-1-1 protocol.
* Note that Dual Page Programs are not supported because there is no existing
* JEDEC/SFDP standard to define them. Also at this moment no SPI flash memory
* implements such commands.
*/
-#define SNOR_HWCAPS_PP_MASK GENMASK(19, 16)
+#define SNOR_HWCAPS_PP_MASK GENMASK(22, 16)
#define SNOR_HWCAPS_PP BIT(16)
#define SNOR_HWCAPS_PP_QUAD GENMASK(19, 17)
@@ -345,6 +356,11 @@ struct spi_nor_hwcaps {
#define SNOR_HWCAPS_PP_1_4_4 BIT(18)
#define SNOR_HWCAPS_PP_4_4_4 BIT(19)
+#define SNOR_HWCAPS_PP_OCTO GENMASK(22, 20)
+#define SNOR_HWCAPS_PP_1_1_8 BIT(20)
+#define SNOR_HWCAPS_PP_1_8_8 BIT(21)
+#define SNOR_HWCAPS_PP_8_8_8 BIT(22)
+
/**
* spi_nor_scan() - scan the SPI NOR
* @nor: the spi_nor structure
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Marek Vasut <marek.vasut@gmail.com> |
|---|---|
| Date | 2017-04-25 22:30 +0200 |
| Subject | Re: [PATCH v8 1/4] mtd: spi-nor: introduce SPI 1-2-2 and SPI 1-4-4 protocols |
| Message-ID | <tAffY-Yq-35@gated-at.bofh.it> |
| In reply to | #1630962 |
On 04/25/2017 10:08 PM, Cyrille Pitchen wrote: > From: Cyrille Pitchen <cyrille.pitchen@atmel.com> > > This patch changes the prototype of spi_nor_scan(): its 3rd parameter > is replaced by a 'struct spi_nor_hwcaps' pointer, which tells the spi-nor > framework about the actual hardware capabilities supported by the SPI > controller and its driver. > > Besides, this patch also introduces a new 'struct spi_nor_flash_parameter' > telling the spi-nor framework about the hardware capabilities supported by > the SPI flash memory and the associated settings required to use those > hardware caps. > > Then, to improve the readability of spi_nor_scan(), the discovery of the > memory settings and the memory initialization are now split into two > dedicated functions. > > 1 - spi_nor_init_params() > > The spi_nor_init_params() function is responsible for initializing the > 'struct spi_nor_flash_parameter'. Currently this structure is filled with > legacy values but further patches will allow to override some parameter > values dynamically, for instance by reading the JESD216 Serial Flash > Discoverable Parameter (SFDP) tables from the SPI memory. > The spi_nor_init_params() function only deals with the hardware > capabilities of the SPI flash memory: especially it doesn't care about > the hardware capabilities supported by the SPI controller. > > 2 - spi_nor_setup() > > The second function is called once the 'struct spi_nor_flash_parameter' > has been initialized by spi_nor_init_params(). > With both 'struct spi_nor_flash_parameter' and 'struct spi_nor_hwcaps', > the new argument of spi_nor_scan(), spi_nor_setup() computes the best > match between hardware caps supported by both the (Q)SPI memory and > controller hence selecting the relevant settings for (Fast) Read and Page > Program operations. > > Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> Reviewed-by: Marek Vasut <marek.vasut@gmail.com> [...] -- Best regards, Marek Vasut
[toc] | [prev] | [next] | [standalone]
| From | Cyrille Pitchen <cyrille.pitchen@wedev4u.fr> |
|---|---|
| Date | 2017-04-25 23:50 +0200 |
| Subject | Re: [PATCH v8 1/4] mtd: spi-nor: introduce SPI 1-2-2 and SPI 1-4-4 protocols |
| Message-ID | <tAgvn-1HU-9@gated-at.bofh.it> |
| In reply to | #1630979 |
Le 25/04/2017 à 22:25, Marek Vasut a écrit : > On 04/25/2017 10:08 PM, Cyrille Pitchen wrote: >> From: Cyrille Pitchen <cyrille.pitchen@atmel.com> >> >> This patch changes the prototype of spi_nor_scan(): its 3rd parameter >> is replaced by a 'struct spi_nor_hwcaps' pointer, which tells the spi-nor >> framework about the actual hardware capabilities supported by the SPI >> controller and its driver. >> >> Besides, this patch also introduces a new 'struct spi_nor_flash_parameter' >> telling the spi-nor framework about the hardware capabilities supported by >> the SPI flash memory and the associated settings required to use those >> hardware caps. >> >> Then, to improve the readability of spi_nor_scan(), the discovery of the >> memory settings and the memory initialization are now split into two >> dedicated functions. >> >> 1 - spi_nor_init_params() >> >> The spi_nor_init_params() function is responsible for initializing the >> 'struct spi_nor_flash_parameter'. Currently this structure is filled with >> legacy values but further patches will allow to override some parameter >> values dynamically, for instance by reading the JESD216 Serial Flash >> Discoverable Parameter (SFDP) tables from the SPI memory. >> The spi_nor_init_params() function only deals with the hardware >> capabilities of the SPI flash memory: especially it doesn't care about >> the hardware capabilities supported by the SPI controller. >> >> 2 - spi_nor_setup() >> >> The second function is called once the 'struct spi_nor_flash_parameter' >> has been initialized by spi_nor_init_params(). >> With both 'struct spi_nor_flash_parameter' and 'struct spi_nor_hwcaps', >> the new argument of spi_nor_scan(), spi_nor_setup() computes the best >> match between hardware caps supported by both the (Q)SPI memory and >> controller hence selecting the relevant settings for (Fast) Read and Page >> Program operations. >> >> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> > > Reviewed-by: Marek Vasut <marek.vasut@gmail.com> > > [...] > whole series applied to the 'next' branch of the github/spi-nor tree. Thanks for your reviews! Best regards, Cyrille
[toc] | [prev] | [next] | [standalone]
| From | Cyrille Pitchen <cyrille.pitchen@wedev4u.fr> |
|---|---|
| Date | 2017-04-25 22:50 +0200 |
| Subject | [PATCH v8 2/4] mtd: m25p80: add support of SPI 1-2-2 and 1-4-4 protocols |
| Message-ID | <tAfzj-14W-17@gated-at.bofh.it> |
| In reply to | #1630962 |
From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Before this patch, m25p80_read() supported few SPI protocols:
- regular SPI 1-1-1
- SPI Dual Output 1-1-2
- SPI Quad Output 1-1-4
On the other hand, m25p80_write() only supported SPI 1-1-1.
This patch updates both m25p80_read() and m25p80_write() functions to let
them support SPI 1-2-2 and SPI 1-4-4 protocols for Fast Read and Page
Program SPI commands.
It adopts a conservative approach to avoid regressions. Hence the new
implementations try to be as close as possible to the old implementations,
so the main differences are:
- the tx_nbits values now being set properly for the spi_transfer
structures carrying the (op code + address/dummy) bytes
- and the spi_transfer structure being split into 2 spi_transfer
structures when the numbers of I/O lines are different for op code and
for address/dummy byte transfers on the SPI bus.
Besides, the current spi-nor framework supports neither the SPI 2-2-2 nor
the SPI 4-4-4 protocols. So, for now, we don't need to update the
m25p80_{read|write}_reg() functions as SPI 1-1-1 is the only one possible
protocol.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Reviewed-by: Marek Vasut <marek.vasut@gmail.com>
---
drivers/mtd/devices/m25p80.c | 102 +++++++++++++++++++++++++++++++++----------
1 file changed, 79 insertions(+), 23 deletions(-)
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 07073f4ce0bd..00eea6fd379c 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -78,11 +78,17 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
{
struct m25p *flash = nor->priv;
struct spi_device *spi = flash->spi;
- struct spi_transfer t[2] = {};
+ unsigned int inst_nbits, addr_nbits, data_nbits, data_idx;
+ struct spi_transfer t[3] = {};
struct spi_message m;
int cmd_sz = m25p_cmdsz(nor);
ssize_t ret;
+ /* get transfer protocols. */
+ inst_nbits = spi_nor_get_protocol_inst_nbits(nor->write_proto);
+ addr_nbits = spi_nor_get_protocol_addr_nbits(nor->write_proto);
+ data_nbits = spi_nor_get_protocol_data_nbits(nor->write_proto);
+
spi_message_init(&m);
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
@@ -92,12 +98,27 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
m25p_addr2cmd(nor, to, flash->command);
t[0].tx_buf = flash->command;
+ t[0].tx_nbits = inst_nbits;
t[0].len = cmd_sz;
spi_message_add_tail(&t[0], &m);
- t[1].tx_buf = buf;
- t[1].len = len;
- spi_message_add_tail(&t[1], &m);
+ /* split the op code and address bytes into two transfers if needed. */
+ data_idx = 1;
+ if (addr_nbits != inst_nbits) {
+ t[0].len = 1;
+
+ t[1].tx_buf = &flash->command[1];
+ t[1].tx_nbits = addr_nbits;
+ t[1].len = cmd_sz - 1;
+ spi_message_add_tail(&t[1], &m);
+
+ data_idx = 2;
+ }
+
+ t[data_idx].tx_buf = buf;
+ t[data_idx].tx_nbits = data_nbits;
+ t[data_idx].len = len;
+ spi_message_add_tail(&t[data_idx], &m);
ret = spi_sync(spi, &m);
if (ret)
@@ -109,11 +130,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
return ret;
}
-static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
-{
- return spi_nor_get_protocol_data_nbits(nor->read_proto);
-}
-
/*
* Read an address range from the nor chip. The address range
* may be any size provided it is within the physical boundaries.
@@ -123,13 +139,20 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
{
struct m25p *flash = nor->priv;
struct spi_device *spi = flash->spi;
- struct spi_transfer t[2];
+ unsigned int inst_nbits, addr_nbits, data_nbits, data_idx;
+ struct spi_transfer t[3];
struct spi_message m;
unsigned int dummy = nor->read_dummy;
ssize_t ret;
+ int cmd_sz;
+
+ /* get transfer protocols. */
+ inst_nbits = spi_nor_get_protocol_inst_nbits(nor->read_proto);
+ addr_nbits = spi_nor_get_protocol_addr_nbits(nor->read_proto);
+ data_nbits = spi_nor_get_protocol_data_nbits(nor->read_proto);
/* convert the dummy cycles to the number of bytes */
- dummy /= 8;
+ dummy = (dummy * addr_nbits) / 8;
if (spi_flash_read_supported(spi)) {
struct spi_flash_read_message msg;
@@ -142,10 +165,9 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
msg.read_opcode = nor->read_opcode;
msg.addr_width = nor->addr_width;
msg.dummy_bytes = dummy;
- /* TODO: Support other combinations */
- msg.opcode_nbits = SPI_NBITS_SINGLE;
- msg.addr_nbits = SPI_NBITS_SINGLE;
- msg.data_nbits = m25p80_rx_nbits(nor);
+ msg.opcode_nbits = inst_nbits;
+ msg.addr_nbits = addr_nbits;
+ msg.data_nbits = data_nbits;
ret = spi_flash_read(spi, &msg);
if (ret < 0)
@@ -160,20 +182,45 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
m25p_addr2cmd(nor, from, flash->command);
t[0].tx_buf = flash->command;
+ t[0].tx_nbits = inst_nbits;
t[0].len = m25p_cmdsz(nor) + dummy;
spi_message_add_tail(&t[0], &m);
- t[1].rx_buf = buf;
- t[1].rx_nbits = m25p80_rx_nbits(nor);
- t[1].len = min3(len, spi_max_transfer_size(spi),
- spi_max_message_size(spi) - t[0].len);
- spi_message_add_tail(&t[1], &m);
+ /*
+ * Set all dummy/mode cycle bits to avoid sending some manufacturer
+ * specific pattern, which might make the memory enter its Continuous
+ * Read mode by mistake.
+ * Based on the different mode cycle bit patterns listed and described
+ * in the JESD216B specification, the 0xff value works for all memories
+ * and all manufacturers.
+ */
+ cmd_sz = t[0].len;
+ memset(flash->command + cmd_sz - dummy, 0xff, dummy);
+
+ /* split the op code and address bytes into two transfers if needed. */
+ data_idx = 1;
+ if (addr_nbits != inst_nbits) {
+ t[0].len = 1;
+
+ t[1].tx_buf = &flash->command[1];
+ t[1].tx_nbits = addr_nbits;
+ t[1].len = cmd_sz - 1;
+ spi_message_add_tail(&t[1], &m);
+
+ data_idx = 2;
+ }
+
+ t[data_idx].rx_buf = buf;
+ t[data_idx].rx_nbits = data_nbits;
+ t[data_idx].len = min3(len, spi_max_transfer_size(spi),
+ spi_max_message_size(spi) - cmd_sz);
+ spi_message_add_tail(&t[data_idx], &m);
ret = spi_sync(spi, &m);
if (ret)
return ret;
- ret = m.actual_length - m25p_cmdsz(nor) - dummy;
+ ret = m.actual_length - cmd_sz;
if (ret < 0)
return -EIO;
return ret;
@@ -218,11 +265,20 @@ static int m25p_probe(struct spi_device *spi)
spi_set_drvdata(spi, flash);
flash->spi = spi;
- if (spi->mode & SPI_RX_QUAD)
+ if (spi->mode & SPI_RX_QUAD) {
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
- else if (spi->mode & SPI_RX_DUAL)
+
+ 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;
+ }
+
if (data && data->name)
nor->mtd.name = data->name;
--
2.9.3
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web