MTD core changes:
- add debugfs nodes for querying the flash name and id SPI NOR core changes: - always use bounce buffer for register read/writes - move m25p80 code in spi-nor.c - rework hwcaps selection for the spi-mem case - rework the core in order to move the manufacturer specific code out of it: - regroup flash parameters in 'struct spi_nor_flash_parameter' - add default_init() and post_sfdp() hooks to tweak the flash parameters - introduce the ->set_4byte(), ->convert_addr() and ->setup() methods, to deal with manufacturer specific code - rework the SPI NOR lock/unlock logic - fix an error code in spi_nor_read_raw() - fix a memory leak bug - enable the debugfs for the partname and partid - add support for few flashes SPI NOR controller drivers changes: - intel-spi: - Whitelist 4B read commands - Add support for Intel Tiger Lake SPI serial flash - aspeed-smc: Add of_node_put() - hisi-sfc: Add of_node_put() - cadence-quadspi: Fix QSPI RCU Schedule Stall -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEHUIqys8OyG1eHf7fS1VPR6WNFOkFAl1o4SQACgkQS1VPR6WN FOnV6ggAgSmUiJi58dzS2n5thNeYeUUW59gjJJptHH152IuP3pBFaEEzDzHA3xB8 YDT/2RmWQmO0YcE0qY3HYFB6cXrDdO1xyfE0bxXrqDqBj7E4eX3Xw/tm+tMvqrHo M2KeI8/BwI7VPVrYwr1uCY1l5eoFmqF4X034DkH8eyQ1xdOM79aewQNmOx0WxHfJ mCFhTm2lrYXDMcedRND/rcRZG2taSGrXMANxoA7KFSkMVJP3SuQ+fsqHpngTyu11 URVo7Xb7VIq0naYzGmpXLVWtHqWrKFfx6cvshAE6eVK/3wPn7aIC2ozapV5yHq06 w05pwsZB4+xNeN0asRV4SnJsRxOUXA== =90pz -----END PGP SIGNATURE----- Merge tag 'spi-nor/for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux into mtd/for-5.4 MTD core changes: - add debugfs nodes for querying the flash name and id SPI NOR core changes: - always use bounce buffer for register read/writes - move m25p80 code in spi-nor.c - rework hwcaps selection for the spi-mem case - rework the core in order to move the manufacturer specific code out of it: - regroup flash parameters in 'struct spi_nor_flash_parameter' - add default_init() and post_sfdp() hooks to tweak the flash parameters - introduce the ->set_4byte(), ->convert_addr() and ->setup() methods, to deal with manufacturer specific code - rework the SPI NOR lock/unlock logic - fix an error code in spi_nor_read_raw() - fix a memory leak bug - enable the debugfs for the partname and partid - add support for few flashes SPI NOR controller drivers changes: - intel-spi: - Whitelist 4B read commands - Add support for Intel Tiger Lake SPI serial flash - aspeed-smc: Add of_node_put() - hisi-sfc: Add of_node_put() - cadence-quadspi: Fix QSPI RCU Schedule Stall
This commit is contained in:
commit
560852a1d3
|
@ -79,24 +79,6 @@ config MTD_DATAFLASH_OTP
|
|||
other key product data. The second half is programmed with a
|
||||
unique-to-each-chip bit pattern at the factory.
|
||||
|
||||
config MTD_M25P80
|
||||
tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
|
||||
depends on SPI_MASTER && MTD_SPI_NOR
|
||||
select SPI_MEM
|
||||
help
|
||||
This enables access to most modern SPI flash chips, used for
|
||||
program and data storage. Series supported include Atmel AT26DF,
|
||||
Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X. Other chips
|
||||
are supported as well. See the driver source for the current list,
|
||||
or to add other chips.
|
||||
|
||||
Note that the original DataFlash chips (AT45 series, not AT26DF),
|
||||
need an entirely different driver.
|
||||
|
||||
Set up your spi devices with the right board-specific platform data,
|
||||
if you want to specify device partitioning or to use a device which
|
||||
doesn't support the JEDEC ID instruction.
|
||||
|
||||
config MTD_MCHP23K256
|
||||
tristate "Microchip 23K256 SRAM"
|
||||
depends on SPI_MASTER
|
||||
|
|
|
@ -12,7 +12,6 @@ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
|
|||
obj-$(CONFIG_MTD_LART) += lart.o
|
||||
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
|
||||
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
|
||||
obj-$(CONFIG_MTD_M25P80) += m25p80.o
|
||||
obj-$(CONFIG_MTD_MCHP23K256) += mchp23k256.o
|
||||
obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
|
||||
obj-$(CONFIG_MTD_SST25L) += sst25l.o
|
||||
|
|
|
@ -1,347 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
|
||||
*
|
||||
* Author: Mike Lavender, mike@steroidmicros.com
|
||||
*
|
||||
* Copyright (c) 2005, Intec Automation Inc.
|
||||
*
|
||||
* Some parts are based on lart.c by Abraham Van Der Merwe
|
||||
*
|
||||
* Cleaned up and generalized based on mtd_dataflash.c
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/mtd/spi-nor.h>
|
||||
|
||||
struct m25p {
|
||||
struct spi_mem *spimem;
|
||||
struct spi_nor spi_nor;
|
||||
};
|
||||
|
||||
static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
|
||||
{
|
||||
struct m25p *flash = nor->priv;
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_IN(len, NULL, 1));
|
||||
void *scratchbuf;
|
||||
int ret;
|
||||
|
||||
scratchbuf = kmalloc(len, GFP_KERNEL);
|
||||
if (!scratchbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
op.data.buf.in = scratchbuf;
|
||||
ret = spi_mem_exec_op(flash->spimem, &op);
|
||||
if (ret < 0)
|
||||
dev_err(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
|
||||
code);
|
||||
else
|
||||
memcpy(val, scratchbuf, len);
|
||||
|
||||
kfree(scratchbuf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
||||
{
|
||||
struct m25p *flash = nor->priv;
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_OUT(len, NULL, 1));
|
||||
void *scratchbuf;
|
||||
int ret;
|
||||
|
||||
scratchbuf = kmemdup(buf, len, GFP_KERNEL);
|
||||
if (!scratchbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
op.data.buf.out = scratchbuf;
|
||||
ret = spi_mem_exec_op(flash->spimem, &op);
|
||||
kfree(scratchbuf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
|
||||
const u_char *buf)
|
||||
{
|
||||
struct m25p *flash = nor->priv;
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
|
||||
SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 1));
|
||||
int ret;
|
||||
|
||||
/* get transfer protocols. */
|
||||
op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
|
||||
op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
|
||||
op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
|
||||
|
||||
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
|
||||
op.addr.nbytes = 0;
|
||||
|
||||
ret = spi_mem_adjust_op_size(flash->spimem, &op);
|
||||
if (ret)
|
||||
return ret;
|
||||
op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
|
||||
|
||||
ret = spi_mem_exec_op(flash->spimem, &op);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return op.data.nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read an address range from the nor chip. The address range
|
||||
* may be any size provided it is within the physical boundaries.
|
||||
*/
|
||||
static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
|
||||
u_char *buf)
|
||||
{
|
||||
struct m25p *flash = nor->priv;
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
|
||||
SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
|
||||
SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1));
|
||||
size_t remaining = len;
|
||||
int ret;
|
||||
|
||||
/* get transfer protocols. */
|
||||
op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
|
||||
op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
|
||||
op.dummy.buswidth = op.addr.buswidth;
|
||||
op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
|
||||
|
||||
/* convert the dummy cycles to the number of bytes */
|
||||
op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
|
||||
|
||||
while (remaining) {
|
||||
op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
|
||||
ret = spi_mem_adjust_op_size(flash->spimem, &op);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spi_mem_exec_op(flash->spimem, &op);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
op.addr.val += op.data.nbytes;
|
||||
remaining -= op.data.nbytes;
|
||||
op.data.buf.in += op.data.nbytes;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* board specific setup should have ensured the SPI clock used here
|
||||
* matches what the READ command supports, at least until this driver
|
||||
* understands FAST_READ (for clocks over 25 MHz).
|
||||
*/
|
||||
static int m25p_probe(struct spi_mem *spimem)
|
||||
{
|
||||
struct spi_device *spi = spimem->spi;
|
||||
struct flash_platform_data *data;
|
||||
struct m25p *flash;
|
||||
struct spi_nor *nor;
|
||||
struct spi_nor_hwcaps hwcaps = {
|
||||
.mask = SNOR_HWCAPS_READ |
|
||||
SNOR_HWCAPS_READ_FAST |
|
||||
SNOR_HWCAPS_PP,
|
||||
};
|
||||
char *flash_name;
|
||||
int ret;
|
||||
|
||||
data = dev_get_platdata(&spimem->spi->dev);
|
||||
|
||||
flash = devm_kzalloc(&spimem->spi->dev, sizeof(*flash), GFP_KERNEL);
|
||||
if (!flash)
|
||||
return -ENOMEM;
|
||||
|
||||
nor = &flash->spi_nor;
|
||||
|
||||
/* install the hooks */
|
||||
nor->read = m25p80_read;
|
||||
nor->write = m25p80_write;
|
||||
nor->write_reg = m25p80_write_reg;
|
||||
nor->read_reg = m25p80_read_reg;
|
||||
|
||||
nor->dev = &spimem->spi->dev;
|
||||
spi_nor_set_flash_node(nor, spi->dev.of_node);
|
||||
nor->priv = flash;
|
||||
|
||||
spi_mem_set_drvdata(spimem, flash);
|
||||
flash->spimem = spimem;
|
||||
|
||||
if (spi->mode & SPI_RX_OCTAL) {
|
||||
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
|
||||
|
||||
if (spi->mode & SPI_TX_OCTAL)
|
||||
hwcaps.mask |= (SNOR_HWCAPS_READ_1_8_8 |
|
||||
SNOR_HWCAPS_PP_1_1_8 |
|
||||
SNOR_HWCAPS_PP_1_8_8);
|
||||
} else 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;
|
||||
|
||||
if (!nor->mtd.name)
|
||||
nor->mtd.name = spi_mem_get_name(spimem);
|
||||
|
||||
/* For some (historical?) reason many platforms provide two different
|
||||
* names in flash_platform_data: "name" and "type". Quite often name is
|
||||
* set to "m25p80" and then "type" provides a real chip name.
|
||||
* If that's the case, respect "type" and ignore a "name".
|
||||
*/
|
||||
if (data && data->type)
|
||||
flash_name = data->type;
|
||||
else if (!strcmp(spi->modalias, "spi-nor"))
|
||||
flash_name = NULL; /* auto-detect */
|
||||
else
|
||||
flash_name = spi->modalias;
|
||||
|
||||
ret = spi_nor_scan(nor, flash_name, &hwcaps);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
|
||||
data ? data->nr_parts : 0);
|
||||
}
|
||||
|
||||
|
||||
static int m25p_remove(struct spi_mem *spimem)
|
||||
{
|
||||
struct m25p *flash = spi_mem_get_drvdata(spimem);
|
||||
|
||||
spi_nor_restore(&flash->spi_nor);
|
||||
|
||||
/* Clean up MTD stuff. */
|
||||
return mtd_device_unregister(&flash->spi_nor.mtd);
|
||||
}
|
||||
|
||||
static void m25p_shutdown(struct spi_mem *spimem)
|
||||
{
|
||||
struct m25p *flash = spi_mem_get_drvdata(spimem);
|
||||
|
||||
spi_nor_restore(&flash->spi_nor);
|
||||
}
|
||||
/*
|
||||
* Do NOT add to this array without reading the following:
|
||||
*
|
||||
* Historically, many flash devices are bound to this driver by their name. But
|
||||
* since most of these flash are compatible to some extent, and their
|
||||
* differences can often be differentiated by the JEDEC read-ID command, we
|
||||
* encourage new users to add support to the spi-nor library, and simply bind
|
||||
* against a generic string here (e.g., "jedec,spi-nor").
|
||||
*
|
||||
* Many flash names are kept here in this list (as well as in spi-nor.c) to
|
||||
* keep them available as module aliases for existing platforms.
|
||||
*/
|
||||
static const struct spi_device_id m25p_ids[] = {
|
||||
/*
|
||||
* Allow non-DT platform devices to bind to the "spi-nor" modalias, and
|
||||
* hack around the fact that the SPI core does not provide uevent
|
||||
* matching for .of_match_table
|
||||
*/
|
||||
{"spi-nor"},
|
||||
|
||||
/*
|
||||
* Entries not used in DTs that should be safe to drop after replacing
|
||||
* them with "spi-nor" in platform data.
|
||||
*/
|
||||
{"s25sl064a"}, {"w25x16"}, {"m25p10"}, {"m25px64"},
|
||||
|
||||
/*
|
||||
* Entries that were used in DTs without "jedec,spi-nor" fallback and
|
||||
* should be kept for backward compatibility.
|
||||
*/
|
||||
{"at25df321a"}, {"at25df641"}, {"at26df081a"},
|
||||
{"mx25l4005a"}, {"mx25l1606e"}, {"mx25l6405d"}, {"mx25l12805d"},
|
||||
{"mx25l25635e"},{"mx66l51235l"},
|
||||
{"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q512a"},
|
||||
{"s25fl256s1"}, {"s25fl512s"}, {"s25sl12801"}, {"s25fl008k"},
|
||||
{"s25fl064k"},
|
||||
{"sst25vf040b"},{"sst25vf016b"},{"sst25vf032b"},{"sst25wf040"},
|
||||
{"m25p40"}, {"m25p80"}, {"m25p16"}, {"m25p32"},
|
||||
{"m25p64"}, {"m25p128"},
|
||||
{"w25x80"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"},
|
||||
{"w25q80bl"}, {"w25q128"}, {"w25q256"},
|
||||
|
||||
/* Flashes that can't be detected using JEDEC */
|
||||
{"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"},
|
||||
{"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"},
|
||||
{"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"},
|
||||
|
||||
/* Everspin MRAMs (non-JEDEC) */
|
||||
{ "mr25h128" }, /* 128 Kib, 40 MHz */
|
||||
{ "mr25h256" }, /* 256 Kib, 40 MHz */
|
||||
{ "mr25h10" }, /* 1 Mib, 40 MHz */
|
||||
{ "mr25h40" }, /* 4 Mib, 40 MHz */
|
||||
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, m25p_ids);
|
||||
|
||||
static const struct of_device_id m25p_of_table[] = {
|
||||
/*
|
||||
* Generic compatibility for SPI NOR that can be identified by the
|
||||
* JEDEC READ ID opcode (0x9F). Use this, if possible.
|
||||
*/
|
||||
{ .compatible = "jedec,spi-nor" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, m25p_of_table);
|
||||
|
||||
static struct spi_mem_driver m25p80_driver = {
|
||||
.spidrv = {
|
||||
.driver = {
|
||||
.name = "m25p80",
|
||||
.of_match_table = m25p_of_table,
|
||||
},
|
||||
.id_table = m25p_ids,
|
||||
},
|
||||
.probe = m25p_probe,
|
||||
.remove = m25p_remove,
|
||||
.shutdown = m25p_shutdown,
|
||||
|
||||
/* REVISIT: many of these chips have deep power-down modes, which
|
||||
* should clearly be entered on suspend() to minimize power use.
|
||||
* And also when they're otherwise idle...
|
||||
*/
|
||||
};
|
||||
|
||||
module_spi_mem_driver(m25p80_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Mike Lavender");
|
||||
MODULE_DESCRIPTION("MTD SPI driver for ST M25Pxx flash chips");
|
|
@ -335,6 +335,82 @@ static const struct device_type mtd_devtype = {
|
|||
.release = mtd_release,
|
||||
};
|
||||
|
||||
static int mtd_partid_show(struct seq_file *s, void *p)
|
||||
{
|
||||
struct mtd_info *mtd = s->private;
|
||||
|
||||
seq_printf(s, "%s\n", mtd->dbg.partid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtd_partid_debugfs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, mtd_partid_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations mtd_partid_debug_fops = {
|
||||
.open = mtd_partid_debugfs_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int mtd_partname_show(struct seq_file *s, void *p)
|
||||
{
|
||||
struct mtd_info *mtd = s->private;
|
||||
|
||||
seq_printf(s, "%s\n", mtd->dbg.partname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtd_partname_debugfs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, mtd_partname_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations mtd_partname_debug_fops = {
|
||||
.open = mtd_partname_debugfs_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static struct dentry *dfs_dir_mtd;
|
||||
|
||||
static void mtd_debugfs_populate(struct mtd_info *mtd)
|
||||
{
|
||||
struct device *dev = &mtd->dev;
|
||||
struct dentry *root, *dent;
|
||||
|
||||
if (IS_ERR_OR_NULL(dfs_dir_mtd))
|
||||
return;
|
||||
|
||||
root = debugfs_create_dir(dev_name(dev), dfs_dir_mtd);
|
||||
if (IS_ERR_OR_NULL(root)) {
|
||||
dev_dbg(dev, "won't show data in debugfs\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mtd->dbg.dfs_dir = root;
|
||||
|
||||
if (mtd->dbg.partid) {
|
||||
dent = debugfs_create_file("partid", 0400, root, mtd,
|
||||
&mtd_partid_debug_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
dev_err(dev, "can't create debugfs entry for partid\n");
|
||||
}
|
||||
|
||||
if (mtd->dbg.partname) {
|
||||
dent = debugfs_create_file("partname", 0400, root, mtd,
|
||||
&mtd_partname_debug_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
dev_err(dev,
|
||||
"can't create debugfs entry for partname\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_MMU
|
||||
unsigned mtd_mmap_capabilities(struct mtd_info *mtd)
|
||||
{
|
||||
|
@ -512,8 +588,6 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct dentry *dfs_dir_mtd;
|
||||
|
||||
/**
|
||||
* add_mtd_device - register an MTD device
|
||||
* @mtd: pointer to new MTD device info structure
|
||||
|
@ -607,13 +681,7 @@ int add_mtd_device(struct mtd_info *mtd)
|
|||
if (error)
|
||||
goto fail_nvmem_add;
|
||||
|
||||
if (!IS_ERR_OR_NULL(dfs_dir_mtd)) {
|
||||
mtd->dbg.dfs_dir = debugfs_create_dir(dev_name(&mtd->dev), dfs_dir_mtd);
|
||||
if (IS_ERR_OR_NULL(mtd->dbg.dfs_dir)) {
|
||||
pr_debug("mtd device %s won't show data in debugfs\n",
|
||||
dev_name(&mtd->dev));
|
||||
}
|
||||
}
|
||||
mtd_debugfs_populate(mtd);
|
||||
|
||||
device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL,
|
||||
"mtd%dro", i);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
menuconfig MTD_SPI_NOR
|
||||
tristate "SPI-NOR device support"
|
||||
depends on MTD
|
||||
depends on MTD && SPI_MASTER
|
||||
select SPI_MEM
|
||||
help
|
||||
This is the framework for the SPI NOR which can be used by the SPI
|
||||
device drivers and the SPI-NOR device driver.
|
||||
|
|
|
@ -836,8 +836,10 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
|
|||
controller->chips[cs] = chip;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
if (ret) {
|
||||
of_node_put(child);
|
||||
aspeed_smc_unregister(controller);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -241,23 +242,13 @@ struct cqspi_driver_platdata {
|
|||
|
||||
#define CQSPI_IRQ_STATUS_MASK 0x1FFFF
|
||||
|
||||
static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clear)
|
||||
static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr)
|
||||
{
|
||||
unsigned long end = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS);
|
||||
u32 val;
|
||||
|
||||
while (1) {
|
||||
val = readl(reg);
|
||||
if (clear)
|
||||
val = ~val;
|
||||
val &= mask;
|
||||
|
||||
if (val == mask)
|
||||
return 0;
|
||||
|
||||
if (time_after(jiffies, end))
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
return readl_relaxed_poll_timeout(reg, val,
|
||||
(((clr ? ~val : val) & mask) == mask),
|
||||
10, CQSPI_TIMEOUT_MS * 1000);
|
||||
}
|
||||
|
||||
static bool cqspi_is_idle(struct cqspi_st *cqspi)
|
||||
|
|
|
@ -401,6 +401,7 @@ static int hisi_spi_nor_register_all(struct hifmc_host *host)
|
|||
|
||||
if (host->num_chip == HIFMC_MAX_CHIP_NUM) {
|
||||
dev_warn(dev, "Flash device number exceeds the maximum chipselect number\n");
|
||||
of_node_put(np);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
|
|||
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
|
||||
{ },
|
||||
|
|
|
@ -621,6 +621,8 @@ static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len,
|
|||
switch (nor->read_opcode) {
|
||||
case SPINOR_OP_READ:
|
||||
case SPINOR_OP_READ_FAST:
|
||||
case SPINOR_OP_READ_4B:
|
||||
case SPINOR_OP_READ_FAST_4B:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -189,6 +189,9 @@ struct module; /* only needed for owner field in mtd_info */
|
|||
*/
|
||||
struct mtd_debug_info {
|
||||
struct dentry *dfs_dir;
|
||||
|
||||
const char *partname;
|
||||
const char *partid;
|
||||
};
|
||||
|
||||
struct mtd_info {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/mtd/cfi.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
|
||||
/*
|
||||
* Manufacturer IDs
|
||||
|
@ -224,7 +225,6 @@ 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,
|
||||
SPI_NOR_OPS_WRITE,
|
||||
|
@ -237,12 +237,12 @@ enum spi_nor_option_flags {
|
|||
SNOR_F_USE_FSR = BIT(0),
|
||||
SNOR_F_HAS_SR_TB = BIT(1),
|
||||
SNOR_F_NO_OP_CHIP_ERASE = BIT(2),
|
||||
SNOR_F_S3AN_ADDR_DEFAULT = BIT(3),
|
||||
SNOR_F_READY_XSR_RDY = BIT(4),
|
||||
SNOR_F_USE_CLSR = BIT(5),
|
||||
SNOR_F_BROKEN_RESET = BIT(6),
|
||||
SNOR_F_4B_OPCODES = BIT(7),
|
||||
SNOR_F_HAS_4BAIT = BIT(8),
|
||||
SNOR_F_READY_XSR_RDY = BIT(3),
|
||||
SNOR_F_USE_CLSR = BIT(4),
|
||||
SNOR_F_BROKEN_RESET = BIT(5),
|
||||
SNOR_F_4B_OPCODES = BIT(6),
|
||||
SNOR_F_HAS_4BAIT = BIT(7),
|
||||
SNOR_F_HAS_LOCK = BIT(8),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -333,130 +333,6 @@ struct spi_nor_erase_map {
|
|||
u8 uniform_erase_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct flash_info - Forward declaration of a structure used internally by
|
||||
* spi_nor_scan()
|
||||
*/
|
||||
struct flash_info;
|
||||
|
||||
/**
|
||||
* struct spi_nor - Structure for defining a the SPI NOR layer
|
||||
* @mtd: point to a mtd_info structure
|
||||
* @lock: the lock for the read/write/erase/lock/unlock operations
|
||||
* @dev: point to a spi device, or a spi nor controller device.
|
||||
* @info: spi-nor part JDEC MFR id and other info
|
||||
* @page_size: the page size of the SPI NOR
|
||||
* @addr_width: number of address bytes
|
||||
* @erase_opcode: the opcode for erasing a sector
|
||||
* @read_opcode: the read opcode
|
||||
* @read_dummy: the dummy needed by the read operation
|
||||
* @program_opcode: the program opcode
|
||||
* @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
|
||||
* @erase_map: the erase map of the SPI NOR
|
||||
* @prepare: [OPTIONAL] do some preparations for the
|
||||
* read/write/erase/lock/unlock operations
|
||||
* @unprepare: [OPTIONAL] do some post work after the
|
||||
* read/write/erase/lock/unlock operations
|
||||
* @read_reg: [DRIVER-SPECIFIC] read out the register
|
||||
* @write_reg: [DRIVER-SPECIFIC] write data to the register
|
||||
* @read: [DRIVER-SPECIFIC] read data from the SPI NOR
|
||||
* @write: [DRIVER-SPECIFIC] write data to the SPI NOR
|
||||
* @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
|
||||
* at the offset @offs; if not provided by the driver,
|
||||
* spi-nor will send the erase opcode via write_reg()
|
||||
* @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
|
||||
* @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
|
||||
* @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
|
||||
* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode
|
||||
* @clear_sr_bp: [FLASH-SPECIFIC] clears the Block Protection Bits from
|
||||
* the SPI NOR Status Register.
|
||||
* completely locked
|
||||
* @priv: the private data
|
||||
*/
|
||||
struct spi_nor {
|
||||
struct mtd_info mtd;
|
||||
struct mutex lock;
|
||||
struct device *dev;
|
||||
const struct flash_info *info;
|
||||
u32 page_size;
|
||||
u8 addr_width;
|
||||
u8 erase_opcode;
|
||||
u8 read_opcode;
|
||||
u8 read_dummy;
|
||||
u8 program_opcode;
|
||||
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];
|
||||
struct spi_nor_erase_map erase_map;
|
||||
|
||||
int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
|
||||
int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
|
||||
|
||||
ssize_t (*read)(struct spi_nor *nor, loff_t from,
|
||||
size_t len, u_char *read_buf);
|
||||
ssize_t (*write)(struct spi_nor *nor, loff_t to,
|
||||
size_t len, const u_char *write_buf);
|
||||
int (*erase)(struct spi_nor *nor, loff_t offs);
|
||||
|
||||
int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
|
||||
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
|
||||
int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
|
||||
int (*quad_enable)(struct spi_nor *nor);
|
||||
int (*clear_sr_bp)(struct spi_nor *nor);
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
static u64 __maybe_unused
|
||||
spi_nor_region_is_last(const struct spi_nor_erase_region *region)
|
||||
{
|
||||
return region->offset & SNOR_LAST_REGION;
|
||||
}
|
||||
|
||||
static u64 __maybe_unused
|
||||
spi_nor_region_end(const struct spi_nor_erase_region *region)
|
||||
{
|
||||
return (region->offset & ~SNOR_ERASE_FLAGS_MASK) + region->size;
|
||||
}
|
||||
|
||||
static void __maybe_unused
|
||||
spi_nor_region_mark_end(struct spi_nor_erase_region *region)
|
||||
{
|
||||
region->offset |= SNOR_LAST_REGION;
|
||||
}
|
||||
|
||||
static void __maybe_unused
|
||||
spi_nor_region_mark_overlay(struct spi_nor_erase_region *region)
|
||||
{
|
||||
region->offset |= SNOR_OVERLAID_REGION;
|
||||
}
|
||||
|
||||
static bool __maybe_unused spi_nor_has_uniform_erase(const struct spi_nor *nor)
|
||||
{
|
||||
return !!nor->erase_map.uniform_erase_type;
|
||||
}
|
||||
|
||||
static inline void spi_nor_set_flash_node(struct spi_nor *nor,
|
||||
struct device_node *np)
|
||||
{
|
||||
mtd_set_of_node(&nor->mtd, np);
|
||||
}
|
||||
|
||||
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).
|
||||
|
@ -518,6 +394,257 @@ struct spi_nor_hwcaps {
|
|||
#define SNOR_HWCAPS_PP_1_8_8 BIT(21)
|
||||
#define SNOR_HWCAPS_PP_8_8_8 BIT(22)
|
||||
|
||||
#define SNOR_HWCAPS_X_X_X (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)
|
||||
|
||||
#define SNOR_HWCAPS_DTR (SNOR_HWCAPS_READ_1_1_1_DTR | \
|
||||
SNOR_HWCAPS_READ_1_2_2_DTR | \
|
||||
SNOR_HWCAPS_READ_1_4_4_DTR | \
|
||||
SNOR_HWCAPS_READ_1_8_8_DTR)
|
||||
|
||||
#define SNOR_HWCAPS_ALL (SNOR_HWCAPS_READ_MASK | \
|
||||
SNOR_HWCAPS_PP_MASK)
|
||||
|
||||
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,
|
||||
|
||||
/* Octal 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,
|
||||
|
||||
/* Octal SPI */
|
||||
SNOR_CMD_PP_1_1_8,
|
||||
SNOR_CMD_PP_1_8_8,
|
||||
SNOR_CMD_PP_8_8_8,
|
||||
|
||||
SNOR_CMD_PP_MAX
|
||||
};
|
||||
|
||||
/* Forward declaration that will be used in 'struct spi_nor_flash_parameter' */
|
||||
struct spi_nor;
|
||||
|
||||
/**
|
||||
* struct spi_nor_locking_ops - SPI NOR locking methods
|
||||
* @lock: lock a region of the SPI NOR.
|
||||
* @unlock: unlock a region of the SPI NOR.
|
||||
* @is_locked: check if a region of the SPI NOR is completely locked
|
||||
*/
|
||||
struct spi_nor_locking_ops {
|
||||
int (*lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
|
||||
int (*unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
|
||||
int (*is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spi_nor_flash_parameter - SPI NOR flash parameters and settings.
|
||||
* Includes legacy flash parameters and settings that can be overwritten
|
||||
* by the spi_nor_fixups hooks, or dynamically when parsing the JESD216
|
||||
* Serial Flash Discoverable Parameters (SFDP) tables.
|
||||
*
|
||||
* @size: the flash memory density in bytes.
|
||||
* @page_size: the page size of the SPI NOR flash memory.
|
||||
* @hwcaps: describes the read and page program hardware
|
||||
* capabilities.
|
||||
* @reads: read capabilities ordered by priority: the higher index
|
||||
* in the array, the higher priority.
|
||||
* @page_programs: page program capabilities ordered by priority: the
|
||||
* higher index in the array, the higher priority.
|
||||
* @erase_map: the erase map parsed from the SFDP Sector Map Parameter
|
||||
* Table.
|
||||
* @quad_enable: enables SPI NOR quad mode.
|
||||
* @set_4byte: puts the SPI NOR in 4 byte addressing mode.
|
||||
* @convert_addr: converts an absolute address into something the flash
|
||||
* will understand. Particularly useful when pagesize is
|
||||
* not a power-of-2.
|
||||
* @setup: configures the SPI NOR memory. Useful for SPI NOR
|
||||
* flashes that have peculiarities to the SPI NOR standard
|
||||
* e.g. different opcodes, specific address calculation,
|
||||
* page size, etc.
|
||||
* @locking_ops: SPI NOR locking methods.
|
||||
*/
|
||||
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];
|
||||
|
||||
struct spi_nor_erase_map erase_map;
|
||||
|
||||
int (*quad_enable)(struct spi_nor *nor);
|
||||
int (*set_4byte)(struct spi_nor *nor, bool enable);
|
||||
u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
|
||||
int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps);
|
||||
|
||||
const struct spi_nor_locking_ops *locking_ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct flash_info - Forward declaration of a structure used internally by
|
||||
* spi_nor_scan()
|
||||
*/
|
||||
struct flash_info;
|
||||
|
||||
/**
|
||||
* struct spi_nor - Structure for defining a the SPI NOR layer
|
||||
* @mtd: point to a mtd_info structure
|
||||
* @lock: the lock for the read/write/erase/lock/unlock operations
|
||||
* @dev: point to a spi device, or a spi nor controller device.
|
||||
* @spimem: point to the spi mem device
|
||||
* @bouncebuf: bounce buffer used when the buffer passed by the MTD
|
||||
* layer is not DMA-able
|
||||
* @bouncebuf_size: size of the bounce buffer
|
||||
* @info: spi-nor part JDEC MFR id and other info
|
||||
* @page_size: the page size of the SPI NOR
|
||||
* @addr_width: number of address bytes
|
||||
* @erase_opcode: the opcode for erasing a sector
|
||||
* @read_opcode: the read opcode
|
||||
* @read_dummy: the dummy needed by the read operation
|
||||
* @program_opcode: the program opcode
|
||||
* @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
|
||||
* @prepare: [OPTIONAL] do some preparations for the
|
||||
* read/write/erase/lock/unlock operations
|
||||
* @unprepare: [OPTIONAL] do some post work after the
|
||||
* read/write/erase/lock/unlock operations
|
||||
* @read_reg: [DRIVER-SPECIFIC] read out the register
|
||||
* @write_reg: [DRIVER-SPECIFIC] write data to the register
|
||||
* @read: [DRIVER-SPECIFIC] read data from the SPI NOR
|
||||
* @write: [DRIVER-SPECIFIC] write data to the SPI NOR
|
||||
* @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
|
||||
* at the offset @offs; if not provided by the driver,
|
||||
* spi-nor will send the erase opcode via write_reg()
|
||||
* @clear_sr_bp: [FLASH-SPECIFIC] clears the Block Protection Bits from
|
||||
* the SPI NOR Status Register.
|
||||
* @params: [FLASH-SPECIFIC] SPI-NOR flash parameters and settings.
|
||||
* The structure includes legacy flash parameters and
|
||||
* settings that can be overwritten by the spi_nor_fixups
|
||||
* hooks, or dynamically when parsing the SFDP tables.
|
||||
* @priv: the private data
|
||||
*/
|
||||
struct spi_nor {
|
||||
struct mtd_info mtd;
|
||||
struct mutex lock;
|
||||
struct device *dev;
|
||||
struct spi_mem *spimem;
|
||||
u8 *bouncebuf;
|
||||
size_t bouncebuf_size;
|
||||
const struct flash_info *info;
|
||||
u32 page_size;
|
||||
u8 addr_width;
|
||||
u8 erase_opcode;
|
||||
u8 read_opcode;
|
||||
u8 read_dummy;
|
||||
u8 program_opcode;
|
||||
enum spi_nor_protocol read_proto;
|
||||
enum spi_nor_protocol write_proto;
|
||||
enum spi_nor_protocol reg_proto;
|
||||
bool sst_write_second;
|
||||
u32 flags;
|
||||
|
||||
int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
|
||||
int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
|
||||
|
||||
ssize_t (*read)(struct spi_nor *nor, loff_t from,
|
||||
size_t len, u_char *read_buf);
|
||||
ssize_t (*write)(struct spi_nor *nor, loff_t to,
|
||||
size_t len, const u_char *write_buf);
|
||||
int (*erase)(struct spi_nor *nor, loff_t offs);
|
||||
|
||||
int (*clear_sr_bp)(struct spi_nor *nor);
|
||||
struct spi_nor_flash_parameter params;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
static u64 __maybe_unused
|
||||
spi_nor_region_is_last(const struct spi_nor_erase_region *region)
|
||||
{
|
||||
return region->offset & SNOR_LAST_REGION;
|
||||
}
|
||||
|
||||
static u64 __maybe_unused
|
||||
spi_nor_region_end(const struct spi_nor_erase_region *region)
|
||||
{
|
||||
return (region->offset & ~SNOR_ERASE_FLAGS_MASK) + region->size;
|
||||
}
|
||||
|
||||
static void __maybe_unused
|
||||
spi_nor_region_mark_end(struct spi_nor_erase_region *region)
|
||||
{
|
||||
region->offset |= SNOR_LAST_REGION;
|
||||
}
|
||||
|
||||
static void __maybe_unused
|
||||
spi_nor_region_mark_overlay(struct spi_nor_erase_region *region)
|
||||
{
|
||||
region->offset |= SNOR_OVERLAID_REGION;
|
||||
}
|
||||
|
||||
static bool __maybe_unused spi_nor_has_uniform_erase(const struct spi_nor *nor)
|
||||
{
|
||||
return !!nor->params.erase_map.uniform_erase_type;
|
||||
}
|
||||
|
||||
static inline void spi_nor_set_flash_node(struct spi_nor *nor,
|
||||
struct device_node *np)
|
||||
{
|
||||
mtd_set_of_node(&nor->mtd, np);
|
||||
}
|
||||
|
||||
static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
|
||||
{
|
||||
return mtd_get_of_node(&nor->mtd);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_scan() - scan the SPI NOR
|
||||
* @nor: the spi_nor structure
|
||||
|
|
Loading…
Reference in New Issue