Skip to content

Commit a344b6c

Browse files
ambarusvarshini-rajendran
authored andcommitted
mtd: spi-nor: core: Allow specifying the byte order in DTR mode
Macronix swaps bytes on a 16-bit boundary when configured in Octal DTR. The byte order of 16-bit words is swapped when read or write written in 8D-8D-8D mode compared to STR modes. Swapping the bytes is a bad design decision because this may affect the boot sequence if the entire boot sequence is not handled in either 8D-8D-8D mode or 1-1-1 mode. Allow operations to specify the byte order in DTR mode, so that controllers can swap the bytes back at run-time to fix the endianness, if they are capable. The byte order in 8D-8D-8D mode can be retrieved at run-time by checking BFPT[DWORD(18)] BIT(31). When set to one, the "Byte order of 16-bit words is swapped when read in 8D-8D-8D mode compared to 1-1-1 mode.". It doesn't specify if this applies to both register and data operations. Macronix is the single user of this byte swap and it doesn't have clear rules, as it contains register operations that require data swap (RDPASS, WRPASS, PASSULK, RDSFDP) and register operations that don't require data swap (WRFBR). All these are not common and can be handled in 1-1-1 mode, so we can ignore them for now. All the other register operations are done on one byte length. The read register operations are actually in 8D-8D-8S mode, as they send the data value twice, on each half of the clock cycle. In case of a register write of one byte, the memory supports receiving the register value only on the first byte, thus it discards the value of the byte on the second half of the clock cycle. Swapping the bytes for one byte register writes is not required, and for one byte register reads it doesn't matter. Thus swap the bytes only for read or page program operations. Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> [varshini.rajendran@microchip.com: Ported to 6.1.4 by fixing merge conflicts] Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com> [varshini.rajendran@microchip.com: Ported to 6.6.9 by fixing merge conflicts] Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
1 parent 1b12a0c commit a344b6c

File tree

3 files changed

+42
-5
lines changed

3 files changed

+42
-5
lines changed

drivers/mtd/spi-nor/core.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor,
106106
op->dummy.dtr = true;
107107
op->data.dtr = true;
108108

109+
if (spi_nor_protocol_is_dtr_bswap16(proto))
110+
op->data.dtr_bswap16 = true;
111+
109112
/* 2 bytes per clock cycle in DTR mode. */
110113
op->dummy.nbytes *= 2;
111114

@@ -453,7 +456,7 @@ int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
453456
if (nor->spimem) {
454457
struct spi_mem_op op = SPI_NOR_RDSR_OP(sr);
455458

456-
if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
459+
if (spi_nor_protocol_is_octal_dtr(nor->reg_proto)) {
457460
op.addr.nbytes = nor->params->rdsr_addr_nbytes;
458461
op.dummy.nbytes = nor->params->rdsr_dummy;
459462
/*
@@ -2691,7 +2694,7 @@ static int spi_nor_set_addr_nbytes(struct spi_nor *nor)
26912694
{
26922695
if (nor->params->addr_nbytes) {
26932696
nor->addr_nbytes = nor->params->addr_nbytes;
2694-
} else if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) {
2697+
} else if (spi_nor_protocol_is_octal_dtr(nor->read_proto)) {
26952698
/*
26962699
* In 8D-8D-8D mode, one byte takes half a cycle to transfer. So
26972700
* in this protocol an odd addr_nbytes cannot be used because
@@ -2896,6 +2899,19 @@ static void spi_nor_init_fixup_flags(struct spi_nor *nor)
28962899
nor->flags |= SNOR_F_SOFT_RESET;
28972900
}
28982901

2902+
static void spi_nor_set_dtr_bswap16_ops(struct spi_nor *nor)
2903+
{
2904+
struct spi_nor_flash_parameter *params = nor->params;
2905+
u32 mask = SNOR_HWCAPS_READ_8_8_8_DTR | SNOR_HWCAPS_PP_8_8_8_DTR;
2906+
2907+
if ((params->hwcaps.mask & mask) == mask) {
2908+
params->reads[SNOR_CMD_READ_8_8_8_DTR].proto |=
2909+
SNOR_PROTO_IS_DTR_BSWAP16;
2910+
params->page_programs[SNOR_CMD_PP_8_8_8_DTR].proto |=
2911+
SNOR_PROTO_IS_DTR_BSWAP16;
2912+
}
2913+
}
2914+
28992915
/**
29002916
* spi_nor_late_init_params() - Late initialization of default flash parameters.
29012917
* @nor: pointer to a 'struct spi_nor'
@@ -2929,6 +2945,9 @@ static int spi_nor_late_init_params(struct spi_nor *nor)
29292945
spi_nor_init_flags(nor);
29302946
spi_nor_init_fixup_flags(nor);
29312947

2948+
if (nor->flags & SNOR_F_DTR_BSWAP16)
2949+
spi_nor_set_dtr_bswap16_ops(nor);
2950+
29322951
/*
29332952
* NOR protection support. When locking_ops are not provided, we pick
29342953
* the default ones.
@@ -3114,8 +3133,8 @@ static int spi_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
31143133
if (!nor->params->set_octal_dtr)
31153134
return 0;
31163135

3117-
if (!(nor->read_proto == SNOR_PROTO_8_8_8_DTR &&
3118-
nor->write_proto == SNOR_PROTO_8_8_8_DTR))
3136+
if (!(spi_nor_protocol_is_octal_dtr(nor->read_proto) &&
3137+
spi_nor_protocol_is_octal_dtr(nor->write_proto)))
31193138
return 0;
31203139

31213140
if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE))
@@ -3210,7 +3229,7 @@ static int spi_nor_init(struct spi_nor *nor)
32103229
spi_nor_try_unlock_all(nor);
32113230

32123231
if (nor->addr_nbytes == 4 &&
3213-
nor->read_proto != SNOR_PROTO_8_8_8_DTR &&
3232+
!spi_nor_protocol_is_octal_dtr(nor->read_proto) &&
32143233
!(nor->flags & SNOR_F_4B_OPCODES)) {
32153234
/*
32163235
* If the RESET# pin isn't hooked up properly, or the system

drivers/mtd/spi-nor/core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ enum spi_nor_option_flags {
133133
SNOR_F_RWW = BIT(14),
134134
SNOR_F_ECC = BIT(15),
135135
SNOR_F_NO_WP = BIT(16),
136+
SNOR_F_DTR_BSWAP16 = BIT(17),
136137
};
137138

138139
struct spi_nor_read_command {

include/linux/mtd/spi-nor.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@
147147
SNOR_PROTO_DATA_MASK)
148148

149149
#define SNOR_PROTO_IS_DTR BIT(24) /* Double Transfer Rate */
150+
/*
151+
* Byte order of 16-bit words is swapped when read or written in DTR mode
152+
* compared to STR mode.
153+
*/
154+
#define SNOR_PROTO_IS_DTR_BSWAP16 BIT(25)
150155

151156
#define SNOR_PROTO_STR(_inst_nbits, _addr_nbits, _data_nbits) \
152157
(SNOR_PROTO_INST(_inst_nbits) | \
@@ -180,6 +185,18 @@ static inline bool spi_nor_protocol_is_dtr(enum spi_nor_protocol proto)
180185
return !!(proto & SNOR_PROTO_IS_DTR);
181186
}
182187

188+
static inline bool spi_nor_protocol_is_octal_dtr(enum spi_nor_protocol proto)
189+
{
190+
return ((proto & SNOR_PROTO_8_8_8_DTR) == SNOR_PROTO_8_8_8_DTR);
191+
}
192+
193+
static inline bool spi_nor_protocol_is_dtr_bswap16(enum spi_nor_protocol proto)
194+
{
195+
u32 mask = SNOR_PROTO_IS_DTR | SNOR_PROTO_IS_DTR_BSWAP16;
196+
197+
return ((proto & mask) == mask);
198+
}
199+
183200
static inline u8 spi_nor_get_protocol_inst_nbits(enum spi_nor_protocol proto)
184201
{
185202
return ((unsigned long)(proto & SNOR_PROTO_INST_MASK)) >>

0 commit comments

Comments
 (0)