1
0
Fork 0

This pull request contains the following notable changes:

- introduce support to the SPI 1-2-2 and 1-4-4 protocols.
 - introduce support to the Double Data Rate (DDR) mode.
 - introduce support to the Octo SPI protocols.
 - add support to new memory parts for Spansion, Macronix and Winbond.
 - add fixes for the Aspeed, STM32 and Cadence QSPI controler drivers.
 - clean up the st_spi_fsm driver.
 -----BEGIN PGP SIGNATURE-----
 
 iQI4BAABCAAiBQJZV6mQGxxjeXJpbGxlLnBpdGNoZW5Ad2VkZXY0dS5mcgAKCRDn
 4OgLHRpJcnqMD/9BVRi6qdKeGU3u6d1osgXSCwnFQ8K4vKzgjht+oNmd3vUTDjbd
 cbqtSQUGeXsBRwA6JJXQlRJOB9+hsaBrBjfeG/LuDFgFvGWJ2vevgd1v0FftSiqE
 jA+Vg6CuIZJvNjdl1E1UsXJ8hcP4xcQADzd8bhjqhQsZOLYfGqG6/nPSpiUI4JWU
 3KsNhJ6HoN/PWNBRNjanGm6d6HRyu0C/GtDT0N9tGKqupas/xkH/cPCHyCkF8nBH
 Tp/IPTw6KmyVBmtMzcTzlR/SVUld3LEZfFQk5FpO8InwUArx4lyKCDp4EIWhhBEC
 QSTL7EmqUuAZTq+JhSyniVjUw9GA54hKcHBaH3NC5uaV0d3cePaWt8rtxKGXVH13
 9SY5U4IBlAzEDC3gpD777Lu4Qhj3YelLetRPUtumnc6i7t0qYFIWgO/3yFxYSWdH
 pFYmIooqG0DQzpwmFTFFiGep4fftxNyMA5DhlzZWfU3OKbvPJ2035QSz5nu/iysZ
 hhYV205FTsE0D33eBFoVkijKn3mEosTlVyvVofkaFbz6dqIY3t8vv8Wx07aEpTqF
 WcQ3iCw7x9nO/dBQ/Q25fTvssOlcNzrB4v+SlGfxcFH3gHprwx7PEaT1YHf9qtaF
 4hP4UludGHCUZgOZGxfk0r5aLNmXD8aNUhEGkt44pdrItDDRfWQTUc0fcQ==
 =ZHnm
 -----END PGP SIGNATURE-----

Merge tag 'spi-nor/for-4.13' into MTD

From Cyrille:
"""
This pull request contains the following notable changes:
- introduce support to the SPI 1-2-2 and 1-4-4 protocols.
- introduce support to the Double Data Rate (DDR) mode.
- introduce support to the Octo SPI protocols.
- add support to new memory parts for Spansion, Macronix and Winbond.
- add fixes for the Aspeed, STM32 and Cadence QSPI controler drivers.
- clean up the st_spi_fsm driver.
"""
hifive-unleashed-5.1
Brian Norris 2017-07-07 18:00:06 -07:00
commit 8b9ef8f955
15 changed files with 937 additions and 239 deletions

View File

@ -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,18 +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)
{
switch (nor->flash_read) {
case SPI_NOR_DUAL:
return 2;
case SPI_NOR_QUAD:
return 4;
default:
return 0;
}
}
/*
* Read an address range from the nor chip. The address range
* may be any size provided it is within the physical boundaries.
@ -130,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;
@ -149,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)
@ -167,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;
@ -196,7 +236,11 @@ static int m25p_probe(struct spi_device *spi)
struct flash_platform_data *data;
struct m25p *flash;
struct spi_nor *nor;
enum read_mode mode = SPI_NOR_NORMAL;
struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_PP,
};
char *flash_name;
int ret;
@ -221,10 +265,19 @@ static int m25p_probe(struct spi_device *spi)
spi_set_drvdata(spi, flash);
flash->spi = spi;
if (spi->mode & SPI_RX_QUAD)
mode = SPI_NOR_QUAD;
else if (spi->mode & SPI_RX_DUAL)
mode = SPI_NOR_DUAL;
if (spi->mode & SPI_RX_QUAD) {
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
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;
@ -241,7 +294,7 @@ static int m25p_probe(struct spi_device *spi)
else
flash_name = spi->modalias;
ret = spi_nor_scan(nor, flash_name, mode);
ret = spi_nor_scan(nor, flash_name, &hwcaps);
if (ret)
return ret;

View File

@ -13,7 +13,6 @@
#define _MTD_SERIAL_FLASH_CMDS_H
/* Generic Flash Commands/OPCODEs */
#define SPINOR_OP_RDSR2 0x35
#define SPINOR_OP_WRVCR 0x81
#define SPINOR_OP_RDVCR 0x85

View File

@ -1445,7 +1445,7 @@ static int stfsm_s25fl_config(struct stfsm *fsm)
}
/* Check status of 'QE' bit, update if required. */
stfsm_read_status(fsm, SPINOR_OP_RDSR2, &cr1, 1);
stfsm_read_status(fsm, SPINOR_OP_RDCR, &cr1, 1);
data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
if (data_pads == 4) {
if (!(cr1 & STFSM_S25FL_CONFIG_QE)) {
@ -1490,7 +1490,7 @@ static int stfsm_w25q_config(struct stfsm *fsm)
return ret;
/* Check status of 'QE' bit, update if required. */
stfsm_read_status(fsm, SPINOR_OP_RDSR2, &sr2, 1);
stfsm_read_status(fsm, SPINOR_OP_RDCR, &sr2, 1);
data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
if (data_pads == 4) {
if (!(sr2 & W25Q_STATUS_QE)) {

View File

@ -108,7 +108,7 @@ config SPI_INTEL_SPI_PLATFORM
config SPI_STM32_QUADSPI
tristate "STM32 Quad SPI controller"
depends on ARCH_STM32
depends on ARCH_STM32 || COMPILE_TEST
help
This enables support for the STM32 Quad SPI controller.
We only connect the NOR to this controller.

View File

@ -19,6 +19,7 @@
#include <linux/mtd/spi-nor.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/sizes.h>
#include <linux/sysfs.h>
#define DEVICE_NAME "aspeed-smc"
@ -97,6 +98,7 @@ struct aspeed_smc_chip {
struct aspeed_smc_controller *controller;
void __iomem *ctl; /* control register */
void __iomem *ahb_base; /* base of chip window */
u32 ahb_window_size; /* chip mapping window size */
u32 ctl_val[smc_max]; /* control settings */
enum aspeed_smc_flash_type type; /* what type of flash */
struct spi_nor nor;
@ -109,6 +111,7 @@ struct aspeed_smc_controller {
const struct aspeed_smc_info *info; /* type info of controller */
void __iomem *regs; /* controller registers */
void __iomem *ahb_base; /* per-chip windows resource */
u32 ahb_window_size; /* full mapping window size */
struct aspeed_smc_chip *chips[0]; /* pointers to attached chips */
};
@ -180,8 +183,7 @@ struct aspeed_smc_controller {
#define CONTROL_KEEP_MASK \
(CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \
CONTROL_IO_DUMMY_MASK | CONTROL_CLOCK_FREQ_SEL_MASK | \
CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
CONTROL_CLOCK_FREQ_SEL_MASK | CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
/*
* The Segment Register uses a 8MB unit to encode the start address
@ -194,6 +196,10 @@ struct aspeed_smc_controller {
#define SEGMENT_ADDR_REG0 0x30
#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23)
#define SEGMENT_ADDR_END(_r) ((((_r) >> 24) & 0xFF) << 23)
#define SEGMENT_ADDR_VALUE(start, end) \
(((((start) >> 23) & 0xFF) << 16) | ((((end) >> 23) & 0xFF) << 24))
#define SEGMENT_ADDR_REG(controller, cs) \
((controller)->regs + SEGMENT_ADDR_REG0 + (cs) * 4)
/*
* In user mode all data bytes read or written to the chip decode address
@ -439,8 +445,7 @@ static void __iomem *aspeed_smc_chip_base(struct aspeed_smc_chip *chip,
u32 reg;
if (controller->info->nce > 1) {
reg = readl(controller->regs + SEGMENT_ADDR_REG0 +
chip->cs * 4);
reg = readl(SEGMENT_ADDR_REG(controller, chip->cs));
if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg))
return NULL;
@ -451,6 +456,146 @@ static void __iomem *aspeed_smc_chip_base(struct aspeed_smc_chip *chip,
return controller->ahb_base + offset;
}
static u32 aspeed_smc_ahb_base_phy(struct aspeed_smc_controller *controller)
{
u32 seg0_val = readl(SEGMENT_ADDR_REG(controller, 0));
return SEGMENT_ADDR_START(seg0_val);
}
static u32 chip_set_segment(struct aspeed_smc_chip *chip, u32 cs, u32 start,
u32 size)
{
struct aspeed_smc_controller *controller = chip->controller;
void __iomem *seg_reg;
u32 seg_oldval, seg_newval, ahb_base_phy, end;
ahb_base_phy = aspeed_smc_ahb_base_phy(controller);
seg_reg = SEGMENT_ADDR_REG(controller, cs);
seg_oldval = readl(seg_reg);
/*
* If the chip size is not specified, use the default segment
* size, but take into account the possible overlap with the
* previous segment
*/
if (!size)
size = SEGMENT_ADDR_END(seg_oldval) - start;
/*
* The segment cannot exceed the maximum window size of the
* controller.
*/
if (start + size > ahb_base_phy + controller->ahb_window_size) {
size = ahb_base_phy + controller->ahb_window_size - start;
dev_warn(chip->nor.dev, "CE%d window resized to %dMB",
cs, size >> 20);
}
end = start + size;
seg_newval = SEGMENT_ADDR_VALUE(start, end);
writel(seg_newval, seg_reg);
/*
* Restore default value if something goes wrong. The chip
* might have set some bogus value and we would loose access
* to the chip.
*/
if (seg_newval != readl(seg_reg)) {
dev_err(chip->nor.dev, "CE%d window invalid", cs);
writel(seg_oldval, seg_reg);
start = SEGMENT_ADDR_START(seg_oldval);
end = SEGMENT_ADDR_END(seg_oldval);
size = end - start;
}
dev_info(chip->nor.dev, "CE%d window [ 0x%.8x - 0x%.8x ] %dMB",
cs, start, end, size >> 20);
return size;
}
/*
* The segment register defines the mapping window on the AHB bus and
* it needs to be configured depending on the chip size. The segment
* register of the following CE also needs to be tuned in order to
* provide a contiguous window across multiple chips.
*
* This is expected to be called in increasing CE order
*/
static u32 aspeed_smc_chip_set_segment(struct aspeed_smc_chip *chip)
{
struct aspeed_smc_controller *controller = chip->controller;
u32 ahb_base_phy, start;
u32 size = chip->nor.mtd.size;
/*
* Each controller has a chip size limit for direct memory
* access
*/
if (size > controller->info->maxsize)
size = controller->info->maxsize;
/*
* The AST2400 SPI controller only handles one chip and does
* not have segment registers. Let's use the chip size for the
* AHB window.
*/
if (controller->info == &spi_2400_info)
goto out;
/*
* The AST2500 SPI controller has a HW bug when the CE0 chip
* size reaches 128MB. Enforce a size limit of 120MB to
* prevent the controller from using bogus settings in the
* segment register.
*/
if (chip->cs == 0 && controller->info == &spi_2500_info &&
size == SZ_128M) {
size = 120 << 20;
dev_info(chip->nor.dev,
"CE%d window resized to %dMB (AST2500 HW quirk)",
chip->cs, size >> 20);
}
ahb_base_phy = aspeed_smc_ahb_base_phy(controller);
/*
* As a start address for the current segment, use the default
* start address if we are handling CE0 or use the previous
* segment ending address
*/
if (chip->cs) {
u32 prev = readl(SEGMENT_ADDR_REG(controller, chip->cs - 1));
start = SEGMENT_ADDR_END(prev);
} else {
start = ahb_base_phy;
}
size = chip_set_segment(chip, chip->cs, start, size);
/* Update chip base address on the AHB bus */
chip->ahb_base = controller->ahb_base + (start - ahb_base_phy);
/*
* Now, make sure the next segment does not overlap with the
* current one we just configured, even if there is no
* available chip. That could break access in Command Mode.
*/
if (chip->cs < controller->info->nce - 1)
chip_set_segment(chip, chip->cs + 1, start + size, 0);
out:
if (size < chip->nor.mtd.size)
dev_warn(chip->nor.dev,
"CE%d window too small for chip %dMB",
chip->cs, (u32)chip->nor.mtd.size >> 20);
return size;
}
static void aspeed_smc_chip_enable_write(struct aspeed_smc_chip *chip)
{
struct aspeed_smc_controller *controller = chip->controller;
@ -524,7 +669,7 @@ static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
*/
chip->ahb_base = aspeed_smc_chip_base(chip, res);
if (!chip->ahb_base) {
dev_warn(chip->nor.dev, "CE segment window closed.\n");
dev_warn(chip->nor.dev, "CE%d window closed", chip->cs);
return -EINVAL;
}
@ -571,6 +716,9 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
if (chip->nor.addr_width == 4 && info->set_4b)
info->set_4b(chip);
/* This is for direct AHB access when using Command Mode. */
chip->ahb_window_size = aspeed_smc_chip_set_segment(chip);
/*
* base mode has not been optimized yet. use it for writes.
*/
@ -585,14 +733,12 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
* TODO: Adjust clocks if fast read is supported and interpret
* SPI-NOR flags to adjust controller settings.
*/
switch (chip->nor.flash_read) {
case SPI_NOR_NORMAL:
cmd = CONTROL_COMMAND_MODE_NORMAL;
break;
case SPI_NOR_FAST:
cmd = CONTROL_COMMAND_MODE_FREAD;
break;
default:
if (chip->nor.read_proto == SNOR_PROTO_1_1_1) {
if (chip->nor.read_dummy == 0)
cmd = CONTROL_COMMAND_MODE_NORMAL;
else
cmd = CONTROL_COMMAND_MODE_FREAD;
} else {
dev_err(chip->nor.dev, "unsupported SPI read mode\n");
return -EINVAL;
}
@ -608,6 +754,11 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
struct device_node *np, struct resource *r)
{
const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_PP,
};
const struct aspeed_smc_info *info = controller->info;
struct device *dev = controller->dev;
struct device_node *child;
@ -671,11 +822,11 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
break;
/*
* TODO: Add support for SPI_NOR_QUAD and SPI_NOR_DUAL
* TODO: Add support for Dual and Quad SPI protocols
* attach when board support is present as determined
* by of property.
*/
ret = spi_nor_scan(nor, NULL, SPI_NOR_NORMAL);
ret = spi_nor_scan(nor, NULL, &hwcaps);
if (ret)
break;
@ -731,6 +882,8 @@ static int aspeed_smc_probe(struct platform_device *pdev)
if (IS_ERR(controller->ahb_base))
return PTR_ERR(controller->ahb_base);
controller->ahb_window_size = resource_size(res);
ret = aspeed_smc_setup_flash(controller, np, res);
if (ret)
dev_err(dev, "Aspeed SMC probe failed %d\n", ret);

View File

@ -275,14 +275,48 @@ static void atmel_qspi_debug_command(struct atmel_qspi *aq,
static int atmel_qspi_run_command(struct atmel_qspi *aq,
const struct atmel_qspi_command *cmd,
u32 ifr_tfrtyp, u32 ifr_width)
u32 ifr_tfrtyp, enum spi_nor_protocol proto)
{
u32 iar, icr, ifr, sr;
int err = 0;
iar = 0;
icr = 0;
ifr = ifr_tfrtyp | ifr_width;
ifr = ifr_tfrtyp;
/* Set the SPI protocol */
switch (proto) {
case SNOR_PROTO_1_1_1:
ifr |= QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
break;
case SNOR_PROTO_1_1_2:
ifr |= QSPI_IFR_WIDTH_DUAL_OUTPUT;
break;
case SNOR_PROTO_1_1_4:
ifr |= QSPI_IFR_WIDTH_QUAD_OUTPUT;
break;
case SNOR_PROTO_1_2_2:
ifr |= QSPI_IFR_WIDTH_DUAL_IO;
break;
case SNOR_PROTO_1_4_4:
ifr |= QSPI_IFR_WIDTH_QUAD_IO;
break;
case SNOR_PROTO_2_2_2:
ifr |= QSPI_IFR_WIDTH_DUAL_CMD;
break;
case SNOR_PROTO_4_4_4:
ifr |= QSPI_IFR_WIDTH_QUAD_CMD;
break;
default:
return -EINVAL;
}
/* Compute instruction parameters */
if (cmd->enable.bits.instruction) {
@ -434,7 +468,7 @@ static int atmel_qspi_read_reg(struct spi_nor *nor, u8 opcode,
cmd.rx_buf = buf;
cmd.buf_len = len;
return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ,
QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
nor->reg_proto);
}
static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
@ -450,7 +484,7 @@ static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
cmd.tx_buf = buf;
cmd.buf_len = len;
return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
nor->reg_proto);
}
static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
@ -469,7 +503,7 @@ static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
cmd.tx_buf = write_buf;
cmd.buf_len = len;
ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM,
QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
nor->write_proto);
return (ret < 0) ? ret : len;
}
@ -484,7 +518,7 @@ static int atmel_qspi_erase(struct spi_nor *nor, loff_t offs)
cmd.instruction = nor->erase_opcode;
cmd.address = (u32)offs;
return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
nor->reg_proto);
}
static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
@ -493,27 +527,8 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
struct atmel_qspi *aq = nor->priv;
struct atmel_qspi_command cmd;
u8 num_mode_cycles, num_dummy_cycles;
u32 ifr_width;
ssize_t ret;
switch (nor->flash_read) {
case SPI_NOR_NORMAL:
case SPI_NOR_FAST:
ifr_width = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
break;
case SPI_NOR_DUAL:
ifr_width = QSPI_IFR_WIDTH_DUAL_OUTPUT;
break;
case SPI_NOR_QUAD:
ifr_width = QSPI_IFR_WIDTH_QUAD_OUTPUT;
break;
default:
return -EINVAL;
}
if (nor->read_dummy >= 2) {
num_mode_cycles = 2;
num_dummy_cycles = nor->read_dummy - 2;
@ -536,7 +551,7 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
cmd.rx_buf = read_buf;
cmd.buf_len = len;
ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ_MEM,
ifr_width);
nor->read_proto);
return (ret < 0) ? ret : len;
}
@ -590,6 +605,20 @@ static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
static int atmel_qspi_probe(struct platform_device *pdev)
{
const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_READ_1_1_2 |
SNOR_HWCAPS_READ_1_2_2 |
SNOR_HWCAPS_READ_2_2_2 |
SNOR_HWCAPS_READ_1_1_4 |
SNOR_HWCAPS_READ_1_4_4 |
SNOR_HWCAPS_READ_4_4_4 |
SNOR_HWCAPS_PP |
SNOR_HWCAPS_PP_1_1_4 |
SNOR_HWCAPS_PP_1_4_4 |
SNOR_HWCAPS_PP_4_4_4,
};
struct device_node *child, *np = pdev->dev.of_node;
struct atmel_qspi *aq;
struct resource *res;
@ -679,7 +708,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
if (err)
goto disable_clk;
err = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
err = spi_nor_scan(nor, NULL, &hwcaps);
if (err)
goto disable_clk;

View File

@ -855,15 +855,14 @@ static int cqspi_set_protocol(struct spi_nor *nor, const int read)
f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
if (read) {
switch (nor->flash_read) {
case SPI_NOR_NORMAL:
case SPI_NOR_FAST:
switch (nor->read_proto) {
case SNOR_PROTO_1_1_1:
f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
break;
case SPI_NOR_DUAL:
case SNOR_PROTO_1_1_2:
f_pdata->data_width = CQSPI_INST_TYPE_DUAL;
break;
case SPI_NOR_QUAD:
case SNOR_PROTO_1_1_4:
f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
break;
default:
@ -1069,6 +1068,13 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
{
const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_READ_1_1_2 |
SNOR_HWCAPS_READ_1_1_4 |
SNOR_HWCAPS_PP,
};
struct platform_device *pdev = cqspi->pdev;
struct device *dev = &pdev->dev;
struct cqspi_flash_pdata *f_pdata;
@ -1123,7 +1129,7 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
goto err;
}
ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
ret = spi_nor_scan(nor, NULL, &hwcaps);
if (ret)
goto err;
@ -1277,7 +1283,7 @@ static const struct dev_pm_ops cqspi__dev_pm_ops = {
#define CQSPI_DEV_PM_OPS NULL
#endif
static struct of_device_id const cqspi_dt_ids[] = {
static const struct of_device_id cqspi_dt_ids[] = {
{.compatible = "cdns,qspi-nor",},
{ /* end of table */ }
};

View File

@ -957,6 +957,10 @@ static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
static int fsl_qspi_probe(struct platform_device *pdev)
{
const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ_1_1_4 |
SNOR_HWCAPS_PP,
};
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct fsl_qspi *q;
@ -1065,7 +1069,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
/* set the chip address for READID */
fsl_qspi_set_base_addr(q, nor);
ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
ret = spi_nor_scan(nor, NULL, &hwcaps);
if (ret)
goto mutex_failed;

View File

@ -120,19 +120,24 @@ static inline int wait_op_finish(struct hifmc_host *host)
(reg & FMC_INT_OP_DONE), 0, FMC_WAIT_TIMEOUT);
}
static int get_if_type(enum read_mode flash_read)
static int get_if_type(enum spi_nor_protocol proto)
{
enum hifmc_iftype if_type;
switch (flash_read) {
case SPI_NOR_DUAL:
switch (proto) {
case SNOR_PROTO_1_1_2:
if_type = IF_TYPE_DUAL;
break;
case SPI_NOR_QUAD:
case SNOR_PROTO_1_2_2:
if_type = IF_TYPE_DIO;
break;
case SNOR_PROTO_1_1_4:
if_type = IF_TYPE_QUAD;
break;
case SPI_NOR_NORMAL:
case SPI_NOR_FAST:
case SNOR_PROTO_1_4_4:
if_type = IF_TYPE_QIO;
break;
case SNOR_PROTO_1_1_1:
default:
if_type = IF_TYPE_STD;
break;
@ -253,7 +258,10 @@ static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off,
writel(FMC_DMA_LEN_SET(len), host->regbase + FMC_DMA_LEN);
reg = OP_CFG_FM_CS(priv->chipselect);
if_type = get_if_type(nor->flash_read);
if (op_type == FMC_OP_READ)
if_type = get_if_type(nor->read_proto);
else
if_type = get_if_type(nor->write_proto);
reg |= OP_CFG_MEM_IF_TYPE(if_type);
if (op_type == FMC_OP_READ)
reg |= OP_CFG_DUMMY_NUM(nor->read_dummy >> 3);
@ -321,6 +329,13 @@ static ssize_t hisi_spi_nor_write(struct spi_nor *nor, loff_t to,
static int hisi_spi_nor_register(struct device_node *np,
struct hifmc_host *host)
{
const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_READ_1_1_2 |
SNOR_HWCAPS_READ_1_1_4 |
SNOR_HWCAPS_PP,
};
struct device *dev = host->dev;
struct spi_nor *nor;
struct hifmc_priv *priv;
@ -362,7 +377,7 @@ static int hisi_spi_nor_register(struct device_node *np,
nor->read = hisi_spi_nor_read;
nor->write = hisi_spi_nor_write;
nor->erase = NULL;
ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
ret = spi_nor_scan(nor, NULL, &hwcaps);
if (ret)
return ret;

View File

@ -715,6 +715,11 @@ static void intel_spi_fill_partition(struct intel_spi *ispi,
struct intel_spi *intel_spi_probe(struct device *dev,
struct resource *mem, const struct intel_spi_boardinfo *info)
{
const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_PP,
};
struct mtd_partition part;
struct intel_spi *ispi;
int ret;
@ -746,7 +751,7 @@ struct intel_spi *intel_spi_probe(struct device *dev,
ispi->nor.write = intel_spi_write;
ispi->nor.erase = intel_spi_erase;
ret = spi_nor_scan(&ispi->nor, NULL, SPI_NOR_NORMAL);
ret = spi_nor_scan(&ispi->nor, NULL, &hwcaps);
if (ret) {
dev_info(dev, "failed to locate the chip\n");
return ERR_PTR(ret);

View File

@ -123,20 +123,20 @@ static void mt8173_nor_set_read_mode(struct mt8173_nor *mt8173_nor)
{
struct spi_nor *nor = &mt8173_nor->nor;
switch (nor->flash_read) {
case SPI_NOR_FAST:
switch (nor->read_proto) {
case SNOR_PROTO_1_1_1:
writeb(nor->read_opcode, mt8173_nor->base +
MTK_NOR_PRGDATA3_REG);
writeb(MTK_NOR_FAST_READ, mt8173_nor->base +
MTK_NOR_CFG1_REG);
break;
case SPI_NOR_DUAL:
case SNOR_PROTO_1_1_2:
writeb(nor->read_opcode, mt8173_nor->base +
MTK_NOR_PRGDATA3_REG);
writeb(MTK_NOR_DUAL_READ_EN, mt8173_nor->base +
MTK_NOR_DUAL_REG);
break;
case SPI_NOR_QUAD:
case SNOR_PROTO_1_1_4:
writeb(nor->read_opcode, mt8173_nor->base +
MTK_NOR_PRGDATA4_REG);
writeb(MTK_NOR_QUAD_READ_EN, mt8173_nor->base +
@ -408,6 +408,11 @@ static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
struct device_node *flash_node)
{
const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_READ_1_1_2 |
SNOR_HWCAPS_PP,
};
int ret;
struct spi_nor *nor;
@ -426,7 +431,7 @@ static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
nor->write_reg = mt8173_nor_write_reg;
nor->mtd.name = "mtk_nor";
/* initialized with NULL */
ret = spi_nor_scan(nor, NULL, SPI_NOR_DUAL);
ret = spi_nor_scan(nor, NULL, &hwcaps);
if (ret)
return ret;

View File

@ -240,13 +240,12 @@ static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs)
static int nxp_spifi_setup_memory_cmd(struct nxp_spifi *spifi)
{
switch (spifi->nor.flash_read) {
case SPI_NOR_NORMAL:
case SPI_NOR_FAST:
switch (spifi->nor.read_proto) {
case SNOR_PROTO_1_1_1:
spifi->mcmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL;
break;
case SPI_NOR_DUAL:
case SPI_NOR_QUAD:
case SNOR_PROTO_1_1_2:
case SNOR_PROTO_1_1_4:
spifi->mcmd = SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA;
break;
default:
@ -274,7 +273,11 @@ static void nxp_spifi_dummy_id_read(struct spi_nor *nor)
static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
struct device_node *np)
{
enum read_mode flash_read;
struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_PP,
};
u32 ctrl, property;
u16 mode = 0;
int ret;
@ -308,13 +311,12 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
if (mode & SPI_RX_DUAL) {
ctrl |= SPIFI_CTRL_DUAL;
flash_read = SPI_NOR_DUAL;
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
} else if (mode & SPI_RX_QUAD) {
ctrl &= ~SPIFI_CTRL_DUAL;
flash_read = SPI_NOR_QUAD;
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
} else {
ctrl |= SPIFI_CTRL_DUAL;
flash_read = SPI_NOR_NORMAL;
}
switch (mode & (SPI_CPHA | SPI_CPOL)) {
@ -351,7 +353,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
*/
nxp_spifi_dummy_id_read(&spifi->nor);
ret = spi_nor_scan(&spifi->nor, NULL, flash_read);
ret = spi_nor_scan(&spifi->nor, NULL, &hwcaps);
if (ret) {
dev_err(spifi->dev, "device scan failed\n");
return ret;

View File

@ -149,24 +149,6 @@ static int read_cr(struct spi_nor *nor)
return val;
}
/*
* Dummy Cycle calculation for different type of read.
* It can be used to support more commands with
* different dummy cycle requirements.
*/
static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
{
switch (nor->flash_read) {
case SPI_NOR_FAST:
case SPI_NOR_DUAL:
case SPI_NOR_QUAD:
return 8;
case SPI_NOR_NORMAL:
return 0;
}
return 0;
}
/*
* Write status register 1 byte
* Returns negative if error occurred.
@ -221,6 +203,10 @@ static inline u8 spi_nor_convert_3to4_read(u8 opcode)
{ SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B },
{ SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B },
{ SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B },
{ SPINOR_OP_READ_1_1_1_DTR, SPINOR_OP_READ_1_1_1_DTR_4B },
{ SPINOR_OP_READ_1_2_2_DTR, SPINOR_OP_READ_1_2_2_DTR_4B },
{ SPINOR_OP_READ_1_4_4_DTR, SPINOR_OP_READ_1_4_4_DTR_4B },
};
return spi_nor_convert_opcode(opcode, spi_nor_3to4_read,
@ -1022,10 +1008,12 @@ static const struct flash_info spi_nor_ids[] = {
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ "mx66l1g45g", INFO(0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
/* Micron */
@ -1036,7 +1024,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
@ -1076,6 +1064,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) },
{ "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ) },
{ "s25fl208k", INFO(0x014014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) },
{ "s25fl064l", INFO(0x016017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
@ -1159,7 +1148,9 @@ static const struct flash_info spi_nor_ids[] = {
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) },
/* Catalyst / On Semiconductor -- non-JEDEC */
{ "cat25c11", CAT25_INFO( 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
@ -1403,8 +1394,9 @@ static int macronix_quad_enable(struct spi_nor *nor)
write_sr(nor, val | SR_QUAD_EN_MX);
if (spi_nor_wait_till_ready(nor))
return 1;
ret = spi_nor_wait_till_ready(nor);
if (ret)
return ret;
ret = read_sr(nor);
if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
@ -1460,30 +1452,6 @@ static int spansion_quad_enable(struct spi_nor *nor)
return 0;
}
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;
}
}
static int spi_nor_check(struct spi_nor *nor)
{
if (!nor->dev || !nor->read || !nor->write ||
@ -1536,8 +1504,349 @@ static int s3an_nor_scan(const struct flash_info *info, struct spi_nor *nor)
return 0;
}
int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
struct spi_nor_read_command {
u8 num_mode_clocks;
u8 num_wait_states;
u8 opcode;
enum spi_nor_protocol proto;
};
struct spi_nor_pp_command {
u8 opcode;
enum spi_nor_protocol proto;
};
enum spi_nor_read_command_index {
SNOR_CMD_READ,
SNOR_CMD_READ_FAST,
SNOR_CMD_READ_1_1_1_DTR,
/* Dual SPI */
SNOR_CMD_READ_1_1_2,
SNOR_CMD_READ_1_2_2,
SNOR_CMD_READ_2_2_2,
SNOR_CMD_READ_1_2_2_DTR,
/* Quad SPI */
SNOR_CMD_READ_1_1_4,
SNOR_CMD_READ_1_4_4,
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
};
enum spi_nor_pp_command_index {
SNOR_CMD_PP,
/* Quad SPI */
SNOR_CMD_PP_1_1_4,
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
};
struct spi_nor_flash_parameter {
u64 size;
u32 page_size;
struct spi_nor_hwcaps hwcaps;
struct spi_nor_read_command reads[SNOR_CMD_READ_MAX];
struct spi_nor_pp_command page_programs[SNOR_CMD_PP_MAX];
int (*quad_enable)(struct spi_nor *nor);
};
static void
spi_nor_set_read_settings(struct spi_nor_read_command *read,
u8 num_mode_clocks,
u8 num_wait_states,
u8 opcode,
enum spi_nor_protocol proto)
{
read->num_mode_clocks = num_mode_clocks;
read->num_wait_states = num_wait_states;
read->opcode = opcode;
read->proto = proto;
}
static void
spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
u8 opcode,
enum spi_nor_protocol proto)
{
pp->opcode = opcode;
pp->proto = proto;
}
static int spi_nor_init_params(struct spi_nor *nor,
const struct flash_info *info,
struct spi_nor_flash_parameter *params)
{
/* Set legacy flash parameters as default. */
memset(params, 0, sizeof(*params));
/* Set SPI NOR sizes. */
params->size = info->sector_size * info->n_sectors;
params->page_size = info->page_size;
/* (Fast) Read settings. */
params->hwcaps.mask |= SNOR_HWCAPS_READ;
spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ],
0, 0, SPINOR_OP_READ,
SNOR_PROTO_1_1_1);
if (!(info->flags & SPI_NOR_NO_FR)) {
params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_FAST],
0, 8, SPINOR_OP_READ_FAST,
SNOR_PROTO_1_1_1);
}
if (info->flags & SPI_NOR_DUAL_READ) {
params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_1_1_2],
0, 8, SPINOR_OP_READ_1_1_2,
SNOR_PROTO_1_1_2);
}
if (info->flags & SPI_NOR_QUAD_READ) {
params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_1_1_4],
0, 8, SPINOR_OP_READ_1_1_4,
SNOR_PROTO_1_1_4);
}
/* Page Program settings. */
params->hwcaps.mask |= SNOR_HWCAPS_PP;
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
SPINOR_OP_PP, SNOR_PROTO_1_1_1);
/* Select the procedure to set the Quad Enable bit. */
if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD |
SNOR_HWCAPS_PP_QUAD)) {
switch (JEDEC_MFR(info)) {
case SNOR_MFR_MACRONIX:
params->quad_enable = macronix_quad_enable;
break;
case SNOR_MFR_MICRON:
break;
default:
params->quad_enable = spansion_quad_enable;
break;
}
}
return 0;
}
static int spi_nor_hwcaps2cmd(u32 hwcaps, const int table[][2], size_t size)
{
size_t i;
for (i = 0; i < size; i++)
if (table[i][0] == (int)hwcaps)
return table[i][1];
return -EINVAL;
}
static int spi_nor_hwcaps_read2cmd(u32 hwcaps)
{
static const int hwcaps_read2cmd[][2] = {
{ SNOR_HWCAPS_READ, SNOR_CMD_READ },
{ SNOR_HWCAPS_READ_FAST, SNOR_CMD_READ_FAST },
{ SNOR_HWCAPS_READ_1_1_1_DTR, SNOR_CMD_READ_1_1_1_DTR },
{ SNOR_HWCAPS_READ_1_1_2, SNOR_CMD_READ_1_1_2 },
{ SNOR_HWCAPS_READ_1_2_2, SNOR_CMD_READ_1_2_2 },
{ SNOR_HWCAPS_READ_2_2_2, SNOR_CMD_READ_2_2_2 },
{ SNOR_HWCAPS_READ_1_2_2_DTR, SNOR_CMD_READ_1_2_2_DTR },
{ SNOR_HWCAPS_READ_1_1_4, SNOR_CMD_READ_1_1_4 },
{ 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,
ARRAY_SIZE(hwcaps_read2cmd));
}
static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
{
static const int hwcaps_pp2cmd[][2] = {
{ SNOR_HWCAPS_PP, SNOR_CMD_PP },
{ 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,
ARRAY_SIZE(hwcaps_pp2cmd));
}
static int spi_nor_select_read(struct spi_nor *nor,
const struct spi_nor_flash_parameter *params,
u32 shared_hwcaps)
{
int cmd, best_match = fls(shared_hwcaps & SNOR_HWCAPS_READ_MASK) - 1;
const struct spi_nor_read_command *read;
if (best_match < 0)
return -EINVAL;
cmd = spi_nor_hwcaps_read2cmd(BIT(best_match));
if (cmd < 0)
return -EINVAL;
read = &params->reads[cmd];
nor->read_opcode = read->opcode;
nor->read_proto = read->proto;
/*
* In the spi-nor framework, we don't need to make the difference
* between mode clock cycles and wait state clock cycles.
* Indeed, the value of the mode clock cycles is used by a QSPI
* flash memory to know whether it should enter or leave its 0-4-4
* (Continuous Read / XIP) mode.
* eXecution In Place is out of the scope of the mtd sub-system.
* Hence we choose to merge both mode and wait state clock cycles
* into the so called dummy clock cycles.
*/
nor->read_dummy = read->num_mode_clocks + read->num_wait_states;
return 0;
}
static int spi_nor_select_pp(struct spi_nor *nor,
const struct spi_nor_flash_parameter *params,
u32 shared_hwcaps)
{
int cmd, best_match = fls(shared_hwcaps & SNOR_HWCAPS_PP_MASK) - 1;
const struct spi_nor_pp_command *pp;
if (best_match < 0)
return -EINVAL;
cmd = spi_nor_hwcaps_pp2cmd(BIT(best_match));
if (cmd < 0)
return -EINVAL;
pp = &params->page_programs[cmd];
nor->program_opcode = pp->opcode;
nor->write_proto = pp->proto;
return 0;
}
static int spi_nor_select_erase(struct spi_nor *nor,
const struct flash_info *info)
{
struct mtd_info *mtd = &nor->mtd;
#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
/* prefer "small sector" erase if possible */
if (info->flags & SECT_4K) {
nor->erase_opcode = SPINOR_OP_BE_4K;
mtd->erasesize = 4096;
} else if (info->flags & SECT_4K_PMC) {
nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
mtd->erasesize = 4096;
} else
#endif
{
nor->erase_opcode = SPINOR_OP_SE;
mtd->erasesize = info->sector_size;
}
return 0;
}
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)
{
u32 ignored_mask, shared_mask;
bool enable_quad_io;
int err;
/*
* Keep only the hardware capabilities supported by both the SPI
* controller and the SPI flash memory.
*/
shared_mask = hwcaps->mask & params->hwcaps.mask;
/* 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_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");
shared_mask &= ~ignored_mask;
}
/* Select the (Fast) Read command. */
err = spi_nor_select_read(nor, params, shared_mask);
if (err) {
dev_err(nor->dev,
"can't select read settings supported by both the SPI controller and memory.\n");
return err;
}
/* Select the Page Program command. */
err = spi_nor_select_pp(nor, params, shared_mask);
if (err) {
dev_err(nor->dev,
"can't select write settings supported by both the SPI controller and memory.\n");
return err;
}
/* Select the Sector Erase command. */
err = spi_nor_select_erase(nor, info);
if (err) {
dev_err(nor->dev,
"can't select erase settings supported by both the SPI controller and memory.\n");
return err;
}
/* Enable Quad I/O if needed. */
enable_quad_io = (spi_nor_get_protocol_width(nor->read_proto) == 4 ||
spi_nor_get_protocol_width(nor->write_proto) == 4);
if (enable_quad_io && params->quad_enable) {
err = params->quad_enable(nor);
if (err) {
dev_err(nor->dev, "quad mode not supported\n");
return err;
}
}
return 0;
}
int spi_nor_scan(struct spi_nor *nor, const char *name,
const struct spi_nor_hwcaps *hwcaps)
{
struct spi_nor_flash_parameter params;
const struct flash_info *info = NULL;
struct device *dev = nor->dev;
struct mtd_info *mtd = &nor->mtd;
@ -1549,6 +1858,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
if (ret)
return ret;
/* Reset SPI protocol for all commands. */
nor->reg_proto = SNOR_PROTO_1_1_1;
nor->read_proto = SNOR_PROTO_1_1_1;
nor->write_proto = SNOR_PROTO_1_1_1;
if (name)
info = spi_nor_match_id(name);
/* Try to auto-detect if chip name wasn't specified or not found */
@ -1591,6 +1905,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
if (info->flags & SPI_S3AN)
nor->flags |= SNOR_F_READY_XSR_RDY;
/* Parse the Serial Flash Discoverable Parameters table. */
ret = spi_nor_init_params(nor, info, &params);
if (ret)
return ret;
/*
* Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
* with the software protection bits set
@ -1611,7 +1930,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
mtd->type = MTD_NORFLASH;
mtd->writesize = 1;
mtd->flags = MTD_CAP_NORFLASH;
mtd->size = info->sector_size * info->n_sectors;
mtd->size = params.size;
mtd->_erase = spi_nor_erase;
mtd->_read = spi_nor_read;
@ -1642,75 +1961,38 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
if (info->flags & NO_CHIP_ERASE)
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
/* prefer "small sector" erase if possible */
if (info->flags & SECT_4K) {
nor->erase_opcode = SPINOR_OP_BE_4K;
mtd->erasesize = 4096;
} else if (info->flags & SECT_4K_PMC) {
nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
mtd->erasesize = 4096;
} else
#endif
{
nor->erase_opcode = SPINOR_OP_SE;
mtd->erasesize = info->sector_size;
}
if (info->flags & SPI_NOR_NO_ERASE)
mtd->flags |= MTD_NO_ERASE;
mtd->dev.parent = dev;
nor->page_size = info->page_size;
nor->page_size = params.page_size;
mtd->writebufsize = nor->page_size;
if (np) {
/* If we were instantiated by DT, use it */
if (of_property_read_bool(np, "m25p,fast-read"))
nor->flash_read = SPI_NOR_FAST;
params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
else
nor->flash_read = SPI_NOR_NORMAL;
params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
} else {
/* If we weren't instantiated by DT, default to fast-read */
nor->flash_read = SPI_NOR_FAST;
params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
}
/* Some devices cannot do fast-read, no matter what DT tells us */
if (info->flags & SPI_NOR_NO_FR)
nor->flash_read = SPI_NOR_NORMAL;
params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
/* Quad/Dual-read mode takes precedence over fast/normal */
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;
} else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
nor->flash_read = SPI_NOR_DUAL;
}
/* Default commands */
switch (nor->flash_read) {
case SPI_NOR_QUAD:
nor->read_opcode = SPINOR_OP_READ_1_1_4;
break;
case SPI_NOR_DUAL:
nor->read_opcode = SPINOR_OP_READ_1_1_2;
break;
case SPI_NOR_FAST:
nor->read_opcode = SPINOR_OP_READ_FAST;
break;
case SPI_NOR_NORMAL:
nor->read_opcode = SPINOR_OP_READ;
break;
default:
dev_err(dev, "No Read opcode defined\n");
return -EINVAL;
}
nor->program_opcode = SPINOR_OP_PP;
/*
* Configure the SPI memory:
* - select op codes for (Fast) Read, Page Program and Sector Erase.
* - set the number of dummy cycles (mode cycles + wait states).
* - set the SPI protocols for register and memory accesses.
* - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
*/
ret = spi_nor_setup(nor, info, &params, hwcaps);
if (ret)
return ret;
if (info->addr_width)
nor->addr_width = info->addr_width;
@ -1732,8 +2014,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
return -EINVAL;
}
nor->read_dummy = spi_nor_read_dummy_cycles(nor);
if (info->flags & SPI_S3AN) {
ret = s3an_nor_scan(info, nor);
if (ret)

View File

@ -19,6 +19,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/sizes.h>
#define QUADSPI_CR 0x00
#define CR_EN BIT(0)
@ -192,15 +193,15 @@ static void stm32_qspi_set_framemode(struct spi_nor *nor,
cmd->framemode = CCR_IMODE_1;
if (read) {
switch (nor->flash_read) {
case SPI_NOR_NORMAL:
case SPI_NOR_FAST:
switch (nor->read_proto) {
default:
case SNOR_PROTO_1_1_1:
dmode = CCR_DMODE_1;
break;
case SPI_NOR_DUAL:
case SNOR_PROTO_1_1_2:
dmode = CCR_DMODE_2;
break;
case SPI_NOR_QUAD:
case SNOR_PROTO_1_1_4:
dmode = CCR_DMODE_4;
break;
}
@ -375,7 +376,7 @@ static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
struct stm32_qspi_cmd cmd;
int err;
dev_dbg(qspi->dev, "read(%#.2x): buf:%p from:%#.8x len:%#x\n",
dev_dbg(qspi->dev, "read(%#.2x): buf:%p from:%#.8x len:%#zx\n",
nor->read_opcode, buf, (u32)from, len);
memset(&cmd, 0, sizeof(cmd));
@ -402,7 +403,7 @@ static ssize_t stm32_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
struct stm32_qspi_cmd cmd;
int err;
dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#x\n",
dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#zx\n",
nor->program_opcode, buf, (u32)to, len);
memset(&cmd, 0, sizeof(cmd));
@ -480,7 +481,12 @@ static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
struct device_node *np)
{
u32 width, flash_read, presc, cs_num, max_rate = 0;
struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_PP,
};
u32 width, presc, cs_num, max_rate = 0;
struct stm32_qspi_flash *flash;
struct mtd_info *mtd;
int ret;
@ -499,12 +505,10 @@ static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
width = 1;
if (width == 4)
flash_read = SPI_NOR_QUAD;
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
else if (width == 2)
flash_read = SPI_NOR_DUAL;
else if (width == 1)
flash_read = SPI_NOR_NORMAL;
else
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
else if (width != 1)
return -EINVAL;
flash = &qspi->flash[cs_num];
@ -539,7 +543,7 @@ static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
*/
flash->fsize = FSIZE_VAL(SZ_1K);
ret = spi_nor_scan(&flash->nor, NULL, flash_read);
ret = spi_nor_scan(&flash->nor, NULL, &hwcaps);
if (ret) {
dev_err(qspi->dev, "device scan failed\n");
return ret;

View File

@ -73,6 +73,15 @@
#define SPINOR_OP_BE_32K_4B 0x5c /* Erase 32KiB block */
#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */
/* Double Transfer Rate opcodes - defined in JEDEC JESD216B. */
#define SPINOR_OP_READ_1_1_1_DTR 0x0d
#define SPINOR_OP_READ_1_2_2_DTR 0xbd
#define SPINOR_OP_READ_1_4_4_DTR 0xed
#define SPINOR_OP_READ_1_1_1_DTR_4B 0x0e
#define SPINOR_OP_READ_1_2_2_DTR_4B 0xbe
#define SPINOR_OP_READ_1_4_4_DTR_4B 0xee
/* Used for SST flashes only. */
#define SPINOR_OP_BP 0x02 /* Byte program */
#define SPINOR_OP_WRDI 0x04 /* Write disable */
@ -119,13 +128,81 @@
/* Configuration Register bits. */
#define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */
enum read_mode {
SPI_NOR_NORMAL = 0,
SPI_NOR_FAST,
SPI_NOR_DUAL,
SPI_NOR_QUAD,
/* Supported SPI protocols */
#define SNOR_PROTO_INST_MASK GENMASK(23, 16)
#define SNOR_PROTO_INST_SHIFT 16
#define SNOR_PROTO_INST(_nbits) \
((((unsigned long)(_nbits)) << SNOR_PROTO_INST_SHIFT) & \
SNOR_PROTO_INST_MASK)
#define SNOR_PROTO_ADDR_MASK GENMASK(15, 8)
#define SNOR_PROTO_ADDR_SHIFT 8
#define SNOR_PROTO_ADDR(_nbits) \
((((unsigned long)(_nbits)) << SNOR_PROTO_ADDR_SHIFT) & \
SNOR_PROTO_ADDR_MASK)
#define SNOR_PROTO_DATA_MASK GENMASK(7, 0)
#define SNOR_PROTO_DATA_SHIFT 0
#define SNOR_PROTO_DATA(_nbits) \
((((unsigned long)(_nbits)) << SNOR_PROTO_DATA_SHIFT) & \
SNOR_PROTO_DATA_MASK)
#define SNOR_PROTO_IS_DTR BIT(24) /* Double Transfer Rate */
#define SNOR_PROTO_STR(_inst_nbits, _addr_nbits, _data_nbits) \
(SNOR_PROTO_INST(_inst_nbits) | \
SNOR_PROTO_ADDR(_addr_nbits) | \
SNOR_PROTO_DATA(_data_nbits))
#define SNOR_PROTO_DTR(_inst_nbits, _addr_nbits, _data_nbits) \
(SNOR_PROTO_IS_DTR | \
SNOR_PROTO_STR(_inst_nbits, _addr_nbits, _data_nbits))
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)
{
return !!(proto & SNOR_PROTO_IS_DTR);
}
static inline u8 spi_nor_get_protocol_inst_nbits(enum spi_nor_protocol proto)
{
return ((unsigned long)(proto & SNOR_PROTO_INST_MASK)) >>
SNOR_PROTO_INST_SHIFT;
}
static inline u8 spi_nor_get_protocol_addr_nbits(enum spi_nor_protocol proto)
{
return ((unsigned long)(proto & SNOR_PROTO_ADDR_MASK)) >>
SNOR_PROTO_ADDR_SHIFT;
}
static inline u8 spi_nor_get_protocol_data_nbits(enum spi_nor_protocol proto)
{
return ((unsigned long)(proto & SNOR_PROTO_DATA_MASK)) >>
SNOR_PROTO_DATA_SHIFT;
}
static inline u8 spi_nor_get_protocol_width(enum spi_nor_protocol proto)
{
return spi_nor_get_protocol_data_nbits(proto);
}
#define SPI_NOR_MAX_CMD_SIZE 8
enum spi_nor_ops {
SPI_NOR_OPS_READ = 0,
@ -154,9 +231,11 @@ enum spi_nor_option_flags {
* @read_opcode: the read opcode
* @read_dummy: the dummy needed by the read operation
* @program_opcode: the program opcode
* @flash_read: the mode of the read
* @sst_write_second: used by the SST write operation
* @flags: flag options for the current SPI-NOR (SNOR_F_*)
* @read_proto: the SPI protocol for read operations
* @write_proto: the SPI protocol for write operations
* @reg_proto the SPI protocol for read_reg/write_reg/erase operations
* @cmd_buf: used by the write_reg
* @prepare: [OPTIONAL] do some preparations for the
* read/write/erase/lock/unlock operations
@ -185,7 +264,9 @@ struct spi_nor {
u8 read_opcode;
u8 read_dummy;
u8 program_opcode;
enum read_mode flash_read;
enum spi_nor_protocol read_proto;
enum spi_nor_protocol write_proto;
enum spi_nor_protocol reg_proto;
bool sst_write_second;
u32 flags;
u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
@ -219,11 +300,72 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
return mtd_get_of_node(&nor->mtd);
}
/**
* struct spi_nor_hwcaps - Structure for describing the hardware capabilies
* supported by the SPI controller (bus master).
* @mask: the bitmask listing all the supported hw capabilies
*/
struct spi_nor_hwcaps {
u32 mask;
};
/*
*(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 Octo SPI protocols first,
* then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
* (Slow) Read.
*/
#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)
#define SNOR_HWCAPS_READ_DUAL GENMASK(6, 3)
#define SNOR_HWCAPS_READ_1_1_2 BIT(3)
#define SNOR_HWCAPS_READ_1_2_2 BIT(4)
#define SNOR_HWCAPS_READ_2_2_2 BIT(5)
#define SNOR_HWCAPS_READ_1_2_2_DTR BIT(6)
#define SNOR_HWCAPS_READ_QUAD GENMASK(10, 7)
#define SNOR_HWCAPS_READ_1_1_4 BIT(7)
#define SNOR_HWCAPS_READ_1_4_4 BIT(8)
#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, 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(22, 16)
#define SNOR_HWCAPS_PP BIT(16)
#define SNOR_HWCAPS_PP_QUAD GENMASK(19, 17)
#define SNOR_HWCAPS_PP_1_1_4 BIT(17)
#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
* @name: the chip type name
* @mode: the read mode supported by the driver
* @hwcaps: the hardware capabilities supported by the controller driver
*
* The drivers can use this fuction to scan the SPI NOR.
* In the scanning, it will try to get all the necessary information to
@ -233,6 +375,7 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
*
* Return: 0 for success, others for failure.
*/
int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode);
int spi_nor_scan(struct spi_nor *nor, const char *name,
const struct spi_nor_hwcaps *hwcaps);
#endif