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 m25p *flash = nor->priv;
struct spi_device *spi = flash->spi; 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; struct spi_message m;
int cmd_sz = m25p_cmdsz(nor); int cmd_sz = m25p_cmdsz(nor);
ssize_t ret; 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); spi_message_init(&m);
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) 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); m25p_addr2cmd(nor, to, flash->command);
t[0].tx_buf = flash->command; t[0].tx_buf = flash->command;
t[0].tx_nbits = inst_nbits;
t[0].len = cmd_sz; t[0].len = cmd_sz;
spi_message_add_tail(&t[0], &m); spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf; /* split the op code and address bytes into two transfers if needed. */
t[1].len = len; data_idx = 1;
spi_message_add_tail(&t[1], &m); 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); ret = spi_sync(spi, &m);
if (ret) if (ret)
@ -109,18 +130,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
return ret; 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 * Read an address range from the nor chip. The address range
* may be any size provided it is within the physical boundaries. * 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 m25p *flash = nor->priv;
struct spi_device *spi = flash->spi; 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; struct spi_message m;
unsigned int dummy = nor->read_dummy; unsigned int dummy = nor->read_dummy;
ssize_t ret; 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 */ /* convert the dummy cycles to the number of bytes */
dummy /= 8; dummy = (dummy * addr_nbits) / 8;
if (spi_flash_read_supported(spi)) { if (spi_flash_read_supported(spi)) {
struct spi_flash_read_message msg; 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.read_opcode = nor->read_opcode;
msg.addr_width = nor->addr_width; msg.addr_width = nor->addr_width;
msg.dummy_bytes = dummy; msg.dummy_bytes = dummy;
/* TODO: Support other combinations */ msg.opcode_nbits = inst_nbits;
msg.opcode_nbits = SPI_NBITS_SINGLE; msg.addr_nbits = addr_nbits;
msg.addr_nbits = SPI_NBITS_SINGLE; msg.data_nbits = data_nbits;
msg.data_nbits = m25p80_rx_nbits(nor);
ret = spi_flash_read(spi, &msg); ret = spi_flash_read(spi, &msg);
if (ret < 0) 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); m25p_addr2cmd(nor, from, flash->command);
t[0].tx_buf = flash->command; t[0].tx_buf = flash->command;
t[0].tx_nbits = inst_nbits;
t[0].len = m25p_cmdsz(nor) + dummy; t[0].len = m25p_cmdsz(nor) + dummy;
spi_message_add_tail(&t[0], &m); spi_message_add_tail(&t[0], &m);
t[1].rx_buf = buf; /*
t[1].rx_nbits = m25p80_rx_nbits(nor); * Set all dummy/mode cycle bits to avoid sending some manufacturer
t[1].len = min3(len, spi_max_transfer_size(spi), * specific pattern, which might make the memory enter its Continuous
spi_max_message_size(spi) - t[0].len); * Read mode by mistake.
spi_message_add_tail(&t[1], &m); * 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); ret = spi_sync(spi, &m);
if (ret) if (ret)
return ret; return ret;
ret = m.actual_length - m25p_cmdsz(nor) - dummy; ret = m.actual_length - cmd_sz;
if (ret < 0) if (ret < 0)
return -EIO; return -EIO;
return ret; return ret;
@ -196,7 +236,11 @@ static int m25p_probe(struct spi_device *spi)
struct flash_platform_data *data; struct flash_platform_data *data;
struct m25p *flash; struct m25p *flash;
struct spi_nor *nor; 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; char *flash_name;
int ret; int ret;
@ -221,10 +265,19 @@ static int m25p_probe(struct spi_device *spi)
spi_set_drvdata(spi, flash); spi_set_drvdata(spi, flash);
flash->spi = spi; flash->spi = spi;
if (spi->mode & SPI_RX_QUAD) if (spi->mode & SPI_RX_QUAD) {
mode = SPI_NOR_QUAD; hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
else if (spi->mode & SPI_RX_DUAL)
mode = SPI_NOR_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) if (data && data->name)
nor->mtd.name = data->name; nor->mtd.name = data->name;
@ -241,7 +294,7 @@ static int m25p_probe(struct spi_device *spi)
else else
flash_name = spi->modalias; flash_name = spi->modalias;
ret = spi_nor_scan(nor, flash_name, mode); ret = spi_nor_scan(nor, flash_name, &hwcaps);
if (ret) if (ret)
return ret; return ret;

View File

@ -13,7 +13,6 @@
#define _MTD_SERIAL_FLASH_CMDS_H #define _MTD_SERIAL_FLASH_CMDS_H
/* Generic Flash Commands/OPCODEs */ /* Generic Flash Commands/OPCODEs */
#define SPINOR_OP_RDSR2 0x35
#define SPINOR_OP_WRVCR 0x81 #define SPINOR_OP_WRVCR 0x81
#define SPINOR_OP_RDVCR 0x85 #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. */ /* 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; data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
if (data_pads == 4) { if (data_pads == 4) {
if (!(cr1 & STFSM_S25FL_CONFIG_QE)) { if (!(cr1 & STFSM_S25FL_CONFIG_QE)) {
@ -1490,7 +1490,7 @@ static int stfsm_w25q_config(struct stfsm *fsm)
return ret; return ret;
/* Check status of 'QE' bit, update if required. */ /* 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; data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
if (data_pads == 4) { if (data_pads == 4) {
if (!(sr2 & W25Q_STATUS_QE)) { if (!(sr2 & W25Q_STATUS_QE)) {

View File

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

View File

@ -19,6 +19,7 @@
#include <linux/mtd/spi-nor.h> #include <linux/mtd/spi-nor.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/sizes.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#define DEVICE_NAME "aspeed-smc" #define DEVICE_NAME "aspeed-smc"
@ -97,6 +98,7 @@ struct aspeed_smc_chip {
struct aspeed_smc_controller *controller; struct aspeed_smc_controller *controller;
void __iomem *ctl; /* control register */ void __iomem *ctl; /* control register */
void __iomem *ahb_base; /* base of chip window */ void __iomem *ahb_base; /* base of chip window */
u32 ahb_window_size; /* chip mapping window size */
u32 ctl_val[smc_max]; /* control settings */ u32 ctl_val[smc_max]; /* control settings */
enum aspeed_smc_flash_type type; /* what type of flash */ enum aspeed_smc_flash_type type; /* what type of flash */
struct spi_nor nor; struct spi_nor nor;
@ -109,6 +111,7 @@ struct aspeed_smc_controller {
const struct aspeed_smc_info *info; /* type info of controller */ const struct aspeed_smc_info *info; /* type info of controller */
void __iomem *regs; /* controller registers */ void __iomem *regs; /* controller registers */
void __iomem *ahb_base; /* per-chip windows resource */ 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 */ struct aspeed_smc_chip *chips[0]; /* pointers to attached chips */
}; };
@ -180,8 +183,7 @@ struct aspeed_smc_controller {
#define CONTROL_KEEP_MASK \ #define CONTROL_KEEP_MASK \
(CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \ (CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \
CONTROL_IO_DUMMY_MASK | CONTROL_CLOCK_FREQ_SEL_MASK | \ CONTROL_CLOCK_FREQ_SEL_MASK | CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
/* /*
* The Segment Register uses a 8MB unit to encode the start address * 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_REG0 0x30
#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23) #define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23)
#define SEGMENT_ADDR_END(_r) ((((_r) >> 24) & 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 * 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; u32 reg;
if (controller->info->nce > 1) { if (controller->info->nce > 1) {
reg = readl(controller->regs + SEGMENT_ADDR_REG0 + reg = readl(SEGMENT_ADDR_REG(controller, chip->cs));
chip->cs * 4);
if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg)) if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg))
return NULL; return NULL;
@ -451,6 +456,146 @@ static void __iomem *aspeed_smc_chip_base(struct aspeed_smc_chip *chip,
return controller->ahb_base + offset; 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) static void aspeed_smc_chip_enable_write(struct aspeed_smc_chip *chip)
{ {
struct aspeed_smc_controller *controller = chip->controller; 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); chip->ahb_base = aspeed_smc_chip_base(chip, res);
if (!chip->ahb_base) { 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; 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) if (chip->nor.addr_width == 4 && info->set_4b)
info->set_4b(chip); 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. * 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 * TODO: Adjust clocks if fast read is supported and interpret
* SPI-NOR flags to adjust controller settings. * SPI-NOR flags to adjust controller settings.
*/ */
switch (chip->nor.flash_read) { if (chip->nor.read_proto == SNOR_PROTO_1_1_1) {
case SPI_NOR_NORMAL: if (chip->nor.read_dummy == 0)
cmd = CONTROL_COMMAND_MODE_NORMAL; cmd = CONTROL_COMMAND_MODE_NORMAL;
break; else
case SPI_NOR_FAST: cmd = CONTROL_COMMAND_MODE_FREAD;
cmd = CONTROL_COMMAND_MODE_FREAD; } else {
break;
default:
dev_err(chip->nor.dev, "unsupported SPI read mode\n"); dev_err(chip->nor.dev, "unsupported SPI read mode\n");
return -EINVAL; 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, static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
struct device_node *np, struct resource *r) 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; const struct aspeed_smc_info *info = controller->info;
struct device *dev = controller->dev; struct device *dev = controller->dev;
struct device_node *child; struct device_node *child;
@ -671,11 +822,11 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
break; 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 * attach when board support is present as determined
* by of property. * by of property.
*/ */
ret = spi_nor_scan(nor, NULL, SPI_NOR_NORMAL); ret = spi_nor_scan(nor, NULL, &hwcaps);
if (ret) if (ret)
break; break;
@ -731,6 +882,8 @@ static int aspeed_smc_probe(struct platform_device *pdev)
if (IS_ERR(controller->ahb_base)) if (IS_ERR(controller->ahb_base))
return PTR_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); ret = aspeed_smc_setup_flash(controller, np, res);
if (ret) if (ret)
dev_err(dev, "Aspeed SMC probe failed %d\n", 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, static int atmel_qspi_run_command(struct atmel_qspi *aq,
const struct atmel_qspi_command *cmd, 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; u32 iar, icr, ifr, sr;
int err = 0; int err = 0;
iar = 0; iar = 0;
icr = 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 */ /* Compute instruction parameters */
if (cmd->enable.bits.instruction) { 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.rx_buf = buf;
cmd.buf_len = len; cmd.buf_len = len;
return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ, 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, 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.tx_buf = buf;
cmd.buf_len = len; cmd.buf_len = len;
return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE, 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, 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.tx_buf = write_buf;
cmd.buf_len = len; cmd.buf_len = len;
ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM, 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; 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.instruction = nor->erase_opcode;
cmd.address = (u32)offs; cmd.address = (u32)offs;
return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE, 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, 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 *aq = nor->priv;
struct atmel_qspi_command cmd; struct atmel_qspi_command cmd;
u8 num_mode_cycles, num_dummy_cycles; u8 num_mode_cycles, num_dummy_cycles;
u32 ifr_width;
ssize_t ret; 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) { if (nor->read_dummy >= 2) {
num_mode_cycles = 2; num_mode_cycles = 2;
num_dummy_cycles = nor->read_dummy - 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.rx_buf = read_buf;
cmd.buf_len = len; cmd.buf_len = len;
ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ_MEM, ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ_MEM,
ifr_width); nor->read_proto);
return (ret < 0) ? ret : len; 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) 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 device_node *child, *np = pdev->dev.of_node;
struct atmel_qspi *aq; struct atmel_qspi *aq;
struct resource *res; struct resource *res;
@ -679,7 +708,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
if (err) if (err)
goto disable_clk; goto disable_clk;
err = spi_nor_scan(nor, NULL, SPI_NOR_QUAD); err = spi_nor_scan(nor, NULL, &hwcaps);
if (err) if (err)
goto disable_clk; 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; f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
if (read) { if (read) {
switch (nor->flash_read) { switch (nor->read_proto) {
case SPI_NOR_NORMAL: case SNOR_PROTO_1_1_1:
case SPI_NOR_FAST:
f_pdata->data_width = CQSPI_INST_TYPE_SINGLE; f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
break; break;
case SPI_NOR_DUAL: case SNOR_PROTO_1_1_2:
f_pdata->data_width = CQSPI_INST_TYPE_DUAL; f_pdata->data_width = CQSPI_INST_TYPE_DUAL;
break; break;
case SPI_NOR_QUAD: case SNOR_PROTO_1_1_4:
f_pdata->data_width = CQSPI_INST_TYPE_QUAD; f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
break; break;
default: 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) 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 platform_device *pdev = cqspi->pdev;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct cqspi_flash_pdata *f_pdata; 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; goto err;
} }
ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD); ret = spi_nor_scan(nor, NULL, &hwcaps);
if (ret) if (ret)
goto err; goto err;
@ -1277,7 +1283,7 @@ static const struct dev_pm_ops cqspi__dev_pm_ops = {
#define CQSPI_DEV_PM_OPS NULL #define CQSPI_DEV_PM_OPS NULL
#endif #endif
static struct of_device_id const cqspi_dt_ids[] = { static const struct of_device_id cqspi_dt_ids[] = {
{.compatible = "cdns,qspi-nor",}, {.compatible = "cdns,qspi-nor",},
{ /* end of table */ } { /* 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) 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_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct fsl_qspi *q; struct fsl_qspi *q;
@ -1065,7 +1069,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
/* set the chip address for READID */ /* set the chip address for READID */
fsl_qspi_set_base_addr(q, nor); 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) if (ret)
goto mutex_failed; 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); (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; enum hifmc_iftype if_type;
switch (flash_read) { switch (proto) {
case SPI_NOR_DUAL: case SNOR_PROTO_1_1_2:
if_type = IF_TYPE_DUAL; if_type = IF_TYPE_DUAL;
break; 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; if_type = IF_TYPE_QUAD;
break; break;
case SPI_NOR_NORMAL: case SNOR_PROTO_1_4_4:
case SPI_NOR_FAST: if_type = IF_TYPE_QIO;
break;
case SNOR_PROTO_1_1_1:
default: default:
if_type = IF_TYPE_STD; if_type = IF_TYPE_STD;
break; 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); writel(FMC_DMA_LEN_SET(len), host->regbase + FMC_DMA_LEN);
reg = OP_CFG_FM_CS(priv->chipselect); 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); reg |= OP_CFG_MEM_IF_TYPE(if_type);
if (op_type == FMC_OP_READ) if (op_type == FMC_OP_READ)
reg |= OP_CFG_DUMMY_NUM(nor->read_dummy >> 3); 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, static int hisi_spi_nor_register(struct device_node *np,
struct hifmc_host *host) 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 device *dev = host->dev;
struct spi_nor *nor; struct spi_nor *nor;
struct hifmc_priv *priv; 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->read = hisi_spi_nor_read;
nor->write = hisi_spi_nor_write; nor->write = hisi_spi_nor_write;
nor->erase = NULL; nor->erase = NULL;
ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD); ret = spi_nor_scan(nor, NULL, &hwcaps);
if (ret) if (ret)
return 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 intel_spi *intel_spi_probe(struct device *dev,
struct resource *mem, const struct intel_spi_boardinfo *info) 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 mtd_partition part;
struct intel_spi *ispi; struct intel_spi *ispi;
int ret; int ret;
@ -746,7 +751,7 @@ struct intel_spi *intel_spi_probe(struct device *dev,
ispi->nor.write = intel_spi_write; ispi->nor.write = intel_spi_write;
ispi->nor.erase = intel_spi_erase; 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) { if (ret) {
dev_info(dev, "failed to locate the chip\n"); dev_info(dev, "failed to locate the chip\n");
return ERR_PTR(ret); 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; struct spi_nor *nor = &mt8173_nor->nor;
switch (nor->flash_read) { switch (nor->read_proto) {
case SPI_NOR_FAST: case SNOR_PROTO_1_1_1:
writeb(nor->read_opcode, mt8173_nor->base + writeb(nor->read_opcode, mt8173_nor->base +
MTK_NOR_PRGDATA3_REG); MTK_NOR_PRGDATA3_REG);
writeb(MTK_NOR_FAST_READ, mt8173_nor->base + writeb(MTK_NOR_FAST_READ, mt8173_nor->base +
MTK_NOR_CFG1_REG); MTK_NOR_CFG1_REG);
break; break;
case SPI_NOR_DUAL: case SNOR_PROTO_1_1_2:
writeb(nor->read_opcode, mt8173_nor->base + writeb(nor->read_opcode, mt8173_nor->base +
MTK_NOR_PRGDATA3_REG); MTK_NOR_PRGDATA3_REG);
writeb(MTK_NOR_DUAL_READ_EN, mt8173_nor->base + writeb(MTK_NOR_DUAL_READ_EN, mt8173_nor->base +
MTK_NOR_DUAL_REG); MTK_NOR_DUAL_REG);
break; break;
case SPI_NOR_QUAD: case SNOR_PROTO_1_1_4:
writeb(nor->read_opcode, mt8173_nor->base + writeb(nor->read_opcode, mt8173_nor->base +
MTK_NOR_PRGDATA4_REG); MTK_NOR_PRGDATA4_REG);
writeb(MTK_NOR_QUAD_READ_EN, mt8173_nor->base + 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, static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
struct device_node *flash_node) 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; int ret;
struct spi_nor *nor; 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->write_reg = mt8173_nor_write_reg;
nor->mtd.name = "mtk_nor"; nor->mtd.name = "mtk_nor";
/* initialized with NULL */ /* initialized with NULL */
ret = spi_nor_scan(nor, NULL, SPI_NOR_DUAL); ret = spi_nor_scan(nor, NULL, &hwcaps);
if (ret) if (ret)
return 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) static int nxp_spifi_setup_memory_cmd(struct nxp_spifi *spifi)
{ {
switch (spifi->nor.flash_read) { switch (spifi->nor.read_proto) {
case SPI_NOR_NORMAL: case SNOR_PROTO_1_1_1:
case SPI_NOR_FAST:
spifi->mcmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL; spifi->mcmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL;
break; break;
case SPI_NOR_DUAL: case SNOR_PROTO_1_1_2:
case SPI_NOR_QUAD: case SNOR_PROTO_1_1_4:
spifi->mcmd = SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA; spifi->mcmd = SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA;
break; break;
default: 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, static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
struct device_node *np) 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; u32 ctrl, property;
u16 mode = 0; u16 mode = 0;
int ret; int ret;
@ -308,13 +311,12 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
if (mode & SPI_RX_DUAL) { if (mode & SPI_RX_DUAL) {
ctrl |= SPIFI_CTRL_DUAL; ctrl |= SPIFI_CTRL_DUAL;
flash_read = SPI_NOR_DUAL; hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
} else if (mode & SPI_RX_QUAD) { } else if (mode & SPI_RX_QUAD) {
ctrl &= ~SPIFI_CTRL_DUAL; ctrl &= ~SPIFI_CTRL_DUAL;
flash_read = SPI_NOR_QUAD; hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
} else { } else {
ctrl |= SPIFI_CTRL_DUAL; ctrl |= SPIFI_CTRL_DUAL;
flash_read = SPI_NOR_NORMAL;
} }
switch (mode & (SPI_CPHA | SPI_CPOL)) { 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); 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) { if (ret) {
dev_err(spifi->dev, "device scan failed\n"); dev_err(spifi->dev, "device scan failed\n");
return ret; return ret;

View File

@ -149,24 +149,6 @@ static int read_cr(struct spi_nor *nor)
return val; 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 * Write status register 1 byte
* Returns negative if error occurred. * 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_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_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_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, 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) }, { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 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) }, { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, { "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) }, { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
/* Micron */ /* 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) }, { "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) }, { "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) }, { "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) }, { "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) }, { "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) }, { "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) }, { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) },
{ "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ) }, { "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) }, { "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 */ /* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, { "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) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, 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 */ /* Catalyst / On Semiconductor -- non-JEDEC */
{ "cat25c11", CAT25_INFO( 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "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); write_sr(nor, val | SR_QUAD_EN_MX);
if (spi_nor_wait_till_ready(nor)) ret = spi_nor_wait_till_ready(nor);
return 1; if (ret)
return ret;
ret = read_sr(nor); ret = read_sr(nor);
if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
@ -1460,30 +1452,6 @@ static int spansion_quad_enable(struct spi_nor *nor)
return 0; 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) static int spi_nor_check(struct spi_nor *nor)
{ {
if (!nor->dev || !nor->read || !nor->write || 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; 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; const struct flash_info *info = NULL;
struct device *dev = nor->dev; struct device *dev = nor->dev;
struct mtd_info *mtd = &nor->mtd; 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) if (ret)
return 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) if (name)
info = spi_nor_match_id(name); info = spi_nor_match_id(name);
/* Try to auto-detect if chip name wasn't specified or not found */ /* 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) if (info->flags & SPI_S3AN)
nor->flags |= SNOR_F_READY_XSR_RDY; 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 * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
* with the software protection bits set * 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->type = MTD_NORFLASH;
mtd->writesize = 1; mtd->writesize = 1;
mtd->flags = MTD_CAP_NORFLASH; mtd->flags = MTD_CAP_NORFLASH;
mtd->size = info->sector_size * info->n_sectors; mtd->size = params.size;
mtd->_erase = spi_nor_erase; mtd->_erase = spi_nor_erase;
mtd->_read = spi_nor_read; 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) if (info->flags & NO_CHIP_ERASE)
nor->flags |= SNOR_F_NO_OP_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) if (info->flags & SPI_NOR_NO_ERASE)
mtd->flags |= MTD_NO_ERASE; mtd->flags |= MTD_NO_ERASE;
mtd->dev.parent = dev; mtd->dev.parent = dev;
nor->page_size = info->page_size; nor->page_size = params.page_size;
mtd->writebufsize = nor->page_size; mtd->writebufsize = nor->page_size;
if (np) { if (np) {
/* If we were instantiated by DT, use it */ /* If we were instantiated by DT, use it */
if (of_property_read_bool(np, "m25p,fast-read")) if (of_property_read_bool(np, "m25p,fast-read"))
nor->flash_read = SPI_NOR_FAST; params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
else else
nor->flash_read = SPI_NOR_NORMAL; params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
} else { } else {
/* If we weren't instantiated by DT, default to fast-read */ /* 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 */ /* Some devices cannot do fast-read, no matter what DT tells us */
if (info->flags & SPI_NOR_NO_FR) 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) { * Configure the SPI memory:
ret = set_quad_mode(nor, info); * - select op codes for (Fast) Read, Page Program and Sector Erase.
if (ret) { * - set the number of dummy cycles (mode cycles + wait states).
dev_err(dev, "quad mode not supported\n"); * - set the SPI protocols for register and memory accesses.
return ret; * - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
} */
nor->flash_read = SPI_NOR_QUAD; ret = spi_nor_setup(nor, info, &params, hwcaps);
} else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) { if (ret)
nor->flash_read = SPI_NOR_DUAL; return ret;
}
/* 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;
if (info->addr_width) if (info->addr_width)
nor->addr_width = 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; return -EINVAL;
} }
nor->read_dummy = spi_nor_read_dummy_cycles(nor);
if (info->flags & SPI_S3AN) { if (info->flags & SPI_S3AN) {
ret = s3an_nor_scan(info, nor); ret = s3an_nor_scan(info, nor);
if (ret) if (ret)

View File

@ -19,6 +19,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/sizes.h>
#define QUADSPI_CR 0x00 #define QUADSPI_CR 0x00
#define CR_EN BIT(0) #define CR_EN BIT(0)
@ -192,15 +193,15 @@ static void stm32_qspi_set_framemode(struct spi_nor *nor,
cmd->framemode = CCR_IMODE_1; cmd->framemode = CCR_IMODE_1;
if (read) { if (read) {
switch (nor->flash_read) { switch (nor->read_proto) {
case SPI_NOR_NORMAL: default:
case SPI_NOR_FAST: case SNOR_PROTO_1_1_1:
dmode = CCR_DMODE_1; dmode = CCR_DMODE_1;
break; break;
case SPI_NOR_DUAL: case SNOR_PROTO_1_1_2:
dmode = CCR_DMODE_2; dmode = CCR_DMODE_2;
break; break;
case SPI_NOR_QUAD: case SNOR_PROTO_1_1_4:
dmode = CCR_DMODE_4; dmode = CCR_DMODE_4;
break; 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; struct stm32_qspi_cmd cmd;
int err; 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); nor->read_opcode, buf, (u32)from, len);
memset(&cmd, 0, sizeof(cmd)); 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; struct stm32_qspi_cmd cmd;
int err; 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); nor->program_opcode, buf, (u32)to, len);
memset(&cmd, 0, sizeof(cmd)); 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, static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
struct device_node *np) 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 stm32_qspi_flash *flash;
struct mtd_info *mtd; struct mtd_info *mtd;
int ret; int ret;
@ -499,12 +505,10 @@ static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
width = 1; width = 1;
if (width == 4) if (width == 4)
flash_read = SPI_NOR_QUAD; hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
else if (width == 2) else if (width == 2)
flash_read = SPI_NOR_DUAL; hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
else if (width == 1) else if (width != 1)
flash_read = SPI_NOR_NORMAL;
else
return -EINVAL; return -EINVAL;
flash = &qspi->flash[cs_num]; 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); 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) { if (ret) {
dev_err(qspi->dev, "device scan failed\n"); dev_err(qspi->dev, "device scan failed\n");
return ret; return ret;

View File

@ -73,6 +73,15 @@
#define SPINOR_OP_BE_32K_4B 0x5c /* Erase 32KiB block */ #define SPINOR_OP_BE_32K_4B 0x5c /* Erase 32KiB block */
#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */ #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. */ /* Used for SST flashes only. */
#define SPINOR_OP_BP 0x02 /* Byte program */ #define SPINOR_OP_BP 0x02 /* Byte program */
#define SPINOR_OP_WRDI 0x04 /* Write disable */ #define SPINOR_OP_WRDI 0x04 /* Write disable */
@ -119,13 +128,81 @@
/* Configuration Register bits. */ /* Configuration Register bits. */
#define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */ #define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */
enum read_mode { /* Supported SPI protocols */
SPI_NOR_NORMAL = 0, #define SNOR_PROTO_INST_MASK GENMASK(23, 16)
SPI_NOR_FAST, #define SNOR_PROTO_INST_SHIFT 16
SPI_NOR_DUAL, #define SNOR_PROTO_INST(_nbits) \
SPI_NOR_QUAD, ((((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 #define SPI_NOR_MAX_CMD_SIZE 8
enum spi_nor_ops { enum spi_nor_ops {
SPI_NOR_OPS_READ = 0, SPI_NOR_OPS_READ = 0,
@ -154,9 +231,11 @@ enum spi_nor_option_flags {
* @read_opcode: the read opcode * @read_opcode: the read opcode
* @read_dummy: the dummy needed by the read operation * @read_dummy: the dummy needed by the read operation
* @program_opcode: the program opcode * @program_opcode: the program opcode
* @flash_read: the mode of the read
* @sst_write_second: used by the SST write operation * @sst_write_second: used by the SST write operation
* @flags: flag options for the current SPI-NOR (SNOR_F_*) * @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 * @cmd_buf: used by the write_reg
* @prepare: [OPTIONAL] do some preparations for the * @prepare: [OPTIONAL] do some preparations for the
* read/write/erase/lock/unlock operations * read/write/erase/lock/unlock operations
@ -185,7 +264,9 @@ struct spi_nor {
u8 read_opcode; u8 read_opcode;
u8 read_dummy; u8 read_dummy;
u8 program_opcode; 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; bool sst_write_second;
u32 flags; u32 flags;
u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; 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); 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 * spi_nor_scan() - scan the SPI NOR
* @nor: the spi_nor structure * @nor: the spi_nor structure
* @name: the chip type name * @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. * The drivers can use this fuction to scan the SPI NOR.
* In the scanning, it will try to get all the necessary information to * 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. * 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 #endif