Skip to content

Commit 3a2639a

Browse files
robhancocksedkartben
authored andcommitted
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 <robert.hancock@calian.com>
1 parent ecacf3d commit 3a2639a

File tree

2 files changed

+56
-5
lines changed

2 files changed

+56
-5
lines changed

drivers/flash/spi_nor.c

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ LOG_MODULE_REGISTER(spi_nor, CONFIG_FLASH_LOG_LEVEL);
5555
#define ANY_INST_USE_4B_ADDR_OPCODES DT_ANY_INST_HAS_BOOL_STATUS_OKAY(use_4b_addr_opcodes)
5656
#define ANY_INST_HAS_FLSR \
5757
DT_ANY_INST_HAS_BOOL_STATUS_OKAY(use_flag_status_register)
58+
#define ANY_INST_USE_FAST_READ DT_ANY_INST_HAS_BOOL_STATUS_OKAY(use_fast_read)
5859

5960
#ifdef CONFIG_SPI_NOR_ACTIVE_DWELL_MS
6061
#define ACTIVE_DWELL_MS CONFIG_SPI_NOR_ACTIVE_DWELL_MS
@@ -153,6 +154,7 @@ struct spi_nor_config {
153154
bool wp_gpios_exist:1;
154155
bool hold_gpios_exist:1;
155156
bool has_flsr: 1;
157+
bool use_fast_read: 1;
156158
};
157159

158160
/**
@@ -359,6 +361,10 @@ static inline void delay_until_exit_dpd_ok(const struct device *const dev)
359361
*/
360362
#define NOR_ACCESS_32BIT_ADDR BIT(2)
361363

364+
/* Indicates that a dummy byte is to be sent following the address.
365+
*/
366+
#define NOR_ACCESS_DUMMY_BYTE BIT(3)
367+
362368
/* Indicates that an access command is performing a write. If not
363369
* provided access is a read.
364370
*/
@@ -384,7 +390,8 @@ static int spi_nor_access(const struct device *const dev,
384390
struct spi_nor_data *const driver_data = dev->data;
385391
bool is_addressed = (access & NOR_ACCESS_ADDRESSED) != 0U;
386392
bool is_write = (access & NOR_ACCESS_WRITE) != 0U;
387-
uint8_t buf[5] = {opcode};
393+
bool has_dummy = (access & NOR_ACCESS_DUMMY_BYTE) != 0U;
394+
uint8_t buf[6] = {opcode};
388395
struct spi_buf spi_buf_tx[2] = {
389396
{
390397
.buf = buf,
@@ -429,6 +436,10 @@ static int spi_nor_access(const struct device *const dev,
429436
spi_buf_rx[0].len += 3;
430437
}
431438
};
439+
if (has_dummy) {
440+
spi_buf_tx[0].len++;
441+
spi_buf_rx[0].len++;
442+
}
432443

433444
const struct spi_buf_set tx_set = {
434445
.buffers = spi_buf_tx,
@@ -457,6 +468,17 @@ static int spi_nor_access(const struct device *const dev,
457468
#define spi_nor_cmd_addr_read_4b(dev, opcode, addr, dest, length) \
458469
spi_nor_access(dev, opcode, NOR_ACCESS_32BIT_ADDR | NOR_ACCESS_ADDRESSED, addr, dest, \
459470
length)
471+
#define spi_nor_cmd_addr_fast_read(dev, opcode, addr, dest, length) \
472+
spi_nor_access(dev, opcode, NOR_ACCESS_ADDRESSED | NOR_ACCESS_DUMMY_BYTE, addr, dest, \
473+
length)
474+
#define spi_nor_cmd_addr_fast_read_3b(dev, opcode, addr, dest, length) \
475+
spi_nor_access(dev, opcode, \
476+
NOR_ACCESS_24BIT_ADDR | NOR_ACCESS_ADDRESSED | NOR_ACCESS_DUMMY_BYTE, addr, \
477+
dest, length)
478+
#define spi_nor_cmd_addr_fast_read_4b(dev, opcode, addr, dest, length) \
479+
spi_nor_access(dev, opcode, \
480+
NOR_ACCESS_32BIT_ADDR | NOR_ACCESS_ADDRESSED | NOR_ACCESS_DUMMY_BYTE, addr, \
481+
dest, length)
460482
#define spi_nor_cmd_write(dev, opcode) \
461483
spi_nor_access(dev, opcode, NOR_ACCESS_WRITE, 0, NULL, 0)
462484
#define spi_nor_cmd_addr_write(dev, opcode, addr, src, length) \
@@ -839,6 +861,7 @@ static int mxicy_configure(const struct device *dev, const uint8_t *jedec_id)
839861
static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
840862
size_t size)
841863
{
864+
const struct spi_nor_config *cfg = dev->config;
842865
const size_t flash_size = dev_flash_size(dev);
843866
int ret;
844867

@@ -854,14 +877,31 @@ static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
854877

855878
acquire_device(dev);
856879

857-
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) && DEV_CFG(dev)->use_4b_addr_opcodes) {
880+
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) && cfg->use_4b_addr_opcodes) {
858881
if (addr > SPI_NOR_3B_ADDR_MAX) {
859-
ret = spi_nor_cmd_addr_read_4b(dev, SPI_NOR_CMD_READ_4B, addr, dest, size);
882+
if (IS_ENABLED(ANY_INST_USE_FAST_READ) && cfg->use_fast_read) {
883+
ret = spi_nor_cmd_addr_fast_read_4b(dev, SPI_NOR_CMD_READ_FAST_4B,
884+
addr, dest, size);
885+
} else {
886+
ret = spi_nor_cmd_addr_read_4b(dev, SPI_NOR_CMD_READ_4B, addr, dest,
887+
size);
888+
}
860889
} else {
861-
ret = spi_nor_cmd_addr_read_3b(dev, SPI_NOR_CMD_READ, addr, dest, size);
890+
if (IS_ENABLED(ANY_INST_USE_FAST_READ) && cfg->use_fast_read) {
891+
ret = spi_nor_cmd_addr_fast_read_3b(dev, SPI_NOR_CMD_READ_FAST,
892+
addr, dest, size);
893+
} else {
894+
ret = spi_nor_cmd_addr_read_3b(dev, SPI_NOR_CMD_READ, addr, dest,
895+
size);
896+
}
862897
}
863898
} else {
864-
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
899+
if (IS_ENABLED(ANY_INST_USE_FAST_READ) && cfg->use_fast_read) {
900+
ret = spi_nor_cmd_addr_fast_read(dev, SPI_NOR_CMD_READ_FAST, addr, dest,
901+
size);
902+
} else {
903+
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
904+
}
865905
}
866906

867907
release_device(dev);
@@ -1859,6 +1899,7 @@ static DEVICE_API(flash, spi_nor_api) = {
18591899
.hold_gpios_exist = DT_INST_NODE_HAS_PROP(idx, hold_gpios), \
18601900
.use_4b_addr_opcodes = DT_INST_PROP(idx, use_4b_addr_opcodes), \
18611901
.has_flsr = DT_INST_PROP(idx, use_flag_status_register), \
1902+
.use_fast_read = DT_INST_PROP(idx, use_fast_read), \
18621903
IF_ENABLED(INST_HAS_LOCK(idx), (.has_lock = DT_INST_PROP(idx, has_lock),)) \
18631904
IF_ENABLED(ANY_INST_HAS_DPD, (INIT_T_ENTER_DPD(idx),)) \
18641905
IF_ENABLED(UTIL_AND(ANY_INST_HAS_DPD, ANY_INST_HAS_T_EXIT_DPD), \

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

Lines changed: 10 additions & 0 deletions
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)