Skip to content

Commit 1969727

Browse files
committed
drivers: flash: spi_nor: Add fast read support
Most SPI NOR flash devices support a "fast read" command which uses dummy bits between the address and the start of the data transfer. In many cases, the maximum SPI clock speed of the device is lower for the regular read command due to the limited time between the address and data phases, so using the fast read command will remove this restriction and allow for faster transfers. Add a device tree flag to indicate that fast reads should be used for the device. Signed-off-by: Robert Hancock <[email protected]>
1 parent 4c49222 commit 1969727

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

drivers/flash/spi_nor.c

+45-5
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ struct spi_nor_config {
153153
bool wp_gpios_exist:1;
154154
bool hold_gpios_exist:1;
155155
bool has_flsr: 1;
156+
bool use_fast_read: 1;
156157
};
157158

158159
/**
@@ -359,6 +360,10 @@ static inline void delay_until_exit_dpd_ok(const struct device *const dev)
359360
*/
360361
#define NOR_ACCESS_32BIT_ADDR BIT(2)
361362

363+
/* Indicates that a dummy byte is to be sent following the address.
364+
*/
365+
#define NOR_ACCESS_DUMMY_BYTE BIT(3)
366+
362367
/* Indicates that an access command is performing a write. If not
363368
* provided access is a read.
364369
*/
@@ -384,7 +389,8 @@ static int spi_nor_access(const struct device *const dev,
384389
struct spi_nor_data *const driver_data = dev->data;
385390
bool is_addressed = (access & NOR_ACCESS_ADDRESSED) != 0U;
386391
bool is_write = (access & NOR_ACCESS_WRITE) != 0U;
387-
uint8_t cmd_buf[5] = {opcode};
392+
bool has_dummy = (access & NOR_ACCESS_DUMMY_BYTE) != 0U;
393+
uint8_t cmd_buf[6] = {opcode};
388394
struct spi_buf spi_buf_tx[2] = {{
389395
.buf = cmd_buf,
390396
.len = 1,
@@ -419,6 +425,10 @@ static int spi_nor_access(const struct device *const dev,
419425
spi_buf_rx[0].len += 3;
420426
}
421427
};
428+
if (has_dummy) {
429+
spi_buf_tx[0].len++;
430+
spi_buf_rx[0].len++;
431+
}
422432

423433
const struct spi_buf_set tx_set = {
424434
.buffers = spi_buf_tx,
@@ -447,6 +457,17 @@ static int spi_nor_access(const struct device *const dev,
447457
#define spi_nor_cmd_addr_read_4b(dev, opcode, addr, dest, length) \
448458
spi_nor_access(dev, opcode, NOR_ACCESS_32BIT_ADDR | NOR_ACCESS_ADDRESSED, addr, dest, \
449459
length)
460+
#define spi_nor_cmd_addr_fast_read(dev, opcode, addr, dest, length) \
461+
spi_nor_access(dev, opcode, NOR_ACCESS_ADDRESSED | NOR_ACCESS_DUMMY_BYTE, addr, dest, \
462+
length)
463+
#define spi_nor_cmd_addr_fast_read_3b(dev, opcode, addr, dest, length) \
464+
spi_nor_access(dev, opcode, \
465+
NOR_ACCESS_24BIT_ADDR | NOR_ACCESS_ADDRESSED | NOR_ACCESS_DUMMY_BYTE, addr, \
466+
dest, length)
467+
#define spi_nor_cmd_addr_fast_read_4b(dev, opcode, addr, dest, length) \
468+
spi_nor_access(dev, opcode, \
469+
NOR_ACCESS_32BIT_ADDR | NOR_ACCESS_ADDRESSED | NOR_ACCESS_DUMMY_BYTE, addr, \
470+
dest, length)
450471
#define spi_nor_cmd_write(dev, opcode) \
451472
spi_nor_access(dev, opcode, NOR_ACCESS_WRITE, 0, NULL, 0)
452473
#define spi_nor_cmd_addr_write(dev, opcode, addr, src, length) \
@@ -834,6 +855,7 @@ static int mxicy_configure(const struct device *dev, const uint8_t *jedec_id)
834855
static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
835856
size_t size)
836857
{
858+
const struct spi_nor_config *cfg = dev->config;
837859
const size_t flash_size = dev_flash_size(dev);
838860
int ret;
839861

@@ -849,14 +871,31 @@ static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
849871

850872
acquire_device(dev);
851873

852-
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) && DEV_CFG(dev)->use_4b_addr_opcodes) {
874+
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) && cfg->use_4b_addr_opcodes) {
853875
if (addr > SPI_NOR_3B_ADDR_MAX) {
854-
ret = spi_nor_cmd_addr_read_4b(dev, SPI_NOR_CMD_READ_4B, addr, dest, size);
876+
if (cfg->use_fast_read) {
877+
ret = spi_nor_cmd_addr_fast_read_4b(dev, SPI_NOR_CMD_READ_FAST_4B,
878+
addr, dest, size);
879+
} else {
880+
ret = spi_nor_cmd_addr_read_4b(dev, SPI_NOR_CMD_READ_4B, addr, dest,
881+
size);
882+
}
855883
} else {
856-
ret = spi_nor_cmd_addr_read_3b(dev, SPI_NOR_CMD_READ, addr, dest, size);
884+
if (cfg->use_fast_read) {
885+
ret = spi_nor_cmd_addr_fast_read_3b(dev, SPI_NOR_CMD_READ_FAST,
886+
addr, dest, size);
887+
} else {
888+
ret = spi_nor_cmd_addr_read_3b(dev, SPI_NOR_CMD_READ, addr, dest,
889+
size);
890+
}
857891
}
858892
} else {
859-
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
893+
if (cfg->use_fast_read) {
894+
ret = spi_nor_cmd_addr_fast_read(dev, SPI_NOR_CMD_READ_FAST, addr, dest,
895+
size);
896+
} else {
897+
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
898+
}
860899
}
861900

862901
release_device(dev);
@@ -1856,6 +1895,7 @@ static DEVICE_API(flash, spi_nor_api) = {
18561895
.hold_gpios_exist = DT_INST_NODE_HAS_PROP(idx, hold_gpios), \
18571896
.use_4b_addr_opcodes = DT_INST_PROP(idx, use_4b_addr_opcodes), \
18581897
.has_flsr = DT_INST_PROP(idx, use_flag_status_register), \
1898+
.use_fast_read = DT_INST_PROP(idx, use_fast_read), \
18591899
IF_ENABLED(INST_HAS_LOCK(idx), (.has_lock = DT_INST_PROP(idx, has_lock),)) \
18601900
IF_ENABLED(ANY_INST_HAS_DPD, (INIT_T_ENTER_DPD(idx),)) \
18611901
IF_ENABLED(UTIL_AND(ANY_INST_HAS_DPD, ANY_INST_HAS_T_EXIT_DPD), \

dts/bindings/mtd/jedec,spi-nor-common.yaml

+10
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,13 @@ properties:
123123
which indicates more details on the status of program or erase operations.
124124
In some cases, program operations will not function properly if the flag
125125
status register is not read after the operation.
126+
127+
use-fast-read:
128+
type: boolean
129+
description: |
130+
Indicates the device supports fast read.
131+
132+
Most SPI NOR devices support a fast read command that allows the device to
133+
output data at a higher clock rate than the standard read command. This
134+
property indicates that the device supports the fast read command with
135+
8 dummy cycles after the address phase of the command.

0 commit comments

Comments
 (0)