summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/devices/docg3.c5
-rw-r--r--drivers/mtd/devices/phram.c54
-rw-r--r--drivers/mtd/devices/powernv_flash.c5
-rw-r--r--drivers/mtd/maps/physmap-bt1-rom.c8
-rw-r--r--drivers/mtd/mtdchar.c2
-rw-r--r--drivers/mtd/mtdcore.c6
-rw-r--r--drivers/mtd/mtdpart.c2
-rw-r--r--drivers/mtd/nand/onenand/onenand_base.c444
-rw-r--r--drivers/mtd/nand/onenand/onenand_bbt.c32
-rw-r--r--drivers/mtd/nand/raw/arasan-nand-controller.c1
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand.c6
-rw-r--r--drivers/mtd/nand/raw/cafe_nand.c2
-rw-r--r--drivers/mtd/nand/raw/diskonchip.c4
-rw-r--r--drivers/mtd/nand/raw/omap2.c18
-rw-r--r--drivers/mtd/nand/raw/omap_elm.c7
-rw-r--r--drivers/mtd/nand/raw/s3c2410.c4
-rw-r--r--drivers/mtd/nand/raw/sunxi_nand.c1
-rw-r--r--drivers/mtd/nand/spi/toshiba.c2
-rw-r--r--drivers/mtd/parsers/cmdlinepart.c14
-rw-r--r--drivers/mtd/spi-nor/Kconfig44
-rw-r--r--drivers/mtd/spi-nor/atmel.c191
-rw-r--r--drivers/mtd/spi-nor/controllers/hisi-sfc.c2
-rw-r--r--drivers/mtd/spi-nor/core.c595
-rw-r--r--drivers/mtd/spi-nor/core.h38
-rw-r--r--drivers/mtd/spi-nor/esmt.c2
-rw-r--r--drivers/mtd/spi-nor/intel.c19
-rw-r--r--drivers/mtd/spi-nor/micron-st.c115
-rw-r--r--drivers/mtd/spi-nor/sfdp.c172
-rw-r--r--drivers/mtd/spi-nor/sfdp.h8
-rw-r--r--drivers/mtd/spi-nor/spansion.c172
-rw-r--r--drivers/mtd/spi-nor/sst.c32
-rw-r--r--drivers/mtd/ubi/build.c1
-rw-r--r--drivers/mtd/ubi/eba.c3
-rw-r--r--drivers/mtd/ubi/gluebi.c2
-rw-r--r--drivers/mtd/ubi/kapi.c2
-rw-r--r--drivers/mtd/ubi/wl.c3
36 files changed, 1528 insertions, 490 deletions
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index a030792115bc..5b0ae5ddad74 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -816,7 +816,7 @@ static void doc_read_page_finish(struct docg3 *docg3)
/**
* calc_block_sector - Calculate blocks, pages and ofs.
-
+ *
* @from: offset in flash
* @block0: first plane block index calculated
* @block1: second plane block index calculated
@@ -1783,10 +1783,9 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
/**
* doc_probe_device - Check if a device is available
- * @base: the io space where the device is probed
+ * @cascade: the cascade of chips this devices will belong to
* @floor: the floor of the probed device
* @dev: the device
- * @cascade: the cascade of chips this devices will belong to
*
* Checks whether a device at the specified IO range, and floor is available.
*
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 087b5e86d1bf..cfd170946ba4 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -1,19 +1,19 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* Copyright (c) ???? Jochen Schäuble <psionic@psionic.de>
* Copyright (c) 2003-2004 Joern Engel <joern@wh.fh-wedel.de>
*
* Usage:
*
* one commend line parameter per device, each in the form:
- * phram=<name>,<start>,<len>
+ * phram=<name>,<start>,<len>[,<erasesize>]
* <name> may be up to 63 characters.
- * <start> and <len> can be octal, decimal or hexadecimal. If followed
+ * <start>, <len>, and <erasesize> can be octal, decimal or hexadecimal. If followed
* by "ki", "Mi" or "Gi", the numbers will be interpreted as kilo, mega or
- * gigabytes.
+ * gigabytes. <erasesize> is optional and defaults to PAGE_SIZE.
*
* Example:
- * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
+ * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi,64Ki
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -26,6 +26,7 @@
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
+#include <asm/div64.h>
struct phram_mtd_list {
struct mtd_info mtd;
@@ -88,7 +89,7 @@ static void unregister_devices(void)
}
}
-static int register_device(char *name, phys_addr_t start, size_t len)
+static int register_device(char *name, phys_addr_t start, size_t len, uint32_t erasesize)
{
struct phram_mtd_list *new;
int ret = -ENOMEM;
@@ -115,7 +116,7 @@ static int register_device(char *name, phys_addr_t start, size_t len)
new->mtd._write = phram_write;
new->mtd.owner = THIS_MODULE;
new->mtd.type = MTD_RAM;
- new->mtd.erasesize = PAGE_SIZE;
+ new->mtd.erasesize = erasesize;
new->mtd.writesize = 1;
ret = -EAGAIN;
@@ -204,22 +205,23 @@ static inline void kill_final_newline(char *str)
static int phram_init_called;
/*
* This shall contain the module parameter if any. It is of the form:
- * - phram=<device>,<address>,<size> for module case
- * - phram.phram=<device>,<address>,<size> for built-in case
- * We leave 64 bytes for the device name, 20 for the address and 20 for the
- * size.
- * Example: phram.phram=rootfs,0xa0000000,512Mi
+ * - phram=<device>,<address>,<size>[,<erasesize>] for module case
+ * - phram.phram=<device>,<address>,<size>[,<erasesize>] for built-in case
+ * We leave 64 bytes for the device name, 20 for the address , 20 for the
+ * size and 20 for the erasesize.
+ * Example: phram.phram=rootfs,0xa0000000,512Mi,65536
*/
-static char phram_paramline[64 + 20 + 20];
+static char phram_paramline[64 + 20 + 20 + 20];
#endif
static int phram_setup(const char *val)
{
- char buf[64 + 20 + 20], *str = buf;
- char *token[3];
+ char buf[64 + 20 + 20 + 20], *str = buf;
+ char *token[4];
char *name;
uint64_t start;
uint64_t len;
+ uint64_t erasesize = PAGE_SIZE;
int i, ret;
if (strnlen(val, sizeof(buf)) >= sizeof(buf))
@@ -228,7 +230,7 @@ static int phram_setup(const char *val)
strcpy(str, val);
kill_final_newline(str);
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
token[i] = strsep(&str, ",");
if (str)
@@ -253,11 +255,25 @@ static int phram_setup(const char *val)
goto error;
}
- ret = register_device(name, start, len);
+ if (token[3]) {
+ ret = parse_num64(&erasesize, token[3]);
+ if (ret) {
+ parse_err("illegal erasesize\n");
+ goto error;
+ }
+ }
+
+ if (len == 0 || erasesize == 0 || erasesize > len
+ || erasesize > UINT_MAX || do_div(len, (uint32_t)erasesize) != 0) {
+ parse_err("illegal erasesize or len\n");
+ goto error;
+ }
+
+ ret = register_device(name, start, len, (uint32_t)erasesize);
if (ret)
goto error;
- pr_info("%s device: %#llx at %#llx\n", name, len, start);
+ pr_info("%s device: %#llx at %#llx for erasesize %#llx\n", name, len, start, erasesize);
return 0;
error:
@@ -298,7 +314,7 @@ static int phram_param_call(const char *val, const struct kernel_param *kp)
}
module_param_call(phram, phram_param_call, NULL, NULL, 0200);
-MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\"");
+MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>[,<erasesize>]\"");
static int __init init_phram(void)
diff --git a/drivers/mtd/devices/powernv_flash.c b/drivers/mtd/devices/powernv_flash.c
index 0b757d9ba2f6..6950a8764815 100644
--- a/drivers/mtd/devices/powernv_flash.c
+++ b/drivers/mtd/devices/powernv_flash.c
@@ -126,6 +126,7 @@ out:
}
/**
+ * powernv_flash_read
* @mtd: the device
* @from: the offset to read from
* @len: the number of bytes to read
@@ -142,6 +143,7 @@ static int powernv_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
}
/**
+ * powernv_flash_write
* @mtd: the device
* @to: the offset to write to
* @len: the number of bytes to write
@@ -158,6 +160,7 @@ static int powernv_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
}
/**
+ * powernv_flash_erase
* @mtd: the device
* @erase: the erase info
* Returns 0 if erase successful or -ERRNO if an error occurred
@@ -176,7 +179,7 @@ static int powernv_flash_erase(struct mtd_info *mtd, struct erase_info *erase)
/**
* powernv_flash_set_driver_info - Fill the mtd_info structure and docg3
- * structure @pdev: The platform device
+ * @dev: The device structure
* @mtd: The structure to fill
*/
static int powernv_flash_set_driver_info(struct device *dev,
diff --git a/drivers/mtd/maps/physmap-bt1-rom.c b/drivers/mtd/maps/physmap-bt1-rom.c
index 27cfe1c63a2e..a35450002284 100644
--- a/drivers/mtd/maps/physmap-bt1-rom.c
+++ b/drivers/mtd/maps/physmap-bt1-rom.c
@@ -31,12 +31,12 @@ static map_word __xipram bt1_rom_map_read(struct map_info *map,
unsigned long ofs)
{
void __iomem *src = map->virt + ofs;
- unsigned long shift;
+ unsigned int shift;
map_word ret;
u32 data;
/* Read data within offset dword. */
- shift = (unsigned long)src & 0x3;
+ shift = (uintptr_t)src & 0x3;
data = readl_relaxed(src - shift);
if (!shift) {
ret.x[0] = data;
@@ -60,7 +60,7 @@ static void __xipram bt1_rom_map_copy_from(struct map_info *map,
ssize_t len)
{
void __iomem *src = map->virt + from;
- ssize_t shift, chunk;
+ unsigned int shift, chunk;
u32 data;
if (len <= 0 || from >= map->size)
@@ -75,7 +75,7 @@ static void __xipram bt1_rom_map_copy_from(struct map_info *map,
* up into the next three stages: unaligned head, aligned body,
* unaligned tail.
*/
- shift = (ssize_t)src & 0x3;
+ shift = (uintptr_t)src & 0x3;
if (shift) {
chunk = min_t(ssize_t, 4 - shift, len);
data = readl_relaxed(src - shift);
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index b40f46a43fc6..323035d4f2d0 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -881,7 +881,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
if (copy_from_user(&offs, argp, sizeof(loff_t)))
return -EFAULT;
return mtd_block_isbad(mtd, offs);
- break;
}
case MEMSETBADBLOCK:
@@ -891,7 +890,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
if (copy_from_user(&offs, argp, sizeof(loff_t)))
return -EFAULT;
return mtd_block_markbad(mtd, offs);
- break;
}
case OTPSELECT:
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index e9e163ae9d86..2d6423d89a17 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -993,6 +993,8 @@ int __get_mtd_device(struct mtd_info *mtd)
}
}
+ master->usecount++;
+
while (mtd->parent) {
mtd->usecount++;
mtd = mtd->parent;
@@ -1059,6 +1061,8 @@ void __put_mtd_device(struct mtd_info *mtd)
mtd = mtd->parent;
}
+ master->usecount--;
+
if (master->_put_device)
master->_put_device(master);
@@ -1578,7 +1582,7 @@ static int mtd_ooblayout_find_region(struct mtd_info *mtd, int byte,
* ECC byte
* @mtd: mtd info structure
* @eccbyte: the byte we are searching for
- * @sectionp: pointer where the section id will be stored
+ * @section: pointer where the section id will be stored
* @oobregion: OOB region information
*
* Works like mtd_ooblayout_find_region() except it searches for a specific ECC
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index c3575b686f79..12ca4f19cb14 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -292,7 +292,7 @@ EXPORT_SYMBOL_GPL(mtd_add_partition);
/**
* __mtd_del_partition - delete MTD partition
*
- * @priv: MTD structure to be deleted
+ * @mtd: MTD structure to be deleted
*
* This function must be called with the partitions mutex locked.
*/
diff --git a/drivers/mtd/nand/onenand/onenand_base.c b/drivers/mtd/nand/onenand/onenand_base.c
index 188b8061e1f7..a9fdea26ea46 100644
--- a/drivers/mtd/nand/onenand/onenand_base.c
+++ b/drivers/mtd/nand/onenand/onenand_base.c
@@ -132,7 +132,7 @@ static const struct mtd_ooblayout_ops onenand_oob_128_ooblayout_ops = {
.free = onenand_ooblayout_128_free,
};
-/**
+/*
* onenand_oob_32_64 - oob info for large (2KB) page
*/
static int onenand_ooblayout_32_64_ecc(struct mtd_info *mtd, int section,
@@ -192,7 +192,7 @@ static const unsigned char ffchars[] = {
/**
* onenand_readw - [OneNAND Interface] Read OneNAND register
- * @param addr address to read
+ * @addr: address to read
*
* Read OneNAND register
*/
@@ -203,8 +203,8 @@ static unsigned short onenand_readw(void __iomem *addr)
/**
* onenand_writew - [OneNAND Interface] Write OneNAND register with value
- * @param value value to write
- * @param addr address to write
+ * @value: value to write
+ * @addr: address to write
*
* Write OneNAND register with value
*/
@@ -215,8 +215,8 @@ static void onenand_writew(unsigned short value, void __iomem *addr)
/**
* onenand_block_address - [DEFAULT] Get block address
- * @param this onenand chip data structure
- * @param block the block
+ * @this: onenand chip data structure
+ * @block: the block
* @return translated block address if DDP, otherwise same
*
* Setup Start Address 1 Register (F100h)
@@ -232,8 +232,8 @@ static int onenand_block_address(struct onenand_chip *this, int block)
/**
* onenand_bufferram_address - [DEFAULT] Get bufferram address
- * @param this onenand chip data structure
- * @param block the block
+ * @this: onenand chip data structure
+ * @block: the block
* @return set DBS value if DDP, otherwise 0
*
* Setup Start Address 2 Register (F101h) for DDP
@@ -249,8 +249,8 @@ static int onenand_bufferram_address(struct onenand_chip *this, int block)
/**
* onenand_page_address - [DEFAULT] Get page address
- * @param page the page address
- * @param sector the sector address
+ * @page: the page address
+ * @sector: the sector address
* @return combined page and sector address
*
* Setup Start Address 8 Register (F107h)
@@ -268,10 +268,10 @@ static int onenand_page_address(int page, int sector)
/**
* onenand_buffer_address - [DEFAULT] Get buffer address
- * @param dataram1 DataRAM index
- * @param sectors the sector address
- * @param count the number of sectors
- * @return the start buffer value
+ * @dataram1: DataRAM index
+ * @sectors: the sector address
+ * @count: the number of sectors
+ * Return: the start buffer value
*
* Setup Start Buffer Register (F200h)
*/
@@ -295,8 +295,8 @@ static int onenand_buffer_address(int dataram1, int sectors, int count)
/**
* flexonenand_block- For given address return block number
- * @param this - OneNAND device structure
- * @param addr - Address for which block number is needed
+ * @this: - OneNAND device structure
+ * @addr: - Address for which block number is needed
*/
static unsigned flexonenand_block(struct onenand_chip *this, loff_t addr)
{
@@ -359,7 +359,7 @@ EXPORT_SYMBOL(onenand_addr);
/**
* onenand_get_density - [DEFAULT] Get OneNAND density
- * @param dev_id OneNAND device ID
+ * @dev_id: OneNAND device ID
*
* Get OneNAND density from device ID
*/
@@ -371,8 +371,8 @@ static inline int onenand_get_density(int dev_id)
/**
* flexonenand_region - [Flex-OneNAND] Return erase region of addr
- * @param mtd MTD device structure
- * @param addr address whose erase region needs to be identified
+ * @mtd: MTD device structure
+ * @addr: address whose erase region needs to be identified
*/
int flexonenand_region(struct mtd_info *mtd, loff_t addr)
{
@@ -387,10 +387,10 @@ EXPORT_SYMBOL(flexonenand_region);
/**
* onenand_command - [DEFAULT] Send command to OneNAND device
- * @param mtd MTD device structure
- * @param cmd the command to be sent
- * @param addr offset to read from or write to
- * @param len number of bytes to read or write
+ * @mtd: MTD device structure
+ * @cmd: the command to be sent
+ * @addr: offset to read from or write to
+ * @len: number of bytes to read or write
*
* Send command to OneNAND device. This function is used for middle/large page
* devices (1KB/2KB Bytes per page)
@@ -519,7 +519,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
/**
* onenand_read_ecc - return ecc status
- * @param this onenand chip structure
+ * @this: onenand chip structure
*/
static inline int onenand_read_ecc(struct onenand_chip *this)
{
@@ -543,8 +543,8 @@ static inline int onenand_read_ecc(struct onenand_chip *this)
/**
* onenand_wait - [DEFAULT] wait until the command is done
- * @param mtd MTD device structure
- * @param state state to select the max. timeout value
+ * @mtd: MTD device structure
+ * @state: state to select the max. timeout value
*
* Wait for command done. This applies to all OneNAND command
* Read can take up to 30us, erase up to 2ms and program up to 350us
@@ -625,8 +625,8 @@ static int onenand_wait(struct mtd_info *mtd, int state)
/*
* onenand_interrupt - [DEFAULT] onenand interrupt handler
- * @param irq onenand interrupt number
- * @param dev_id interrupt data
+ * @irq: onenand interrupt number
+ * @dev_id: interrupt data
*
* complete the work
*/
@@ -643,8 +643,8 @@ static irqreturn_t onenand_interrupt(int irq, void *data)
/*
* onenand_interrupt_wait - [DEFAULT] wait until the command is done
- * @param mtd MTD device structure
- * @param state state to select the max. timeout value
+ * @mtd: MTD device structure
+ * @state: state to select the max. timeout value
*
* Wait for command done.
*/
@@ -659,8 +659,8 @@ static int onenand_interrupt_wait(struct mtd_info *mtd, int state)
/*
* onenand_try_interrupt_wait - [DEFAULT] try interrupt wait
- * @param mtd MTD device structure
- * @param state state to select the max. timeout value
+ * @mtd: MTD device structure
+ * @state: state to select the max. timeout value
*
* Try interrupt based wait (It is used one-time)
*/
@@ -689,7 +689,7 @@ static int onenand_try_interrupt_wait(struct mtd_info *mtd, int state)
/*
* onenand_setup_wait - [OneNAND Interface] setup onenand wait method
- * @param mtd MTD device structure
+ * @mtd: MTD device structure
*
* There's two method to wait onenand work
* 1. polling - read interrupt status register
@@ -724,8 +724,8 @@ static void onenand_setup_wait(struct mtd_info *mtd)
/**
* onenand_bufferram_offset - [DEFAULT] BufferRAM offset
- * @param mtd MTD data structure
- * @param area BufferRAM area
+ * @mtd: MTD data structure
+ * @area: BufferRAM area
* @return offset given area
*
* Return BufferRAM offset given area
@@ -747,11 +747,11 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
/**
* onenand_read_bufferram - [OneNAND Interface] Read the bufferram area
- * @param mtd MTD data structure
- * @param area BufferRAM area
- * @param buffer the databuffer to put/get data
- * @param offset offset to read from or write to
- * @param count number of bytes to read/write
+ * @mtd: MTD data structure
+ * @area: BufferRAM area
+ * @buffer: the databuffer to put/get data
+ * @offset: offset to read from or write to
+ * @count: number of bytes to read/write
*
* Read the BufferRAM area
*/
@@ -783,11 +783,11 @@ static int onenand_read_bufferram(struct mtd_info *mtd, int area,
/**
* onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode
- * @param mtd MTD data structure
- * @param area BufferRAM area
- * @param buffer the databuffer to put/get data
- * @param offset offset to read from or write to
- * @param count number of bytes to read/write
+ * @mtd: MTD data structure
+ * @area: BufferRAM area
+ * @buffer: the databuffer to put/get data
+ * @offset: offset to read from or write to
+ * @count: number of bytes to read/write
*
* Read the BufferRAM area with Sync. Burst Mode
*/
@@ -823,11 +823,11 @@ static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area,
/**
* onenand_write_bufferram - [OneNAND Interface] Write the bufferram area
- * @param mtd MTD data structure
- * @param area BufferRAM area
- * @param buffer the databuffer to put/get data
- * @param offset offset to read from or write to
- * @param count number of bytes to read/write
+ * @mtd: MTD data structure
+ * @area: BufferRAM area
+ * @buffer: the databuffer to put/get data
+ * @offset: offset to read from or write to
+ * @count: number of bytes to read/write
*
* Write the BufferRAM area
*/
@@ -864,8 +864,8 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area,
/**
* onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode
- * @param mtd MTD data structure
- * @param addr address to check
+ * @mtd: MTD data structure
+ * @addr: address to check
* @return blockpage address
*
* Get blockpage address at 2x program mode
@@ -888,8 +888,8 @@ static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr)
/**
* onenand_check_bufferram - [GENERIC] Check BufferRAM information
- * @param mtd MTD data structure
- * @param addr address to check
+ * @mtd: MTD data structure
+ * @addr: address to check
* @return 1 if there are valid data, otherwise 0
*
* Check bufferram if there is data we required
@@ -930,9 +930,9 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
/**
* onenand_update_bufferram - [GENERIC] Update BufferRAM information
- * @param mtd MTD data structure
- * @param addr address to update
- * @param valid valid flag
+ * @mtd: MTD data structure
+ * @addr: address to update
+ * @valid: valid flag
*
* Update BufferRAM information
*/
@@ -963,9 +963,9 @@ static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
/**
* onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information
- * @param mtd MTD data structure
- * @param addr start address to invalidate
- * @param len length to invalidate
+ * @mtd: MTD data structure
+ * @addr: start address to invalidate
+ * @len: length to invalidate
*
* Invalidate BufferRAM information
*/
@@ -986,8 +986,8 @@ static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr,
/**
* onenand_get_device - [GENERIC] Get chip for selected access
- * @param mtd MTD device structure
- * @param new_state the state which is requested
+ * @mtd: MTD device structure
+ * @new_state: the state which is requested
*
* Get the device and lock it for exclusive access
*/
@@ -1024,7 +1024,7 @@ static int onenand_get_device(struct mtd_info *mtd, int new_state)
/**
* onenand_release_device - [GENERIC] release chip
- * @param mtd MTD device structure
+ * @mtd: MTD device structure
*
* Deselect, release chip lock and wake up anyone waiting on the device
*/
@@ -1043,10 +1043,10 @@ static void onenand_release_device(struct mtd_info *mtd)
/**
* onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer
- * @param mtd MTD device structure
- * @param buf destination address
- * @param column oob offset to read from
- * @param thislen oob length to read
+ * @mtd: MTD device structure
+ * @buf: destination address
+ * @column: oob offset to read from
+ * @thislen: oob length to read
*/
static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column,
int thislen)
@@ -1061,9 +1061,9 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
/**
* onenand_recover_lsb - [Flex-OneNAND] Recover LSB page data
- * @param mtd MTD device structure
- * @param addr address to recover
- * @param status return value from onenand_wait / onenand_bbt_wait
+ * @mtd: MTD device structure
+ * @addr: address to recover
+ * @status: return value from onenand_wait / onenand_bbt_wait
*
* MLC NAND Flash cell has paired pages - LSB page and MSB page. LSB page has
* lower page address and MSB page has higher page address in paired pages.
@@ -1104,9 +1104,9 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
/**
* onenand_mlc_read_ops_nolock - MLC OneNAND read main and/or out-of-band
- * @param mtd MTD device structure
- * @param from offset to read from
- * @param ops: oob operation description structure
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operation description structure
*
* MLC OneNAND / Flex-OneNAND has 4KB page size and 4KB dataram.
* So, read-while-load is not present.
@@ -1206,9 +1206,9 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
/**
* onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
- * @param mtd MTD device structure
- * @param from offset to read from
- * @param ops: oob operation description structure
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operation description structure
*
* OneNAND read main and/or out-of-band data
*/
@@ -1335,9 +1335,9 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
/**
* onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
- * @param mtd MTD device structure
- * @param from offset to read from
- * @param ops: oob operation description structure
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operation description structure
*
* OneNAND read out-of-band data from the spare area
*/
@@ -1430,10 +1430,10 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
/**
* onenand_read_oob - [MTD Interface] Read main and/or out-of-band
- * @param mtd: MTD device structure
- * @param from: offset to read from
- * @param ops: oob operation description structure
-
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operation description structure
+ *
* Read main and/or out-of-band
*/
static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
@@ -1466,8 +1466,8 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
/**
* onenand_bbt_wait - [DEFAULT] wait until the command is done
- * @param mtd MTD device structure
- * @param state state to select the max. timeout value
+ * @mtd: MTD device structure
+ * @state: state to select the max. timeout value
*
* Wait for command done.
*/
@@ -1517,9 +1517,9 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
/**
* onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
- * @param mtd MTD device structure
- * @param from offset to read from
- * @param ops oob operation description structure
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operation description structure
*
* OneNAND read out-of-band data from the spare area for bbt scan
*/
@@ -1594,9 +1594,9 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
/**
* onenand_verify_oob - [GENERIC] verify the oob contents after a write
- * @param mtd MTD device structure
- * @param buf the databuffer to verify
- * @param to offset to read from
+ * @mtd: MTD device structure
+ * @buf: the databuffer to verify
+ * @to: offset to read from
*/
static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
{
@@ -1622,10 +1622,10 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
/**
* onenand_verify - [GENERIC] verify the chip contents after a write
- * @param mtd MTD device structure
- * @param buf the databuffer to verify
- * @param addr offset to read from
- * @param len number of bytes to read and compare
+ * @mtd: MTD device structure
+ * @buf: the databuffer to verify
+ * @addr: offset to read from
+ * @len: number of bytes to read and compare
*/
static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
{
@@ -1684,11 +1684,11 @@ static void onenand_panic_wait(struct mtd_info *mtd)
/**
* onenand_panic_write - [MTD Interface] write buffer to FLASH in a panic context
- * @param mtd MTD device structure
- * @param to offset to write to
- * @param len number of bytes to write
- * @param retlen pointer to variable to store the number of written bytes
- * @param buf the data to write
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @len: number of bytes to write
+ * @retlen: pointer to variable to store the number of written bytes
+ * @buf: the data to write
*
* Write with ECC
*/
@@ -1762,11 +1762,11 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
/**
* onenand_fill_auto_oob - [INTERN] oob auto-placement transfer
- * @param mtd MTD device structure
- * @param oob_buf oob buffer
- * @param buf source address
- * @param column oob offset to write to
- * @param thislen oob length to write
+ * @mtd: MTD device structure
+ * @oob_buf: oob buffer
+ * @buf: source address
+ * @column: oob offset to write to
+ * @thislen: oob length to write
*/
static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
const u_char *buf, int column, int thislen)
@@ -1776,9 +1776,9 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
/**
* onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
- * @param mtd MTD device structure
- * @param to offset to write to
- * @param ops oob operation description structure
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operation description structure
*
* Write main and/or oob with ECC
*/
@@ -1957,12 +1957,9 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
/**
* onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band
- * @param mtd MTD device structure
- * @param to offset to write to
- * @param len number of bytes to write
- * @param retlen pointer to variable to store the number of written bytes
- * @param buf the data to write
- * @param mode operation mode
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operation description structure
*
* OneNAND write out-of-band
*/
@@ -2070,9 +2067,9 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
/**
* onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
- * @param mtd: MTD device structure
- * @param to: offset to write
- * @param ops: oob operation description structure
+ * @mtd: MTD device structure
+ * @to: offset to write
+ * @ops: oob operation description structure
*/
static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
@@ -2101,9 +2098,9 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
/**
* onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
- * @param mtd MTD device structure
- * @param ofs offset from device start
- * @param allowbbt 1, if its allowed to access the bbt area
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ * @allowbbt: 1, if its allowed to access the bbt area
*
* Check, if the block is bad. Either by reading the bad block table or
* calling of the scan function.
@@ -2144,9 +2141,9 @@ static int onenand_multiblock_erase_verify(struct mtd_info *mtd,
/**
* onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase
- * @param mtd MTD device structure
- * @param instr erase instruction
- * @param region erase region
+ * @mtd: MTD device structure
+ * @instr: erase instruction
+ * @block_size: block size
*
* Erase one or more blocks up to 64 block at a time
*/
@@ -2254,10 +2251,10 @@ static int onenand_multiblock_erase(struct mtd_info *mtd,
/**
* onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase
- * @param mtd MTD device structure
- * @param instr erase instruction
- * @param region erase region
- * @param block_size erase block size
+ * @mtd: MTD device structure
+ * @instr: erase instruction
+ * @region: erase region
+ * @block_size: erase block size
*
* Erase one or more blocks one block at a time
*/
@@ -2326,8 +2323,8 @@ static int onenand_block_by_block_erase(struct mtd_info *mtd,
/**
* onenand_erase - [MTD Interface] erase block(s)
- * @param mtd MTD device structure
- * @param instr erase instruction
+ * @mtd: MTD device structure
+ * @instr: erase instruction
*
* Erase one or more blocks
*/
@@ -2391,7 +2388,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
/**
* onenand_sync - [MTD Interface] sync
- * @param mtd MTD device structure
+ * @mtd: MTD device structure
*
* Sync is actually a wait for chip ready function
*/
@@ -2408,8 +2405,8 @@ static void onenand_sync(struct mtd_info *mtd)
/**
* onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
- * @param mtd MTD device structure
- * @param ofs offset relative to mtd start
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
*
* Check whether the block is bad
*/
@@ -2425,8 +2422,8 @@ static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
/**
* onenand_default_block_markbad - [DEFAULT] mark a block bad
- * @param mtd MTD device structure
- * @param ofs offset from device start
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
*
* This is the default implementation, which can be overridden by
* a hardware specific driver.
@@ -2460,8 +2457,8 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/**
* onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
- * @param mtd MTD device structure
- * @param ofs offset relative to mtd start
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
*
* Mark the block as bad
*/
@@ -2486,10 +2483,10 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
/**
* onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s)
- * @param mtd MTD device structure
- * @param ofs offset relative to mtd start
- * @param len number of bytes to lock or unlock
- * @param cmd lock or unlock command
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ * @len: number of bytes to lock or unlock
+ * @cmd: lock or unlock command
*
* Lock or unlock one or more blocks
*/
@@ -2566,9 +2563,9 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
/**
* onenand_lock - [MTD Interface] Lock block(s)
- * @param mtd MTD device structure
- * @param ofs offset relative to mtd start
- * @param len number of bytes to unlock
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ * @len: number of bytes to unlock
*
* Lock one or more blocks
*/
@@ -2584,9 +2581,9 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
/**
* onenand_unlock - [MTD Interface] Unlock block(s)
- * @param mtd MTD device structure
- * @param ofs offset relative to mtd start
- * @param len number of bytes to unlock
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ * @len: number of bytes to unlock
*
* Unlock one or more blocks
*/
@@ -2602,7 +2599,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
/**
* onenand_check_lock_status - [OneNAND Interface] Check lock status
- * @param this onenand chip data structure
+ * @this: onenand chip data structure
*
* Check lock status
*/
@@ -2636,7 +2633,7 @@ static int onenand_check_lock_status(struct onenand_chip *this)
/**
* onenand_unlock_all - [OneNAND Interface] unlock all blocks
- * @param mtd MTD device structure
+ * @mtd: MTD device structure
*
* Unlock all blocks
*/
@@ -2683,10 +2680,10 @@ static void onenand_unlock_all(struct mtd_info *mtd)
/**
* onenand_otp_command - Send OTP specific command to OneNAND device
- * @param mtd MTD device structure
- * @param cmd the command to be sent
- * @param addr offset to read from or write to
- * @param len number of bytes to read or write
+ * @mtd: MTD device structure
+ * @cmd: the command to be sent
+ * @addr: offset to read from or write to
+ * @len: number of bytes to read or write
*/
static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr,
size_t len)
@@ -2758,11 +2755,9 @@ static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr,
/**
* onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP
- * @param mtd MTD device structure
- * @param to offset to write to
- * @param len number of bytes to write
- * @param retlen pointer to variable to store the number of written bytes
- * @param buf the data to write
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operation description structure
*
* OneNAND write out-of-band only for OTP
*/
@@ -2889,11 +2884,11 @@ typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len,
/**
* do_otp_read - [DEFAULT] Read OTP block area
- * @param mtd MTD device structure
- * @param from The offset to read
- * @param len number of bytes to read
- * @param retlen pointer to variable to store the number of readbytes
- * @param buf the databuffer to put/get data
+ * @mtd: MTD device structure
+ * @from: The offset to read
+ * @len: number of bytes to read
+ * @retlen: pointer to variable to store the number of readbytes
+ * @buf: the databuffer to put/get data
*
* Read OTP block area.
*/
@@ -2926,11 +2921,11 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
/**
* do_otp_write - [DEFAULT] Write OTP block area
- * @param mtd MTD device structure
- * @param to The offset to write
- * @param len number of bytes to write
- * @param retlen pointer to variable to store the number of write bytes
- * @param buf the databuffer to put/get data
+ * @mtd: MTD device structure
+ * @to: The offset to write
+ * @len: number of bytes to write
+ * @retlen: pointer to variable to store the number of write bytes
+ * @buf: the databuffer to put/get data
*
* Write OTP block area.
*/
@@ -2970,11 +2965,11 @@ static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
/**
* do_otp_lock - [DEFAULT] Lock OTP block area
- * @param mtd MTD device structure
- * @param from The offset to lock
- * @param len number of bytes to lock
- * @param retlen pointer to variable to store the number of lock bytes
- * @param buf the databuffer to put/get data
+ * @mtd: MTD device structure
+ * @from: The offset to lock
+ * @len: number of bytes to lock
+ * @retlen: pointer to variable to store the number of lock bytes
+ * @buf: the databuffer to put/get data
*
* Lock OTP block area.
*/
@@ -3018,13 +3013,13 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
/**
* onenand_otp_walk - [DEFAULT] Handle OTP operation
- * @param mtd MTD device structure
- * @param from The offset to read/write
- * @param len number of bytes to read/write
- * @param retlen pointer to variable to store the number of read bytes
- * @param buf the databuffer to put/get data
- * @param action do given action
- * @param mode specify user and factory
+ * @mtd: MTD device structure
+ * @from: The offset to read/write
+ * @len: number of bytes to read/write
+ * @retlen: pointer to variable to store the number of read bytes
+ * @buf: the databuffer to put/get data
+ * @action: do given action
+ * @mode: specify user and factory
*
* Handle OTP operation.
*/
@@ -3099,10 +3094,10 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
/**
* onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info
- * @param mtd MTD device structure
- * @param len number of bytes to read
- * @param retlen pointer to variable to store the number of read bytes
- * @param buf the databuffer to put/get data
+ * @mtd: MTD device structure
+ * @len: number of bytes to read
+ * @retlen: pointer to variable to store the number of read bytes
+ * @buf: the databuffer to put/get data
*
* Read factory OTP info.
*/
@@ -3115,11 +3110,11 @@ static int onenand_get_fact_prot_info(struct mtd_info *mtd, size_t len,
/**
* onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area
- * @param mtd MTD device structure
- * @param from The offset to read
- * @param len number of bytes to read
- * @param retlen pointer to variable to store the number of read bytes
- * @param buf the databuffer to put/get data
+ * @mtd: MTD device structure
+ * @from: The offset to read
+ * @len: number of bytes to read
+ * @retlen: pointer to variable to store the number of read bytes
+ * @buf: the databuffer to put/get data
*
* Read factory OTP area.
*/
@@ -3131,10 +3126,10 @@ static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
/**
* onenand_get_user_prot_info - [MTD Interface] Read user OTP info
- * @param mtd MTD device structure
- * @param retlen pointer to variable to store the number of read bytes
- * @param len number of bytes to read
- * @param buf the databuffer to put/get data
+ * @mtd: MTD device structure
+ * @retlen: pointer to variable to store the number of read bytes
+ * @len: number of bytes to read
+ * @buf: the databuffer to put/get data
*
* Read user OTP info.
*/
@@ -3147,11 +3142,11 @@ static int onenand_get_user_prot_info(struct mtd_info *mtd, size_t len,
/**
* onenand_read_user_prot_reg - [MTD Interface] Read user OTP area
- * @param mtd MTD device structure
- * @param from The offset to read
- * @param len number of bytes to read
- * @param retlen pointer to variable to store the number of read bytes
- * @param buf the databuffer to put/get data
+ * @mtd: MTD device structure
+ * @from: The offset to read
+ * @len: number of bytes to read
+ * @retlen: pointer to variable to store the number of read bytes
+ * @buf: the databuffer to put/get data
*
* Read user OTP area.
*/
@@ -3163,11 +3158,11 @@ static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
/**
* onenand_write_user_prot_reg - [MTD Interface] Write user OTP area
- * @param mtd MTD device structure
- * @param from The offset to write
- * @param len number of bytes to write
- * @param retlen pointer to variable to store the number of write bytes
- * @param buf the databuffer to put/get data
+ * @mtd: MTD device structure
+ * @from: The offset to write
+ * @len: number of bytes to write
+ * @retlen: pointer to variable to store the number of write bytes
+ * @buf: the databuffer to put/get data
*
* Write user OTP area.
*/
@@ -3179,9 +3174,9 @@ static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
/**
* onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area
- * @param mtd MTD device structure
- * @param from The offset to lock
- * @param len number of bytes to unlock
+ * @mtd: MTD device structure
+ * @from: The offset to lock
+ * @len: number of bytes to unlock
*
* Write lock mark on spare area in page 0 in OTP block
*/
@@ -3234,7 +3229,7 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
/**
* onenand_check_features - Check and set OneNAND features
- * @param mtd MTD data structure
+ * @mtd: MTD data structure
*
* Check and set OneNAND features
* - lock scheme
@@ -3324,8 +3319,8 @@ static void onenand_check_features(struct mtd_info *mtd)
/**
* onenand_print_device_info - Print device & version ID
- * @param device device ID
- * @param version version ID
+ * @device: device ID
+ * @version: version ID
*
* Print device & version ID
*/
@@ -3355,7 +3350,7 @@ static const struct onenand_manufacturers onenand_manuf_ids[] = {
/**
* onenand_check_maf - Check manufacturer ID
- * @param manuf manufacturer ID
+ * @manuf: manufacturer ID
*
* Check manufacturer ID
*/
@@ -3380,9 +3375,9 @@ static int onenand_check_maf(int manuf)
}
/**
-* flexonenand_get_boundary - Reads the SLC boundary
-* @param onenand_info - onenand info structure
-**/
+ * flexonenand_get_boundary - Reads the SLC boundary
+ * @mtd: MTD data structure
+ */
static int flexonenand_get_boundary(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
@@ -3422,7 +3417,7 @@ static int flexonenand_get_boundary(struct mtd_info *mtd)
/**
* flexonenand_get_size - Fill up fields in onenand_chip and mtd_info
* boundary[], diesize[], mtd->size, mtd->erasesize
- * @param mtd - MTD device structure
+ * @mtd: - MTD device structure
*/
static void flexonenand_get_size(struct mtd_info *mtd)
{
@@ -3493,9 +3488,9 @@ static void flexonenand_get_size(struct mtd_info *mtd)
/**
* flexonenand_check_blocks_erased - Check if blocks are erased
- * @param mtd_info - mtd info structure
- * @param start - first erase block to check
- * @param end - last erase block to check
+ * @mtd: mtd info structure
+ * @start: first erase block to check
+ * @end: last erase block to check
*
* Converting an unerased block from MLC to SLC
* causes byte values to change. Since both data and its ECC
@@ -3548,9 +3543,8 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int
return 0;
}
-/**
+/*
* flexonenand_set_boundary - Writes the SLC boundary
- * @param mtd - mtd info structure
*/
static int flexonenand_set_boundary(struct mtd_info *mtd, int die,
int boundary, int lock)
@@ -3640,7 +3634,7 @@ out:
/**
* onenand_chip_probe - [OneNAND Interface] The generic chip probe
- * @param mtd MTD device structure
+ * @mtd: MTD device structure
*
* OneNAND detection method:
* Compare the values from command with ones from register
@@ -3688,7 +3682,7 @@ static int onenand_chip_probe(struct mtd_info *mtd)
/**
* onenand_probe - [OneNAND Interface] Probe the OneNAND device
- * @param mtd MTD device structure
+ * @mtd: MTD device structure
*/
static int onenand_probe(struct mtd_info *mtd)
{
@@ -3783,7 +3777,7 @@ static int onenand_probe(struct mtd_info *mtd)
/**
* onenand_suspend - [MTD Interface] Suspend the OneNAND flash
- * @param mtd MTD device structure
+ * @mtd: MTD device structure
*/
static int onenand_suspend(struct mtd_info *mtd)
{
@@ -3792,7 +3786,7 @@ static int onenand_suspend(struct mtd_info *mtd)
/**
* onenand_resume - [MTD Interface] Resume the OneNAND flash
- * @param mtd MTD device structure
+ * @mtd: MTD device structure
*/
static void onenand_resume(struct mtd_info *mtd)
{
@@ -3807,8 +3801,8 @@ static void onenand_resume(struct mtd_info *mtd)
/**
* onenand_scan - [OneNAND Interface] Scan for the OneNAND device
- * @param mtd MTD device structure
- * @param maxchips Number of chips to scan for
+ * @mtd: MTD device structure
+ * @maxchips: Number of chips to scan for
*
* This fills out all the not initialized function pointers
* with the defaults.
@@ -3985,7 +3979,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
/**
* onenand_release - [OneNAND Interface] Free resources held by the OneNAND device
- * @param mtd MTD device structure
+ * @mtd: MTD device structure
*/
void onenand_release(struct mtd_info *mtd)
{
diff --git a/drivers/mtd/nand/onenand/onenand_bbt.c b/drivers/mtd/nand/onenand/onenand_bbt.c
index 57c31c81be18..def89f108007 100644
--- a/drivers/mtd/nand/onenand/onenand_bbt.c
+++ b/drivers/mtd/nand/onenand/onenand_bbt.c
@@ -18,10 +18,10 @@
/**
* check_short_pattern - [GENERIC] check if a pattern is in the buffer
- * @param buf the buffer to search
- * @param len the length of buffer to search
- * @param paglen the pagelength
- * @param td search pattern descriptor
+ * @buf: the buffer to search
+ * @len: the length of buffer to search
+ * @paglen: the pagelength
+ * @td: search pattern descriptor
*
* Check for a pattern at the given place. Used to search bad block
* tables and good / bad block identifiers. Same as check_pattern, but
@@ -44,10 +44,10 @@ static int check_short_pattern(uint8_t *buf, int len, int paglen, struct nand_bb
/**
* create_bbt - [GENERIC] Create a bad block table by scanning the device
- * @param mtd MTD device structure
- * @param buf temporary buffer
- * @param bd descriptor for the good/bad block search pattern
- * @param chip create the table for a specific chip, -1 read all chips.
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @bd: descriptor for the good/bad block search pattern
+ * @chip: create the table for a specific chip, -1 read all chips.
* Applies only if NAND_BBT_PERCHIP option is set
*
* Create a bad block table by scanning the device
@@ -122,8 +122,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
/**
* onenand_memory_bbt - [GENERIC] create a memory based bad block table
- * @param mtd MTD device structure
- * @param bd descriptor for the good/bad block search pattern
+ * @mtd: MTD device structure
+ * @bd: descriptor for the good/bad block search pattern
*
* The function creates a memory based bbt by scanning the device
* for manufacturer / software marked good / bad blocks
@@ -137,9 +137,9 @@ static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_desc
/**
* onenand_isbad_bbt - [OneNAND Interface] Check if a block is bad
- * @param mtd MTD device structure
- * @param offs offset in the device
- * @param allowbbt allow access to bad block table region
+ * @mtd: MTD device structure
+ * @offs: offset in the device
+ * @allowbbt: allow access to bad block table region
*/
static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
{
@@ -166,8 +166,8 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
/**
* onenand_scan_bbt - [OneNAND Interface] scan, find, read and maybe create bad block table(s)
- * @param mtd MTD device structure
- * @param bd descriptor for the good/bad block search pattern
+ * @mtd: MTD device structure
+ * @bd: descriptor for the good/bad block search pattern
*
* The function checks, if a bad block table(s) is/are already
* available. If not it scans the device for manufacturer
@@ -221,7 +221,7 @@ static struct nand_bbt_descr largepage_memorybased = {
/**
* onenand_default_bbt - [OneNAND Interface] Select a default bad block table for the device
- * @param mtd MTD device structure
+ * @mtd: MTD device structure
*
* This function selects the default bad block table
* support for the device and calls the onenand_scan_bbt function
diff --git a/drivers/mtd/nand/raw/arasan-nand-controller.c b/drivers/mtd/nand/raw/arasan-nand-controller.c
index fbb4ea751be8..549aac00228e 100644
--- a/drivers/mtd/nand/raw/arasan-nand-controller.c
+++ b/drivers/mtd/nand/raw/arasan-nand-controller.c
@@ -118,6 +118,7 @@
* @rdy_timeout_ms: Timeout for waits on Ready/Busy pin
* @len: Data transfer length
* @read: Data transfer direction from the controller point of view
+ * @buf: Data buffer
*/
struct anfc_op {
u32 pkt_reg;
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 2da39ab89286..659eaa6f0980 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -1846,7 +1846,7 @@ static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf,
}
}
-/**
+/*
* Kick EDU engine
*/
static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
@@ -1937,7 +1937,7 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
return ret;
}
-/**
+/*
* Construct a FLASH_DMA descriptor as part of a linked list. You must know the
* following ahead of time:
* - Is this descriptor the beginning or end of a linked list?
@@ -1970,7 +1970,7 @@ static int brcmnand_fill_dma_desc(struct brcmnand_host *host,
return 0;
}
-/**
+/*
* Kick the FLASH_DMA engine, with a given DMA descriptor
*/
static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
index 2b94f385a1a8..d0e8ffd55c22 100644
--- a/drivers/mtd/nand/raw/cafe_nand.c
+++ b/drivers/mtd/nand/raw/cafe_nand.c
@@ -359,10 +359,10 @@ static int cafe_nand_read_oob(struct nand_chip *chip, int page)
}
/**
* cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller expects OOB data read to chip->oob_poi
+ * @page: page number to read
*
* The hw generator calculates the error syndrome automatically. Therefore
* we need a special oob layout and handling.
diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c
index 26b265e4384a..5d2ddb037a9a 100644
--- a/drivers/mtd/nand/raw/diskonchip.c
+++ b/drivers/mtd/nand/raw/diskonchip.c
@@ -216,7 +216,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
{
- volatile char dummy;
+ volatile char __always_unused dummy;
int i;
for (i = 0; i < cycles; i++) {
@@ -703,7 +703,7 @@ static int doc200x_calculate_ecc(struct nand_chip *this, const u_char *dat,
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
- int emptymatch = 1;
+ int __always_unused emptymatch = 1;
/* flush the pipeline */
if (DoC_is_2000(doc)) {
diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c
index 4cc47ab7f01a..fbb9955f2467 100644
--- a/drivers/mtd/nand/raw/omap2.c
+++ b/drivers/mtd/nand/raw/omap2.c
@@ -184,6 +184,7 @@ static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
* @dma_mode: dma mode enable (1) or disable (0)
* @u32_count: number of bytes to be transferred
* @is_write: prefetch read(0) or write post(1) mode
+ * @info: NAND device structure containing platform data
*/
static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode,
unsigned int u32_count, int is_write, struct omap_nand_info *info)
@@ -213,7 +214,7 @@ static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode,
return 0;
}
-/**
+/*
* omap_prefetch_reset - disables and stops the prefetch engine
*/
static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
@@ -938,7 +939,7 @@ static int omap_calculate_ecc(struct nand_chip *chip, const u_char *dat,
/**
* omap_enable_hwecc - This function enables the hardware ecc functionality
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @mode: Read/Write mode
*/
static void omap_enable_hwecc(struct nand_chip *chip, int mode)
@@ -1008,7 +1009,7 @@ static int omap_wait(struct nand_chip *this)
/**
* omap_dev_ready - checks the NAND Ready GPIO line
- * @mtd: MTD device structure
+ * @chip: NAND chip object
*
* Returns true if ready and false if busy.
*/
@@ -1021,7 +1022,7 @@ static int omap_dev_ready(struct nand_chip *chip)
/**
* omap_enable_hwecc_bch - Program GPMC to perform BCH ECC calculation
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @mode: Read/Write mode
*
* When using BCH with SW correction (i.e. no ELM), sector size is set
@@ -1130,7 +1131,7 @@ static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
* _omap_calculate_ecc_bch - Generate ECC bytes for one sector
* @mtd: MTD device structure
* @dat: The pointer to data on which ecc is computed
- * @ecc_code: The ecc_code buffer
+ * @ecc_calc: The ecc_code buffer
* @i: The sector number (for a multi sector page)
*
* Support calculating of BCH4/8/16 ECC vectors for one sector
@@ -1258,7 +1259,7 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
* omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction
* @chip: NAND chip object
* @dat: The pointer to data on which ecc is computed
- * @ecc_code: The ecc_code buffer
+ * @ecc_calc: Buffer storing the calculated ECC bytes
*
* Support calculating of BCH4/8/16 ECC vectors for one sector. This is used
* when SW based correction is required as ECC is required for one sector
@@ -1274,7 +1275,7 @@ static int omap_calculate_ecc_bch_sw(struct nand_chip *chip,
* omap_calculate_ecc_bch_multi - Generate ECC for multiple sectors
* @mtd: MTD device structure
* @dat: The pointer to data on which ecc is computed
- * @ecc_code: The ecc_code buffer
+ * @ecc_calc: Buffer storing the calculated ECC bytes
*
* Support calculating of BCH4/8/16 ecc vectors for the entire page in one go.
*/
@@ -1673,7 +1674,8 @@ static int omap_read_page_bch(struct nand_chip *chip, uint8_t *buf,
/**
* is_elm_present - checks for presence of ELM module by scanning DT nodes
- * @omap_nand_info: NAND device structure containing platform data
+ * @info: NAND device structure containing platform data
+ * @elm_node: ELM's DT node
*/
static bool is_elm_present(struct omap_nand_info *info,
struct device_node *elm_node)
diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c
index 4b799521a427..550695a4c1ab 100644
--- a/drivers/mtd/nand/raw/omap_elm.c
+++ b/drivers/mtd/nand/raw/omap_elm.c
@@ -96,6 +96,9 @@ static u32 elm_read_reg(struct elm_info *info, int offset)
* elm_config - Configure ELM module
* @dev: ELM device
* @bch_type: Type of BCH ecc
+ * @ecc_steps: ECC steps to assign to config
+ * @ecc_step_size: ECC step size to assign to config
+ * @ecc_syndrome_size: ECC syndrome size to assign to config
*/
int elm_config(struct device *dev, enum bch_ecc bch_type,
int ecc_steps, int ecc_step_size, int ecc_syndrome_size)
@@ -432,7 +435,7 @@ static int elm_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
-/**
+/*
* elm_context_save
* saves ELM configurations to preserve them across Hardware powered-down
*/
@@ -480,7 +483,7 @@ static int elm_context_save(struct elm_info *info)
return 0;
}
-/**
+/*
* elm_context_restore
* writes configurations saved duing power-down back into ELM registers
*/
diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
index cb2d1b4e278c..f0a4535c812a 100644
--- a/drivers/mtd/nand/raw/s3c2410.c
+++ b/drivers/mtd/nand/raw/s3c2410.c
@@ -133,7 +133,8 @@ enum s3c_nand_clk_state {
/**
* struct s3c2410_nand_info - NAND controller state.
- * @mtds: An array of MTD instances on this controoler.
+ * @controller: Base controller structure.
+ * @mtds: An array of MTD instances on this controller.
* @platform: The platform data for this board.
* @device: The platform device we bound to.
* @clk: The clock resource for this controller.
@@ -145,6 +146,7 @@ enum s3c_nand_clk_state {
* @clk_rate: The clock rate from @clk.
* @clk_state: The current clock state.
* @cpu_type: The exact type of this controller.
+ * @freq_transition: CPUFreq notifier block
*/
struct s3c2410_nand_info {
/* mtd info */
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 1ec672bbd459..923a9e236fcf 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -236,6 +236,7 @@ struct sunxi_nfc_caps {
* controller
* @complete: a completion object used to wait for NAND controller events
* @dmac: the DMA channel attached to the NAND controller
+ * @caps: NAND Controller capabilities
*/
struct sunxi_nfc {
struct nand_controller controller;
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index 21fde2875674..7380b1ebaccd 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -28,7 +28,7 @@ static SPINAND_OP_VARIANTS(update_cache_x4_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
-/**
+/*
* Backward compatibility for 1st generation Serial NAND devices
* which don't support Quad Program Load operation.
*/
diff --git a/drivers/mtd/parsers/cmdlinepart.c b/drivers/mtd/parsers/cmdlinepart.c
index a79e4d866b08..0ddff1a4b51f 100644
--- a/drivers/mtd/parsers/cmdlinepart.c
+++ b/drivers/mtd/parsers/cmdlinepart.c
@@ -226,7 +226,7 @@ static int mtdpart_setup_real(char *s)
struct cmdline_mtd_partition *this_mtd;
struct mtd_partition *parts;
int mtd_id_len, num_parts;
- char *p, *mtd_id, *semicol;
+ char *p, *mtd_id, *semicol, *open_parenth;
/*
* Replace the first ';' by a NULL char so strrchr can work
@@ -236,6 +236,14 @@ static int mtdpart_setup_real(char *s)
if (semicol)
*semicol = '\0';
+ /*
+ * make sure that part-names with ":" will not be handled as
+ * part of the mtd-id with an ":"
+ */
+ open_parenth = strchr(s, '(');
+ if (open_parenth)
+ *open_parenth = '\0';
+
mtd_id = s;
/*
@@ -245,6 +253,10 @@ static int mtdpart_setup_real(char *s)
*/
p = strrchr(s, ':');
+ /* Restore the '(' now. */
+ if (open_parenth)
+ *open_parenth = '(';
+
/* Restore the ';' now. */
if (semicol)
*semicol = ';';
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index ffc4b380f2b1..24cd25de2b8b 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -24,6 +24,50 @@ config MTD_SPI_NOR_USE_4K_SECTORS
Please note that some tools/drivers/filesystems may not work with
4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum).
+choice
+ prompt "Software write protection at boot"
+ default MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE
+
+config MTD_SPI_NOR_SWP_DISABLE
+ bool "Disable SWP on any flashes (legacy behavior)"
+ help
+ This option disables the software write protection on any SPI
+ flashes at boot-up.
+
+ Depending on the flash chip this either clears the block protection
+ bits or does a "Global Unprotect" command.
+
+ Don't use this if you intent to use the software write protection
+ of your SPI flash. This is only to keep backwards compatibility.
+
+config MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE
+ bool "Disable SWP on flashes w/ volatile protection bits"
+ help
+ Some SPI flashes have volatile block protection bits, ie. after a
+ power-up or a reset the flash is software write protected by
+ default.
+
+ This option disables the software write protection for these kind
+ of flashes while keeping it enabled for any other SPI flashes
+ which have non-volatile write protection bits.
+
+ If the software write protection will be disabled depending on
+ the flash either the block protection bits are cleared or a
+ "Global Unprotect" command is issued.
+
+ If you are unsure, select this option.
+
+config MTD_SPI_NOR_SWP_KEEP
+ bool "Keep software write protection as is"
+ help
+ If you select this option the software write protection of any
+ SPI flashes will not be changed. If your flash is software write
+ protected or will be automatically software write protected after
+ power-up you have to manually unlock it before you are able to
+ write to it.
+
+endchoice
+
source "drivers/mtd/spi-nor/controllers/Kconfig"
endif # MTD_SPI_NOR
diff --git a/drivers/mtd/spi-nor/atmel.c b/drivers/mtd/spi-nor/atmel.c
index 3f5f21a473a6..1fea5cab492c 100644
--- a/drivers/mtd/spi-nor/atmel.c
+++ b/drivers/mtd/spi-nor/atmel.c
@@ -8,39 +8,192 @@
#include "core.h"
+#define ATMEL_SR_GLOBAL_PROTECT_MASK GENMASK(5, 2)
+
+/*
+ * The Atmel AT25FS010/AT25FS040 parts have some weird configuration for the
+ * block protection bits. We don't support them. But legacy behavior in linux
+ * is to unlock the whole flash array on startup. Therefore, we have to support
+ * exactly this operation.
+ */
+static int atmel_at25fs_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+ return -EOPNOTSUPP;
+}
+
+static int atmel_at25fs_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+ int ret;
+
+ /* We only support unlocking the whole flash array */
+ if (ofs || len != nor->params->size)
+ return -EINVAL;
+
+ /* Write 0x00 to the status register to disable write protection */
+ ret = spi_nor_write_sr_and_check(nor, 0);
+ if (ret)
+ dev_dbg(nor->dev, "unable to clear BP bits, WP# asserted?\n");
+
+ return ret;
+}
+
+static int atmel_at25fs_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+ return -EOPNOTSUPP;
+}
+
+static const struct spi_nor_locking_ops atmel_at25fs_locking_ops = {
+ .lock = atmel_at25fs_lock,
+ .unlock = atmel_at25fs_unlock,
+ .is_locked = atmel_at25fs_is_locked,
+};
+
+static void atmel_at25fs_default_init(struct spi_nor *nor)
+{
+ nor->params->locking_ops = &atmel_at25fs_locking_ops;
+}
+
+static const struct spi_nor_fixups atmel_at25fs_fixups = {
+ .default_init = atmel_at25fs_default_init,
+};
+
+/**
+ * atmel_set_global_protection - Do a Global Protect or Unprotect command
+ * @nor: pointer to 'struct spi_nor'
+ * @ofs: offset in bytes
+ * @len: len in bytes
+ * @is_protect: if true do a Global Protect otherwise it is a Global Unprotect
+ *
+ * Return: 0 on success, -error otherwise.
+ */
+static int atmel_set_global_protection(struct spi_nor *nor, loff_t ofs,
+ uint64_t len, bool is_protect)
+{
+ int ret;
+ u8 sr;
+
+ /* We only support locking the whole flash array */
+ if (ofs || len != nor->params->size)
+ return -EINVAL;
+
+ ret = spi_nor_read_sr(nor, nor->bouncebuf);
+ if (ret)
+ return ret;
+
+ sr = nor->bouncebuf[0];
+
+ /* SRWD bit needs to be cleared, otherwise the protection doesn't change */
+ if (sr & SR_SRWD) {
+ sr &= ~SR_SRWD;
+ ret = spi_nor_write_sr_and_check(nor, sr);
+ if (ret) {
+ dev_dbg(nor->dev, "unable to clear SRWD bit, WP# asserted?\n");
+ return ret;
+ }
+ }
+
+ if (is_protect) {
+ sr |= ATMEL_SR_GLOBAL_PROTECT_MASK;
+ /*
+ * Set the SRWD bit again as soon as we are protecting
+ * anything. This will ensure that the WP# pin is working
+ * correctly. By doing this we also behave the same as
+ * spi_nor_sr_lock(), which sets SRWD if any block protection
+ * is active.
+ */
+ sr |= SR_SRWD;
+ } else {
+ sr &= ~ATMEL_SR_GLOBAL_PROTECT_MASK;
+ }
+
+ nor->bouncebuf[0] = sr;
+
+ /*
+ * We cannot use the spi_nor_write_sr_and_check() because this command
+ * isn't really setting any bits, instead it is an pseudo command for
+ * "Global Unprotect" or "Global Protect"
+ */
+ return spi_nor_write_sr(nor, nor->bouncebuf, 1);
+}
+
+static int atmel_global_protect(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+ return atmel_set_global_protection(nor, ofs, len, true);
+}
+
+static int atmel_global_unprotect(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+ return atmel_set_global_protection(nor, ofs, len, false);
+}
+
+static int atmel_is_global_protected(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+ int ret;
+
+ if (ofs >= nor->params->size || (ofs + len) > nor->params->size)
+ return -EINVAL;
+
+ ret = spi_nor_read_sr(nor, nor->bouncebuf);
+ if (ret)
+ return ret;
+
+ return ((nor->bouncebuf[0] & ATMEL_SR_GLOBAL_PROTECT_MASK) == ATMEL_SR_GLOBAL_PROTECT_MASK);
+}
+
+static const struct spi_nor_locking_ops atmel_global_protection_ops = {
+ .lock = atmel_global_protect,
+ .unlock = atmel_global_unprotect,
+ .is_locked = atmel_is_global_protected,
+};
+
+static void atmel_global_protection_default_init(struct spi_nor *nor)
+{
+ nor->params->locking_ops = &atmel_global_protection_ops;
+}
+
+static const struct spi_nor_fixups atmel_global_protection_fixups = {
+ .default_init = atmel_global_protection_default_init,
+};
+
static const struct flash_info atmel_parts[] = {
/* Atmel -- some are (confusingly) marketed as "DataFlash" */
- { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) },
- { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) },
+ { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K | SPI_NOR_HAS_LOCK)
+ .fixups = &atmel_at25fs_fixups },
+ { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_HAS_LOCK)
+ .fixups = &atmel_at25fs_fixups },
- { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) },
- { "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
- { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) },
- { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
+ { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8,
+ SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
+ .fixups = &atmel_global_protection_fixups },
+ { "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64,
+ SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
+ .fixups = &atmel_global_protection_fixups },
+ { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64,
+ SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
+ .fixups = &atmel_global_protection_fixups },
+ { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128,
+ SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
+ .fixups = &atmel_global_protection_fixups },
{ "at25sl321", INFO(0x1f4216, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) },
- { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
- { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
- { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
+ { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16,
+ SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
+ .fixups = &atmel_global_protection_fixups },
+ { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32,
+ SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
+ .fixups = &atmel_global_protection_fixups },
+ { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64,
+ SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
+ .fixups = &atmel_global_protection_fixups },
{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
};
-static void atmel_default_init(struct spi_nor *nor)
-{
- nor->flags |= SNOR_F_HAS_LOCK;
-}
-
-static const struct spi_nor_fixups atmel_fixups = {
- .default_init = atmel_default_init,
-};
-
const struct spi_nor_manufacturer spi_nor_atmel = {
.name = "atmel",
.parts = atmel_parts,
.nparts = ARRAY_SIZE(atmel_parts),
- .fixups = &atmel_fixups,
};
diff --git a/drivers/mtd/spi-nor/controllers/hisi-sfc.c b/drivers/mtd/spi-nor/controllers/hisi-sfc.c
index 95c502173cbd..7c26f8f565cb 100644
--- a/drivers/mtd/spi-nor/controllers/hisi-sfc.c
+++ b/drivers/mtd/spi-nor/controllers/hisi-sfc.c
@@ -320,7 +320,7 @@ static const struct spi_nor_controller_ops hisi_controller_ops = {
.write = hisi_spi_nor_write,
};
-/**
+/*
* Get spi flash device information and register it as a mtd device.
*/
static int hisi_spi_nor_register(struct device_node *np,
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index f0ae7a01703a..20df44b753da 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -40,6 +40,81 @@
#define SPI_NOR_MAX_ADDR_WIDTH 4
+#define SPI_NOR_SRST_SLEEP_MIN 200
+#define SPI_NOR_SRST_SLEEP_MAX 400
+
+/**
+ * spi_nor_get_cmd_ext() - Get the command opcode extension based on the
+ * extension type.
+ * @nor: pointer to a 'struct spi_nor'
+ * @op: pointer to the 'struct spi_mem_op' whose properties
+ * need to be initialized.
+ *
+ * Right now, only "repeat" and "invert" are supported.
+ *
+ * Return: The opcode extension.
+ */
+static u8 spi_nor_get_cmd_ext(const struct spi_nor *nor,
+ const struct spi_mem_op *op)
+{
+ switch (nor->cmd_ext_type) {
+ case SPI_NOR_EXT_INVERT:
+ return ~op->cmd.opcode;
+
+ case SPI_NOR_EXT_REPEAT:
+ return op->cmd.opcode;
+
+ default:
+ dev_err(nor->dev, "Unknown command extension type\n");
+ return 0;
+ }
+}
+
+/**
+ * spi_nor_spimem_setup_op() - Set up common properties of a spi-mem op.
+ * @nor: pointer to a 'struct spi_nor'
+ * @op: pointer to the 'struct spi_mem_op' whose properties
+ * need to be initialized.
+ * @proto: the protocol from which the properties need to be set.
+ */
+void spi_nor_spimem_setup_op(const struct spi_nor *nor,
+ struct spi_mem_op *op,
+ const enum spi_nor_protocol proto)
+{
+ u8 ext;
+
+ op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(proto);
+
+ if (op->addr.nbytes)
+ op->addr.buswidth = spi_nor_get_protocol_addr_nbits(proto);
+
+ if (op->dummy.nbytes)
+ op->dummy.buswidth = spi_nor_get_protocol_addr_nbits(proto);
+
+ if (op->data.nbytes)
+ op->data.buswidth = spi_nor_get_protocol_data_nbits(proto);
+
+ if (spi_nor_protocol_is_dtr(proto)) {
+ /*
+ * SPIMEM supports mixed DTR modes, but right now we can only
+ * have all phases either DTR or STR. IOW, SPIMEM can have
+ * something like 4S-4D-4D, but SPI NOR can't. So, set all 4
+ * phases to either DTR or STR.
+ */
+ op->cmd.dtr = true;
+ op->addr.dtr = true;
+ op->dummy.dtr = true;
+ op->data.dtr = true;
+
+ /* 2 bytes per clock cycle in DTR mode. */
+ op->dummy.nbytes *= 2;
+
+ ext = spi_nor_get_cmd_ext(nor, op);
+ op->cmd.opcode = (op->cmd.opcode << 8) | ext;
+ op->cmd.nbytes = 2;
+ }
+}
+
/**
* spi_nor_spimem_bounce() - check if a bounce buffer is needed for the data
* transfer
@@ -82,6 +157,32 @@ static int spi_nor_spimem_exec_op(struct spi_nor *nor, struct spi_mem_op *op)
return spi_mem_exec_op(nor->spimem, op);
}
+static int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode,
+ u8 *buf, size_t len)
+{
+ if (spi_nor_protocol_is_dtr(nor->reg_proto))
+ return -EOPNOTSUPP;
+
+ return nor->controller_ops->read_reg(nor, opcode, buf, len);
+}
+
+static int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode,
+ const u8 *buf, size_t len)
+{
+ if (spi_nor_protocol_is_dtr(nor->reg_proto))
+ return -EOPNOTSUPP;
+
+ return nor->controller_ops->write_reg(nor, opcode, buf, len);
+}
+
+static int spi_nor_controller_ops_erase(struct spi_nor *nor, loff_t offs)
+{
+ if (spi_nor_protocol_is_dtr(nor->write_proto))
+ return -EOPNOTSUPP;
+
+ return nor->controller_ops->erase(nor, offs);
+}
+
/**
* spi_nor_spimem_read_data() - read data from flash's memory region via
* spi-mem
@@ -96,22 +197,20 @@ static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from,
size_t len, u8 *buf)
{
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));
+ SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0),
+ SPI_MEM_OP_ADDR(nor->addr_width, from, 0),
+ SPI_MEM_OP_DUMMY(nor->read_dummy, 0),
+ SPI_MEM_OP_DATA_IN(len, buf, 0));
bool usebouncebuf;
ssize_t nbytes;
int error;
- /* 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);
+ spi_nor_spimem_setup_op(nor, &op, nor->read_proto);
/* convert the dummy cycles to the number of bytes */
op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
+ if (spi_nor_protocol_is_dtr(nor->read_proto))
+ op.dummy.nbytes *= 2;
usebouncebuf = spi_nor_spimem_bounce(nor, &op);
@@ -162,20 +261,18 @@ static ssize_t spi_nor_spimem_write_data(struct spi_nor *nor, loff_t to,
size_t len, const u8 *buf)
{
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(SPI_MEM_OP_CMD(nor->program_opcode, 0),
+ SPI_MEM_OP_ADDR(nor->addr_width, to, 0),
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(len, buf, 1));
+ SPI_MEM_OP_DATA_OUT(len, buf, 0));
ssize_t nbytes;
int error;
- 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;
+ spi_nor_spimem_setup_op(nor, &op, nor->write_proto);
+
if (spi_nor_spimem_bounce(nor, &op))
memcpy(nor->bouncebuf, buf, op.data.nbytes);
@@ -222,15 +319,17 @@ int spi_nor_write_enable(struct spi_nor *nor)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREN, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREN, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_NO_DATA);
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WREN,
- NULL, 0);
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_WREN,
+ NULL, 0);
}
if (ret)
@@ -251,15 +350,17 @@ int spi_nor_write_disable(struct spi_nor *nor)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRDI, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRDI, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_NO_DATA);
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRDI,
- NULL, 0);
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_WRDI,
+ NULL, 0);
}
if (ret)
@@ -272,25 +373,37 @@ int spi_nor_write_disable(struct spi_nor *nor)
* spi_nor_read_sr() - Read the Status Register.
* @nor: pointer to 'struct spi_nor'.
* @sr: pointer to a DMA-able buffer where the value of the
- * Status Register will be written.
+ * Status Register will be written. Should be at least 2 bytes.
*
* Return: 0 on success, -errno otherwise.
*/
-static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
+int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
{
int ret;
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(1, sr, 1));
+ SPI_MEM_OP_DATA_IN(1, sr, 0));
+
+ if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
+ op.addr.nbytes = nor->params->rdsr_addr_nbytes;
+ op.dummy.nbytes = nor->params->rdsr_dummy;
+ /*
+ * We don't want to read only one byte in DTR mode. So,
+ * read 2 and then discard the second byte.
+ */
+ op.data.nbytes = 2;
+ }
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR,
- sr, 1);
+ ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDSR, sr,
+ 1);
}
if (ret)
@@ -303,7 +416,8 @@ static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
* spi_nor_read_fsr() - Read the Flag Status Register.
* @nor: pointer to 'struct spi_nor'
* @fsr: pointer to a DMA-able buffer where the value of the
- * Flag Status Register will be written.
+ * Flag Status Register will be written. Should be at least 2
+ * bytes.
*
* Return: 0 on success, -errno otherwise.
*/
@@ -313,15 +427,27 @@ static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(1, fsr, 1));
+ SPI_MEM_OP_DATA_IN(1, fsr, 0));
+
+ if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
+ op.addr.nbytes = nor->params->rdsr_addr_nbytes;
+ op.dummy.nbytes = nor->params->rdsr_dummy;
+ /*
+ * We don't want to read only one byte in DTR mode. So,
+ * read 2 and then discard the second byte.
+ */
+ op.data.nbytes = 2;
+ }
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDFSR,
- fsr, 1);
+ ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr,
+ 1);
}
if (ret)
@@ -345,14 +471,17 @@ static int spi_nor_read_cr(struct spi_nor *nor, u8 *cr)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDCR, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDCR, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(1, cr, 1));
+ SPI_MEM_OP_DATA_IN(1, cr, 0));
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDCR, cr, 1);
+ ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDCR, cr,
+ 1);
}
if (ret)
@@ -378,17 +507,19 @@ int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
SPI_MEM_OP(SPI_MEM_OP_CMD(enable ?
SPINOR_OP_EN4B :
SPINOR_OP_EX4B,
- 1),
+ 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_NO_DATA);
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->write_reg(nor,
- enable ? SPINOR_OP_EN4B :
- SPINOR_OP_EX4B,
- NULL, 0);
+ ret = spi_nor_controller_ops_write_reg(nor,
+ enable ? SPINOR_OP_EN4B :
+ SPINOR_OP_EX4B,
+ NULL, 0);
}
if (ret)
@@ -414,15 +545,17 @@ static int spansion_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_BRWR, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_BRWR, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1));
+ SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 0));
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->write_reg(nor, SPINOR_OP_BRWR,
- nor->bouncebuf, 1);
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_BRWR,
+ nor->bouncebuf, 1);
}
if (ret)
@@ -446,15 +579,17 @@ int spi_nor_write_ear(struct spi_nor *nor, u8 ear)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREAR, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREAR, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1));
+ SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 0));
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WREAR,
- nor->bouncebuf, 1);
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_WREAR,
+ nor->bouncebuf, 1);
}
if (ret)
@@ -477,15 +612,17 @@ int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_XRDSR, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_XRDSR, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(1, sr, 1));
+ SPI_MEM_OP_DATA_IN(1, sr, 0));
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->read_reg(nor, SPINOR_OP_XRDSR,
- sr, 1);
+ ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_XRDSR, sr,
+ 1);
}
if (ret)
@@ -522,15 +659,17 @@ static void spi_nor_clear_sr(struct spi_nor *nor)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_NO_DATA);
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CLSR,
- NULL, 0);
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR,
+ NULL, 0);
}
if (ret)
@@ -586,15 +725,17 @@ static void spi_nor_clear_fsr(struct spi_nor *nor)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_NO_DATA);
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CLFSR,
- NULL, 0);
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR,
+ NULL, 0);
}
if (ret)
@@ -720,7 +861,7 @@ int spi_nor_wait_till_ready(struct spi_nor *nor)
*
* Return: 0 on success, -errno otherwise.
*/
-static int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len)
+int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len)
{
int ret;
@@ -730,15 +871,17 @@ static int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(len, sr, 1));
+ SPI_MEM_OP_DATA_OUT(len, sr, 0));
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRSR,
- sr, len);
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_WRSR, sr,
+ len);
}
if (ret) {
@@ -906,7 +1049,7 @@ static int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr)
*
* Return: 0 on success, -errno otherwise.
*/
-static int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1)
+int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1)
{
if (nor->flags & SNOR_F_HAS_16BIT_SR)
return spi_nor_write_16bit_sr_and_check(nor, sr1);
@@ -932,15 +1075,17 @@ static int spi_nor_write_sr2(struct spi_nor *nor, const u8 *sr2)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR2, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR2, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(1, sr2, 1));
+ SPI_MEM_OP_DATA_OUT(1, sr2, 0));
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRSR2,
- sr2, 1);
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_WRSR2,
+ sr2, 1);
}
if (ret) {
@@ -966,15 +1111,17 @@ static int spi_nor_read_sr2(struct spi_nor *nor, u8 *sr2)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR2, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR2, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(1, sr2, 1));
+ SPI_MEM_OP_DATA_IN(1, sr2, 0));
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR2,
- sr2, 1);
+ ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDSR2, sr2,
+ 1);
}
if (ret)
@@ -997,15 +1144,18 @@ static int spi_nor_erase_chip(struct spi_nor *nor)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CHIP_ERASE, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CHIP_ERASE, 0),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_NO_DATA);
+ spi_nor_spimem_setup_op(nor, &op, nor->write_proto);
+
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CHIP_ERASE,
- NULL, 0);
+ ret = spi_nor_controller_ops_write_reg(nor,
+ SPINOR_OP_CHIP_ERASE,
+ NULL, 0);
}
if (ret)
@@ -1139,14 +1289,16 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
if (nor->spimem) {
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 1),
- SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
+ SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 0),
+ SPI_MEM_OP_ADDR(nor->addr_width, addr, 0),
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_NO_DATA);
+ spi_nor_spimem_setup_op(nor, &op, nor->write_proto);
+
return spi_mem_exec_op(nor->spimem, &op);
} else if (nor->controller_ops->erase) {
- return nor->controller_ops->erase(nor, addr);
+ return spi_nor_controller_ops_erase(nor, addr);
}
/*
@@ -1158,8 +1310,8 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
addr >>= 8;
}
- return nor->controller_ops->write_reg(nor, nor->erase_opcode,
- nor->bouncebuf, nor->addr_width);
+ return spi_nor_controller_ops_write_reg(nor, nor->erase_opcode,
+ nor->bouncebuf, nor->addr_width);
}
/**
@@ -1447,7 +1599,7 @@ destroy_erase_cmd_list:
/*
* Erase an address range on the nor chip. The address range may extend
- * one or more erase sectors. Return an error is there is a problem erasing.
+ * one or more erase sectors. Return an error if there is a problem erasing.
*/
static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
{
@@ -2204,7 +2356,7 @@ static int spi_nor_check(struct spi_nor *nor)
return 0;
}
-static void
+void
spi_nor_set_read_settings(struct spi_nor_read_command *read,
u8 num_mode_clocks,
u8 num_wait_states,
@@ -2253,6 +2405,7 @@ int spi_nor_hwcaps_read2cmd(u32 hwcaps)
{ 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 },
+ { SNOR_HWCAPS_READ_8_8_8_DTR, SNOR_CMD_READ_8_8_8_DTR },
};
return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd,
@@ -2269,6 +2422,7 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
{ 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 },
+ { SNOR_HWCAPS_PP_8_8_8_DTR, SNOR_CMD_PP_8_8_8_DTR },
};
return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd,
@@ -2281,7 +2435,7 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
*@nor: pointer to a 'struct spi_nor'
*@op: pointer to op template to be checked
*
- * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ * Returns 0 if operation is supported, -EOPNOTSUPP otherwise.
*/
static int spi_nor_spimem_check_op(struct spi_nor *nor,
struct spi_mem_op *op)
@@ -2295,12 +2449,12 @@ static int spi_nor_spimem_check_op(struct spi_nor *nor,
op->addr.nbytes = 4;
if (!spi_mem_supports_op(nor->spimem, op)) {
if (nor->mtd.size > SZ_16M)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
/* If flash size <= 16MB, 3 address bytes are sufficient */
op->addr.nbytes = 3;
if (!spi_mem_supports_op(nor->spimem, op))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
return 0;
@@ -2312,22 +2466,22 @@ static int spi_nor_spimem_check_op(struct spi_nor *nor,
*@nor: pointer to a 'struct spi_nor'
*@read: pointer to op template to be checked
*
- * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ * Returns 0 if operation is supported, -EOPNOTSUPP otherwise.
*/
static int spi_nor_spimem_check_readop(struct spi_nor *nor,
const struct spi_nor_read_command *read)
{
- struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 1),
- SPI_MEM_OP_ADDR(3, 0, 1),
- SPI_MEM_OP_DUMMY(0, 1),
- SPI_MEM_OP_DATA_IN(0, NULL, 1));
+ struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 0),
+ SPI_MEM_OP_ADDR(3, 0, 0),
+ SPI_MEM_OP_DUMMY(1, 0),
+ SPI_MEM_OP_DATA_IN(1, NULL, 0));
- op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(read->proto);
- op.addr.buswidth = spi_nor_get_protocol_addr_nbits(read->proto);
- op.data.buswidth = spi_nor_get_protocol_data_nbits(read->proto);
- op.dummy.buswidth = op.addr.buswidth;
- op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) *
- op.dummy.buswidth / 8;
+ spi_nor_spimem_setup_op(nor, &op, read->proto);
+
+ /* convert the dummy cycles to the number of bytes */
+ op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
+ if (spi_nor_protocol_is_dtr(nor->read_proto))
+ op.dummy.nbytes *= 2;
return spi_nor_spimem_check_op(nor, &op);
}
@@ -2338,19 +2492,17 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor,
*@nor: pointer to a 'struct spi_nor'
*@pp: pointer to op template to be checked
*
- * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ * Returns 0 if operation is supported, -EOPNOTSUPP otherwise.
*/
static int spi_nor_spimem_check_pp(struct spi_nor *nor,
const struct spi_nor_pp_command *pp)
{
- struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 1),
- SPI_MEM_OP_ADDR(3, 0, 1),
+ struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 0),
+ SPI_MEM_OP_ADDR(3, 0, 0),
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(0, NULL, 1));
+ SPI_MEM_OP_DATA_OUT(1, NULL, 0));
- op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(pp->proto);
- op.addr.buswidth = spi_nor_get_protocol_addr_nbits(pp->proto);
- op.data.buswidth = spi_nor_get_protocol_data_nbits(pp->proto);
+ spi_nor_spimem_setup_op(nor, &op, pp->proto);
return spi_nor_spimem_check_op(nor, &op);
}
@@ -2368,12 +2520,16 @@ spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor, u32 *hwcaps)
struct spi_nor_flash_parameter *params = nor->params;
unsigned int cap;
- /* DTR modes are not supported yet, mask them all. */
- *hwcaps &= ~SNOR_HWCAPS_DTR;
-
/* X-X-X modes are not supported yet, mask them all. */
*hwcaps &= ~SNOR_HWCAPS_X_X_X;
+ /*
+ * If the reset line is broken, we do not want to enter a stateful
+ * mode.
+ */
+ if (nor->flags & SNOR_F_BROKEN_RESET)
+ *hwcaps &= ~(SNOR_HWCAPS_X_X_X | SNOR_HWCAPS_X_X_X_DTR);
+
for (cap = 0; cap < sizeof(*hwcaps) * BITS_PER_BYTE; cap++) {
int rdidx, ppidx;
@@ -2537,7 +2693,7 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map,
}
/*
- * Otherwise, the current erase size is still a valid canditate.
+ * Otherwise, the current erase size is still a valid candidate.
* Select the biggest valid candidate.
*/
if (!erase && tested_erase->size)
@@ -2628,7 +2784,7 @@ static int spi_nor_default_setup(struct spi_nor *nor,
* controller directly implements the spi_nor interface.
* Yet another reason to switch to spi-mem.
*/
- ignored_mask = SNOR_HWCAPS_X_X_X;
+ ignored_mask = SNOR_HWCAPS_X_X_X | SNOR_HWCAPS_X_X_X_DTR;
if (shared_mask & ignored_mask) {
dev_dbg(nor->dev,
"SPI n-n-n protocols are not supported.\n");
@@ -2729,6 +2885,7 @@ static void spi_nor_info_init_params(struct spi_nor *nor)
nor->flags |= SNOR_F_HAS_16BIT_SR;
/* Set SPI NOR sizes. */
+ params->writesize = 1;
params->size = (u64)info->sector_size * info->n_sectors;
params->page_size = info->page_size;
@@ -2773,11 +2930,28 @@ static void spi_nor_info_init_params(struct spi_nor *nor)
SNOR_PROTO_1_1_8);
}
+ if (info->flags & SPI_NOR_OCTAL_DTR_READ) {
+ params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
+ spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_8_8_8_DTR],
+ 0, 20, SPINOR_OP_READ_FAST,
+ SNOR_PROTO_8_8_8_DTR);
+ }
+
/* 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);
+ if (info->flags & SPI_NOR_OCTAL_DTR_PP) {
+ params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+ /*
+ * Since xSPI Page Program opcode is backward compatible with
+ * Legacy SPI, use Legacy SPI opcode there as well.
+ */
+ spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
+ SPINOR_OP_PP, SNOR_PROTO_8_8_8_DTR);
+ }
+
/*
* Sector Erase settings. Sort Erase Types in ascending order, with the
* smallest erase size starting at BIT(0).
@@ -2885,7 +3059,8 @@ static int spi_nor_init_params(struct spi_nor *nor)
spi_nor_manufacturer_init_params(nor);
- if ((nor->info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) &&
+ if ((nor->info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+ SPI_NOR_OCTAL_READ | SPI_NOR_OCTAL_DTR_READ)) &&
!(nor->info->flags & SPI_NOR_SKIP_SFDP))
spi_nor_sfdp_init_params(nor);
@@ -2896,6 +3071,38 @@ static int spi_nor_init_params(struct spi_nor *nor)
return 0;
}
+/** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed
+ * @nor: pointer to a 'struct spi_nor'
+ * @enable: whether to enable or disable Octal DTR
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
+{
+ int ret;
+
+ if (!nor->params->octal_dtr_enable)
+ return 0;
+
+ if (!(nor->read_proto == SNOR_PROTO_8_8_8_DTR &&
+ nor->write_proto == SNOR_PROTO_8_8_8_DTR))
+ return 0;
+
+ if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE))
+ return 0;
+
+ ret = nor->params->octal_dtr_enable(nor, enable);
+ if (ret)
+ return ret;
+
+ if (enable)
+ nor->reg_proto = SNOR_PROTO_8_8_8_DTR;
+ else
+ nor->reg_proto = SNOR_PROTO_1_1_1;
+
+ return 0;
+}
+
/**
* spi_nor_quad_enable() - enable Quad I/O if needed.
* @nor: pointer to a 'struct spi_nor'
@@ -2915,39 +3122,65 @@ static int spi_nor_quad_enable(struct spi_nor *nor)
}
/**
- * spi_nor_unlock_all() - Unlocks the entire flash memory array.
+ * spi_nor_try_unlock_all() - Tries to unlock the entire flash memory array.
* @nor: pointer to a 'struct spi_nor'.
*
* Some SPI NOR flashes are write protected by default after a power-on reset
* cycle, in order to avoid inadvertent writes during power-up. Backward
* compatibility imposes to unlock the entire flash memory array at power-up
* by default.
+ *
+ * Unprotecting the entire flash array will fail for boards which are hardware
+ * write-protected. Thus any errors are ignored.
*/
-static int spi_nor_unlock_all(struct spi_nor *nor)
+static void spi_nor_try_unlock_all(struct spi_nor *nor)
{
- if (nor->flags & SNOR_F_HAS_LOCK)
- return spi_nor_unlock(&nor->mtd, 0, nor->params->size);
+ int ret;
- return 0;
+ if (!(nor->flags & SNOR_F_HAS_LOCK))
+ return;
+
+ dev_dbg(nor->dev, "Unprotecting entire flash array\n");
+
+ ret = spi_nor_unlock(&nor->mtd, 0, nor->params->size);
+ if (ret)
+ dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n");
}
static int spi_nor_init(struct spi_nor *nor)
{
int err;
- err = spi_nor_quad_enable(nor);
+ err = spi_nor_octal_dtr_enable(nor, true);
if (err) {
- dev_dbg(nor->dev, "quad mode not supported\n");
+ dev_dbg(nor->dev, "octal mode not supported\n");
return err;
}
- err = spi_nor_unlock_all(nor);
+ err = spi_nor_quad_enable(nor);
if (err) {
- dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n");
+ dev_dbg(nor->dev, "quad mode not supported\n");
return err;
}
- if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES)) {
+ /*
+ * Some SPI NOR flashes are write protected by default after a power-on
+ * reset cycle, in order to avoid inadvertent writes during power-up.
+ * Backward compatibility imposes to unlock the entire flash memory
+ * array at power-up by default. Depending on the kernel configuration
+ * (1) do nothing, (2) always unlock the entire flash array or (3)
+ * unlock the entire flash array only when the software write
+ * protection bits are volatile. The latter is indicated by
+ * SNOR_F_SWP_IS_VOLATILE.
+ */
+ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE) ||
+ (IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE) &&
+ nor->flags & SNOR_F_SWP_IS_VOLATILE))
+ spi_nor_try_unlock_all(nor);
+
+ if (nor->addr_width == 4 &&
+ nor->read_proto != SNOR_PROTO_8_8_8_DTR &&
+ !(nor->flags & SNOR_F_4B_OPCODES)) {
/*
* If the RESET# pin isn't hooked up properly, or the system
* otherwise doesn't perform a reset command in the boot
@@ -2963,6 +3196,59 @@ static int spi_nor_init(struct spi_nor *nor)
return 0;
}
+static void spi_nor_soft_reset(struct spi_nor *nor)
+{
+ struct spi_mem_op op;
+ int ret;
+
+ op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 0),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DATA);
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret) {
+ dev_warn(nor->dev, "Software reset failed: %d\n", ret);
+ return;
+ }
+
+ op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRST, 0),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DATA);
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret) {
+ dev_warn(nor->dev, "Software reset failed: %d\n", ret);
+ return;
+ }
+
+ /*
+ * Software Reset is not instant, and the delay varies from flash to
+ * flash. Looking at a few flashes, most range somewhere below 100
+ * microseconds. So, sleep for a range of 200-400 us.
+ */
+ usleep_range(SPI_NOR_SRST_SLEEP_MIN, SPI_NOR_SRST_SLEEP_MAX);
+}
+
+/* mtd suspend handler */
+static int spi_nor_suspend(struct mtd_info *mtd)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ /* Disable octal DTR mode if we enabled it. */
+ ret = spi_nor_octal_dtr_enable(nor, false);
+ if (ret)
+ dev_err(nor->dev, "suspend() failed\n");
+
+ return ret;
+}
+
/* mtd resume handler */
static void spi_nor_resume(struct mtd_info *mtd)
{
@@ -2982,6 +3268,9 @@ void spi_nor_restore(struct spi_nor *nor)
if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
nor->flags & SNOR_F_BROKEN_RESET)
nor->params->set_4byte_addr_mode(nor, false);
+
+ if (nor->flags & SNOR_F_SOFT_RESET)
+ spi_nor_soft_reset(nor);
}
EXPORT_SYMBOL_GPL(spi_nor_restore);
@@ -3006,6 +3295,20 @@ static int spi_nor_set_addr_width(struct spi_nor *nor)
{
if (nor->addr_width) {
/* already configured from SFDP */
+ } else if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) {
+ /*
+ * In 8D-8D-8D mode, one byte takes half a cycle to transfer. So
+ * in this protocol an odd address width cannot be used because
+ * then the address phase would only span a cycle and a half.
+ * Half a cycle would be left over. We would then have to start
+ * the dummy phase in the middle of a cycle and so too the data
+ * phase, and we will end the transaction with half a cycle left
+ * over.
+ *
+ * Force all 8D-8D-8D flashes to use an address width of 4 to
+ * avoid this situation.
+ */
+ nor->addr_width = 4;
} else if (nor->info->addr_width) {
nor->addr_width = nor->info->addr_width;
} else {
@@ -3146,11 +3449,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
mtd->name = dev_name(dev);
mtd->priv = nor;
mtd->type = MTD_NORFLASH;
- mtd->writesize = 1;
+ mtd->writesize = nor->params->writesize;
mtd->flags = MTD_CAP_NORFLASH;
mtd->size = nor->params->size;
mtd->_erase = spi_nor_erase;
mtd->_read = spi_nor_read;
+ mtd->_suspend = spi_nor_suspend;
mtd->_resume = spi_nor_resume;
if (nor->params->locking_ops) {
@@ -3171,6 +3475,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
if (info->flags & USE_CLSR)
nor->flags |= SNOR_F_USE_CLSR;
+ if (info->flags & SPI_NOR_SWP_IS_VOLATILE)
+ nor->flags |= SNOR_F_SWP_IS_VOLATILE;
if (info->flags & SPI_NOR_4BIT_BP) {
nor->flags |= SNOR_F_HAS_4BIT_BP;
@@ -3201,6 +3507,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (info->flags & SPI_NOR_4B_OPCODES)
nor->flags |= SNOR_F_4B_OPCODES;
+ if (info->flags & SPI_NOR_IO_MODE_EN_VOLATILE)
+ nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
+
ret = spi_nor_set_addr_width(nor);
if (ret)
return ret;
@@ -3236,23 +3545,28 @@ EXPORT_SYMBOL_GPL(spi_nor_scan);
static int spi_nor_create_read_dirmap(struct spi_nor *nor)
{
struct spi_mem_dirmap_info info = {
- .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
- SPI_MEM_OP_ADDR(nor->addr_width, 0, 1),
- SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
- SPI_MEM_OP_DATA_IN(0, NULL, 1)),
+ .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0),
+ SPI_MEM_OP_ADDR(nor->addr_width, 0, 0),
+ SPI_MEM_OP_DUMMY(nor->read_dummy, 0),
+ SPI_MEM_OP_DATA_IN(0, NULL, 0)),
.offset = 0,
.length = nor->mtd.size,
};
struct spi_mem_op *op = &info.op_tmpl;
- /* 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);
+ spi_nor_spimem_setup_op(nor, op, nor->read_proto);
/* convert the dummy cycles to the number of bytes */
op->dummy.nbytes = (nor->read_dummy * op->dummy.buswidth) / 8;
+ if (spi_nor_protocol_is_dtr(nor->read_proto))
+ op->dummy.nbytes *= 2;
+
+ /*
+ * Since spi_nor_spimem_setup_op() only sets buswidth when the number
+ * of data bytes is non-zero, the data buswidth won't be set here. So,
+ * do it explicitly.
+ */
+ op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
nor->dirmap.rdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem,
&info);
@@ -3262,24 +3576,27 @@ static int spi_nor_create_read_dirmap(struct spi_nor *nor)
static int spi_nor_create_write_dirmap(struct spi_nor *nor)
{
struct spi_mem_dirmap_info info = {
- .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
- SPI_MEM_OP_ADDR(nor->addr_width, 0, 1),
+ .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0),
+ SPI_MEM_OP_ADDR(nor->addr_width, 0, 0),
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(0, NULL, 1)),
+ SPI_MEM_OP_DATA_OUT(0, NULL, 0)),
.offset = 0,
.length = nor->mtd.size,
};
struct spi_mem_op *op = &info.op_tmpl;
- /* 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->dummy.buswidth = op->addr.buswidth;
- 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;
+ spi_nor_spimem_setup_op(nor, op, nor->write_proto);
+
+ /*
+ * Since spi_nor_spimem_setup_op() only sets buswidth when the number
+ * of data bytes is non-zero, the data buswidth won't be set here. So,
+ * do it explicitly.
+ */
+ op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
+
nor->dirmap.wdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem,
&info);
return PTR_ERR_OR_ZERO(nor->dirmap.wdesc);
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 6f2f6b27173f..d631ee299de3 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -26,6 +26,9 @@ enum spi_nor_option_flags {
SNOR_F_HAS_SR_TB_BIT6 = BIT(11),
SNOR_F_HAS_4BIT_BP = BIT(12),
SNOR_F_HAS_SR_BP3_BIT6 = BIT(13),
+ SNOR_F_IO_MODE_EN_VOLATILE = BIT(14),
+ SNOR_F_SOFT_RESET = BIT(15),
+ SNOR_F_SWP_IS_VOLATILE = BIT(16),
};
struct spi_nor_read_command {
@@ -62,6 +65,7 @@ enum spi_nor_read_command_index {
SNOR_CMD_READ_1_8_8,
SNOR_CMD_READ_8_8_8,
SNOR_CMD_READ_1_8_8_DTR,
+ SNOR_CMD_READ_8_8_8_DTR,
SNOR_CMD_READ_MAX
};
@@ -78,6 +82,7 @@ enum spi_nor_pp_command_index {
SNOR_CMD_PP_1_1_8,
SNOR_CMD_PP_1_8_8,
SNOR_CMD_PP_8_8_8,
+ SNOR_CMD_PP_8_8_8_DTR,
SNOR_CMD_PP_MAX
};
@@ -189,7 +194,12 @@ struct spi_nor_locking_ops {
* Serial Flash Discoverable Parameters (SFDP) tables.
*
* @size: the flash memory density in bytes.
+ * @writesize Minimal writable flash unit size. Defaults to 1. Set to
+ * ECC unit size for ECC-ed flashes.
* @page_size: the page size of the SPI NOR flash memory.
+ * @rdsr_dummy: dummy cycles needed for Read Status Register command.
+ * @rdsr_addr_nbytes: dummy address bytes needed for Read Status Register
+ * command.
* @hwcaps: describes the read and page program hardware
* capabilities.
* @reads: read capabilities ordered by priority: the higher index
@@ -198,6 +208,7 @@ struct spi_nor_locking_ops {
* higher index in the array, the higher priority.
* @erase_map: the erase map parsed from the SFDP Sector Map Parameter
* Table.
+ * @octal_dtr_enable: enables SPI NOR octal DTR mode.
* @quad_enable: enables SPI NOR quad mode.
* @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode.
* @convert_addr: converts an absolute address into something the flash
@@ -211,7 +222,10 @@ struct spi_nor_locking_ops {
*/
struct spi_nor_flash_parameter {
u64 size;
+ u32 writesize;
u32 page_size;
+ u8 rdsr_dummy;
+ u8 rdsr_addr_nbytes;
struct spi_nor_hwcaps hwcaps;
struct spi_nor_read_command reads[SNOR_CMD_READ_MAX];
@@ -219,6 +233,7 @@ struct spi_nor_flash_parameter {
struct spi_nor_erase_map erase_map;
+ int (*octal_dtr_enable)(struct spi_nor *nor, bool enable);
int (*quad_enable)(struct spi_nor *nor);
int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable);
u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
@@ -311,6 +326,18 @@ struct flash_info {
* BP3 is bit 6 of status register.
* Must be used with SPI_NOR_4BIT_BP.
*/
+#define SPI_NOR_OCTAL_DTR_READ BIT(19) /* Flash supports octal DTR Read. */
+#define SPI_NOR_OCTAL_DTR_PP BIT(20) /* Flash supports Octal DTR Page Program */
+#define SPI_NOR_IO_MODE_EN_VOLATILE BIT(21) /*
+ * Flash enables the best
+ * available I/O mode via a
+ * volatile bit.
+ */
+#define SPI_NOR_SWP_IS_VOLATILE BIT(22) /*
+ * Flash has volatile software write
+ * protection bits. Usually these will
+ * power-up in a write-protected state.
+ */
/* Part specific fixup hooks. */
const struct spi_nor_fixups *fixups;
@@ -399,6 +426,9 @@ extern const struct spi_nor_manufacturer spi_nor_winbond;
extern const struct spi_nor_manufacturer spi_nor_xilinx;
extern const struct spi_nor_manufacturer spi_nor_xmc;
+void spi_nor_spimem_setup_op(const struct spi_nor *nor,
+ struct spi_mem_op *op,
+ const enum spi_nor_protocol proto);
int spi_nor_write_enable(struct spi_nor *nor);
int spi_nor_write_disable(struct spi_nor *nor);
int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable);
@@ -409,6 +439,9 @@ void spi_nor_unlock_and_unprep(struct spi_nor *nor);
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor);
+int spi_nor_read_sr(struct spi_nor *nor, u8 *sr);
+int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len);
+int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr);
ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
@@ -418,6 +451,11 @@ ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
int spi_nor_hwcaps_read2cmd(u32 hwcaps);
u8 spi_nor_convert_3to4_read(u8 opcode);
+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);
void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode,
enum spi_nor_protocol proto);
diff --git a/drivers/mtd/spi-nor/esmt.c b/drivers/mtd/spi-nor/esmt.c
index c93170008118..cfc9218c1053 100644
--- a/drivers/mtd/spi-nor/esmt.c
+++ b/drivers/mtd/spi-nor/esmt.c
@@ -11,7 +11,7 @@
static const struct flash_info esmt_parts[] = {
/* ESMT */
{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64,
- SECT_4K | SPI_NOR_HAS_LOCK) },
+ SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
{ "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_HAS_LOCK) },
{ "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128,
diff --git a/drivers/mtd/spi-nor/intel.c b/drivers/mtd/spi-nor/intel.c
index d8196f101368..8ece9cceb3cf 100644
--- a/drivers/mtd/spi-nor/intel.c
+++ b/drivers/mtd/spi-nor/intel.c
@@ -10,23 +10,16 @@
static const struct flash_info intel_parts[] = {
/* Intel/Numonyx -- xxxs33b */
- { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
- { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) },
- { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) },
-};
-
-static void intel_default_init(struct spi_nor *nor)
-{
- nor->flags |= SNOR_F_HAS_LOCK;
-}
-
-static const struct spi_nor_fixups intel_fixups = {
- .default_init = intel_default_init,
+ { "160s33b", INFO(0x898911, 0, 64 * 1024, 32,
+ SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
+ { "320s33b", INFO(0x898912, 0, 64 * 1024, 64,
+ SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
+ { "640s33b", INFO(0x898913, 0, 64 * 1024, 128,
+ SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
};
const struct spi_nor_manufacturer spi_nor_intel = {
.name = "intel",
.parts = intel_parts,
.nparts = ARRAY_SIZE(intel_parts),
- .fixups = &intel_fixups,
};
diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c
index ef3695080710..c224e59820a1 100644
--- a/drivers/mtd/spi-nor/micron-st.c
+++ b/drivers/mtd/spi-nor/micron-st.c
@@ -8,10 +8,123 @@
#include "core.h"
+#define SPINOR_OP_MT_DTR_RD 0xfd /* Fast Read opcode in DTR mode */
+#define SPINOR_OP_MT_RD_ANY_REG 0x85 /* Read volatile register */
+#define SPINOR_OP_MT_WR_ANY_REG 0x81 /* Write volatile register */
+#define SPINOR_REG_MT_CFR0V 0x00 /* For setting octal DTR mode */
+#define SPINOR_REG_MT_CFR1V 0x01 /* For setting dummy cycles */
+#define SPINOR_MT_OCT_DTR 0xe7 /* Enable Octal DTR. */
+#define SPINOR_MT_EXSPI 0xff /* Enable Extended SPI (default) */
+
+static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor, bool enable)
+{
+ struct spi_mem_op op;
+ u8 *buf = nor->bouncebuf;
+ int ret;
+
+ if (enable) {
+ /* Use 20 dummy cycles for memory array reads. */
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ *buf = 20;
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1),
+ SPI_MEM_OP_ADDR(3, SPINOR_REG_MT_CFR1V, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(1, buf, 1));
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ return ret;
+ }
+
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ if (enable)
+ *buf = SPINOR_MT_OCT_DTR;
+ else
+ *buf = SPINOR_MT_EXSPI;
+
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1),
+ SPI_MEM_OP_ADDR(enable ? 3 : 4,
+ SPINOR_REG_MT_CFR0V, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(1, buf, 1));
+
+ if (!enable)
+ spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ /* Read flash ID to make sure the switch was successful. */
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 1),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_DUMMY(enable ? 8 : 0, 1),
+ SPI_MEM_OP_DATA_IN(round_up(nor->info->id_len, 2),
+ buf, 1));
+
+ if (enable)
+ spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ if (memcmp(buf, nor->info->id, nor->info->id_len))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void mt35xu512aba_default_init(struct spi_nor *nor)
+{
+ nor->params->octal_dtr_enable = spi_nor_micron_octal_dtr_enable;
+}
+
+static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
+{
+ /* Set the Fast Read settings. */
+ nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
+ spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR],
+ 0, 20, SPINOR_OP_MT_DTR_RD,
+ SNOR_PROTO_8_8_8_DTR);
+
+ nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+ nor->params->rdsr_dummy = 8;
+ nor->params->rdsr_addr_nbytes = 0;
+
+ /*
+ * The BFPT quad enable field is set to a reserved value so the quad
+ * enable function is ignored by spi_nor_parse_bfpt(). Make sure we
+ * disable it.
+ */
+ nor->params->quad_enable = NULL;
+}
+
+static struct spi_nor_fixups mt35xu512aba_fixups = {
+ .default_init = mt35xu512aba_default_init,
+ .post_sfdp = mt35xu512aba_post_sfdp_fixup,
+};
+
static const struct flash_info micron_parts[] = {
{ "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512,
SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ |
- SPI_NOR_4B_OPCODES) },
+ SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP |
+ SPI_NOR_IO_MODE_EN_VOLATILE)
+ .fixups = &mt35xu512aba_fixups},
{ "mt35xu02g", INFO(0x2c5b1c, 0, 128 * 1024, 2048,
SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ |
SPI_NOR_4B_OPCODES) },
diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c
index e2a43d39eb5f..6ee7719e5903 100644
--- a/drivers/mtd/spi-nor/sfdp.c
+++ b/drivers/mtd/spi-nor/sfdp.c
@@ -4,6 +4,7 @@
* Copyright (C) 2014, Freescale Semiconductor, Inc.
*/
+#include <linux/bitfield.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/mtd/spi-nor.h>
@@ -19,6 +20,11 @@
#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */
#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */
#define SFDP_4BAIT_ID 0xff84 /* 4-byte Address Instruction Table */
+#define SFDP_PROFILE1_ID 0xff05 /* xSPI Profile 1.0 table. */
+#define SFDP_SCCR_MAP_ID 0xff87 /*
+ * Status, Control and Configuration
+ * Register Map.
+ */
#define SFDP_SIGNATURE 0x50444653U
@@ -59,7 +65,7 @@ struct sfdp_bfpt_read {
struct sfdp_bfpt_erase {
/*
- * The half-word at offset <shift> in DWORD <dwoard> encodes the
+ * The half-word at offset <shift> in DWORD <dword> encodes the
* op code and erase sector size to be used by Sector Erase commands.
*/
u32 dword;
@@ -602,10 +608,32 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
break;
}
+ /* Soft Reset support. */
+ if (bfpt.dwords[BFPT_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST)
+ nor->flags |= SNOR_F_SOFT_RESET;
+
/* Stop here if not JESD216 rev C or later. */
if (bfpt_header->length == BFPT_DWORD_MAX_JESD216B)
return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt,
params);
+ /* 8D-8D-8D command extension. */
+ switch (bfpt.dwords[BFPT_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) {
+ case BFPT_DWORD18_CMD_EXT_REP:
+ nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+ break;
+
+ case BFPT_DWORD18_CMD_EXT_INV:
+ nor->cmd_ext_type = SPI_NOR_EXT_INVERT;
+ break;
+
+ case BFPT_DWORD18_CMD_EXT_RES:
+ dev_dbg(nor->dev, "Reserved command extension used\n");
+ break;
+
+ case BFPT_DWORD18_CMD_EXT_16B:
+ dev_dbg(nor->dev, "16-bit opcodes not supported\n");
+ return -EOPNOTSUPP;
+ }
return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params);
}
@@ -1047,9 +1075,16 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,
}
/* 4BAIT is the only SFDP table that indicates page program support. */
- if (pp_hwcaps & SNOR_HWCAPS_PP)
+ if (pp_hwcaps & SNOR_HWCAPS_PP) {
spi_nor_set_pp_settings(&params_pp[SNOR_CMD_PP],
SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
+ /*
+ * Since xSPI Page Program opcode is backward compatible with
+ * Legacy SPI, use Legacy SPI opcode there as well.
+ */
+ spi_nor_set_pp_settings(&params_pp[SNOR_CMD_PP_8_8_8_DTR],
+ SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
+ }
if (pp_hwcaps & SNOR_HWCAPS_PP_1_1_4)
spi_nor_set_pp_settings(&params_pp[SNOR_CMD_PP_1_1_4],
SPINOR_OP_PP_1_1_4_4B,
@@ -1083,6 +1118,131 @@ out:
return ret;
}
+#define PROFILE1_DWORD1_RDSR_ADDR_BYTES BIT(29)
+#define PROFILE1_DWORD1_RDSR_DUMMY BIT(28)
+#define PROFILE1_DWORD1_RD_FAST_CMD GENMASK(15, 8)
+#define PROFILE1_DWORD4_DUMMY_200MHZ GENMASK(11, 7)
+#define PROFILE1_DWORD5_DUMMY_166MHZ GENMASK(31, 27)
+#define PROFILE1_DWORD5_DUMMY_133MHZ GENMASK(21, 17)
+#define PROFILE1_DWORD5_DUMMY_100MHZ GENMASK(11, 7)
+
+/**
+ * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table
+ * @nor: pointer to a 'struct spi_nor'
+ * @profile1_header: pointer to the 'struct sfdp_parameter_header' describing
+ * the Profile 1.0 Table length and version.
+ * @params: pointer to the 'struct spi_nor_flash_parameter' to be.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_profile1(struct spi_nor *nor,
+ const struct sfdp_parameter_header *profile1_header,
+ struct spi_nor_flash_parameter *params)
+{
+ u32 *dwords, addr;
+ size_t len;
+ int ret;
+ u8 dummy, opcode;
+
+ len = profile1_header->length * sizeof(*dwords);
+ dwords = kmalloc(len, GFP_KERNEL);
+ if (!dwords)
+ return -ENOMEM;
+
+ addr = SFDP_PARAM_HEADER_PTP(profile1_header);
+ ret = spi_nor_read_sfdp(nor, addr, len, dwords);
+ if (ret)
+ goto out;
+
+ le32_to_cpu_array(dwords, profile1_header->length);
+
+ /* Get 8D-8D-8D fast read opcode and dummy cycles. */
+ opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, dwords[0]);
+
+ /* Set the Read Status Register dummy cycles and dummy address bytes. */
+ if (dwords[0] & PROFILE1_DWORD1_RDSR_DUMMY)
+ params->rdsr_dummy = 8;
+ else
+ params->rdsr_dummy = 4;
+
+ if (dwords[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES)
+ params->rdsr_addr_nbytes = 4;
+ else
+ params->rdsr_addr_nbytes = 0;
+
+ /*
+ * We don't know what speed the controller is running at. Find the
+ * dummy cycles for the fastest frequency the flash can run at to be
+ * sure we are never short of dummy cycles. A value of 0 means the
+ * frequency is not supported.
+ *
+ * Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let
+ * flashes set the correct value if needed in their fixup hooks.
+ */
+ dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, dwords[3]);
+ if (!dummy)
+ dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ, dwords[4]);
+ if (!dummy)
+ dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ, dwords[4]);
+ if (!dummy)
+ dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ, dwords[4]);
+ if (!dummy)
+ dev_dbg(nor->dev,
+ "Can't find dummy cycles from Profile 1.0 table\n");
+
+ /* Round up to an even value to avoid tripping controllers up. */
+ dummy = round_up(dummy, 2);
+
+ /* Update the fast read settings. */
+ spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_8_8_8_DTR],
+ 0, dummy, opcode,
+ SNOR_PROTO_8_8_8_DTR);
+
+out:
+ kfree(dwords);
+ return ret;
+}
+
+#define SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE BIT(31)
+
+/**
+ * spi_nor_parse_sccr() - Parse the Status, Control and Configuration Register
+ * Map.
+ * @nor: pointer to a 'struct spi_nor'
+ * @sccr_header: pointer to the 'struct sfdp_parameter_header' describing
+ * the SCCR Map table length and version.
+ * @params: pointer to the 'struct spi_nor_flash_parameter' to be.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_sccr(struct spi_nor *nor,
+ const struct sfdp_parameter_header *sccr_header,
+ struct spi_nor_flash_parameter *params)
+{
+ u32 *dwords, addr;
+ size_t len;
+ int ret;
+
+ len = sccr_header->length * sizeof(*dwords);
+ dwords = kmalloc(len, GFP_KERNEL);
+ if (!dwords)
+ return -ENOMEM;
+
+ addr = SFDP_PARAM_HEADER_PTP(sccr_header);
+ ret = spi_nor_read_sfdp(nor, addr, len, dwords);
+ if (ret)
+ goto out;
+
+ le32_to_cpu_array(dwords, sccr_header->length);
+
+ if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, dwords[22]))
+ nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
+
+out:
+ kfree(dwords);
+ return ret;
+}
+
/**
* spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
* @nor: pointer to a 'struct spi_nor'
@@ -1184,6 +1344,14 @@ int spi_nor_parse_sfdp(struct spi_nor *nor,
err = spi_nor_parse_4bait(nor, param_header, params);
break;
+ case SFDP_PROFILE1_ID:
+ err = spi_nor_parse_profile1(nor, param_header, params);
+ break;
+
+ case SFDP_SCCR_MAP_ID:
+ err = spi_nor_parse_sccr(nor, param_header, params);
+ break;
+
default:
break;
}
diff --git a/drivers/mtd/spi-nor/sfdp.h b/drivers/mtd/spi-nor/sfdp.h
index 7f9846b3a1ad..89152ae1cf3e 100644
--- a/drivers/mtd/spi-nor/sfdp.h
+++ b/drivers/mtd/spi-nor/sfdp.h
@@ -90,6 +90,14 @@ struct sfdp_bfpt {
#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20)
#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */
+#define BFPT_DWORD16_SWRST_EN_RST BIT(12)
+
+#define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29)
+#define BFPT_DWORD18_CMD_EXT_REP (0x0UL << 29) /* Repeat */
+#define BFPT_DWORD18_CMD_EXT_INV (0x1UL << 29) /* Invert */
+#define BFPT_DWORD18_CMD_EXT_RES (0x2UL << 29) /* Reserved */
+#define BFPT_DWORD18_CMD_EXT_16B (0x3UL << 29) /* 16-bit opcode */
+
struct sfdp_parameter_header {
u8 id_lsb;
u8 minor;
diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
index 8429b4af999a..b0c5521c1e27 100644
--- a/drivers/mtd/spi-nor/spansion.c
+++ b/drivers/mtd/spi-nor/spansion.c
@@ -8,6 +8,173 @@
#include "core.h"
+#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
+#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
+#define SPINOR_REG_CYPRESS_CFR2V 0x00800003
+#define SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24 0xb
+#define SPINOR_REG_CYPRESS_CFR3V 0x00800004
+#define SPINOR_REG_CYPRESS_CFR3V_PGSZ BIT(4) /* Page size. */
+#define SPINOR_REG_CYPRESS_CFR5V 0x00800006
+#define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN 0x3
+#define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS 0
+#define SPINOR_OP_CYPRESS_RD_FAST 0xee
+
+/**
+ * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
+ * @nor: pointer to a 'struct spi_nor'
+ * @enable: whether to enable or disable Octal DTR
+ *
+ * This also sets the memory access latency cycles to 24 to allow the flash to
+ * run at up to 200MHz.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor, bool enable)
+{
+ struct spi_mem_op op;
+ u8 *buf = nor->bouncebuf;
+ int ret;
+
+ if (enable) {
+ /* Use 24 dummy cycles for memory array reads. */
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24;
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1),
+ SPI_MEM_OP_ADDR(3, SPINOR_REG_CYPRESS_CFR2V,
+ 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(1, buf, 1));
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ return ret;
+
+ nor->read_dummy = 24;
+ }
+
+ /* Set/unset the octal and DTR enable bits. */
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ if (enable)
+ *buf = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN;
+ else
+ *buf = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS;
+
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1),
+ SPI_MEM_OP_ADDR(enable ? 3 : 4,
+ SPINOR_REG_CYPRESS_CFR5V,
+ 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(1, buf, 1));
+
+ if (!enable)
+ spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ /* Read flash ID to make sure the switch was successful. */
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 1),
+ SPI_MEM_OP_ADDR(enable ? 4 : 0, 0, 1),
+ SPI_MEM_OP_DUMMY(enable ? 3 : 0, 1),
+ SPI_MEM_OP_DATA_IN(round_up(nor->info->id_len, 2),
+ buf, 1));
+
+ if (enable)
+ spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ if (memcmp(buf, nor->info->id, nor->info->id_len))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void s28hs512t_default_init(struct spi_nor *nor)
+{
+ nor->params->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable;
+ nor->params->writesize = 16;
+}
+
+static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor)
+{
+ /*
+ * On older versions of the flash the xSPI Profile 1.0 table has the
+ * 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE.
+ */
+ if (nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
+ nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
+ SPINOR_OP_CYPRESS_RD_FAST;
+
+ /* This flash is also missing the 4-byte Page Program opcode bit. */
+ spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP],
+ SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
+ /*
+ * Since xSPI Page Program opcode is backward compatible with
+ * Legacy SPI, use Legacy SPI opcode there as well.
+ */
+ spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
+ SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
+
+ /*
+ * The xSPI Profile 1.0 table advertises the number of additional
+ * address bytes needed for Read Status Register command as 0 but the
+ * actual value for that is 4.
+ */
+ nor->params->rdsr_addr_nbytes = 4;
+}
+
+static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor,
+ const struct sfdp_parameter_header *bfpt_header,
+ const struct sfdp_bfpt *bfpt,
+ struct spi_nor_flash_parameter *params)
+{
+ /*
+ * The BFPT table advertises a 512B page size but the page size is
+ * actually configurable (with the default being 256B). Read from
+ * CFR3V[4] and set the correct size.
+ */
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 1),
+ SPI_MEM_OP_ADDR(3, SPINOR_REG_CYPRESS_CFR3V, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1));
+ int ret;
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3V_PGSZ)
+ params->page_size = 512;
+ else
+ params->page_size = 256;
+
+ return 0;
+}
+
+static struct spi_nor_fixups s28hs512t_fixups = {
+ .default_init = s28hs512t_default_init,
+ .post_sfdp = s28hs512t_post_sfdp_fixup,
+ .post_bfpt = s28hs512t_post_bfpt_fixup,
+};
+
static int
s25fs_s_post_bfpt_fixups(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
@@ -104,6 +271,11 @@ static const struct flash_info spansion_parts[] = {
SPI_NOR_4B_OPCODES) },
{ "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1,
SPI_NOR_NO_ERASE) },
+ { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP)
+ .fixups = &s28hs512t_fixups,
+ },
};
static void spansion_post_sfdp_fixups(struct spi_nor *nor)
diff --git a/drivers/mtd/spi-nor/sst.c b/drivers/mtd/spi-nor/sst.c
index e0af6d25d573..00e48da0744a 100644
--- a/drivers/mtd/spi-nor/sst.c
+++ b/drivers/mtd/spi-nor/sst.c
@@ -11,26 +11,28 @@
static const struct flash_info sst_parts[] = {
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8,
- SECT_4K | SST_WRITE) },
+ SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
{ "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16,
- SECT_4K | SST_WRITE) },
+ SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
{ "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32,
- SECT_4K | SST_WRITE) },
+ SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
{ "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64,
- SECT_4K | SST_WRITE) },
- { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) },
+ SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
+ { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128,
+ SECT_4K | SPI_NOR_4BIT_BP | SPI_NOR_HAS_LOCK |
+ SPI_NOR_SWP_IS_VOLATILE) },
{ "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1,
- SECT_4K | SST_WRITE) },
+ SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
{ "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2,
- SECT_4K | SST_WRITE) },
+ SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
{ "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4,
- SECT_4K | SST_WRITE) },
- { "sst25wf020a", INFO(0x621612, 0, 64 * 1024, 4, SECT_4K) },
- { "sst25wf040b", INFO(0x621613, 0, 64 * 1024, 8, SECT_4K) },
+ SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
+ { "sst25wf020a", INFO(0x621612, 0, 64 * 1024, 4, SECT_4K | SPI_NOR_HAS_LOCK) },
+ { "sst25wf040b", INFO(0x621613, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_HAS_LOCK) },
{ "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8,
- SECT_4K | SST_WRITE) },
+ SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
{ "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16,
- SECT_4K | SST_WRITE) },
+ SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
{ "sst26wf016b", INFO(0xbf2651, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) },
@@ -127,11 +129,6 @@ out:
return ret;
}
-static void sst_default_init(struct spi_nor *nor)
-{
- nor->flags |= SNOR_F_HAS_LOCK;
-}
-
static void sst_post_sfdp_fixups(struct spi_nor *nor)
{
if (nor->info->flags & SST_WRITE)
@@ -139,7 +136,6 @@ static void sst_post_sfdp_fixups(struct spi_nor *nor)
}
static const struct spi_nor_fixups sst_fixups = {
- .default_init = sst_default_init,
.post_sfdp = sst_post_sfdp_fixups,
};
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index e85b04e9716b..40fa994ad6a8 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -50,6 +50,7 @@
* struct mtd_dev_param - MTD device parameter description data structure.
* @name: MTD character device node path, MTD device name, or MTD device number
* string
+ * @ubi_num: UBI number
* @vid_hdr_offs: VID header offset
* @max_beb_per1024: maximum expected number of bad PEBs per 1024 PEBs
*/
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 0edecfdbd01f..892494c8cb7c 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -1290,7 +1290,7 @@ static int is_error_sane(int err)
* @ubi: UBI device description object
* @from: physical eraseblock number from where to copy
* @to: physical eraseblock number where to copy
- * @vid_hdr: VID header of the @from physical eraseblock
+ * @vidb: data structure from where the VID header is derived
*
* This function copies logical eraseblock from physical eraseblock @from to
* physical eraseblock @to. The @vid_hdr buffer may be changed by this
@@ -1463,6 +1463,7 @@ out_unlock_leb:
/**
* print_rsvd_warning - warn about not having enough reserved PEBs.
* @ubi: UBI device description object
+ * @ai: UBI attach info object
*
* This is a helper function for 'ubi_eba_init()' which is called when UBI
* cannot reserve enough PEBs for bad block handling. This function makes a
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index cc547b37cace..1b980d15d9fb 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -439,7 +439,7 @@ static int gluebi_resized(struct ubi_volume_info *vi)
* gluebi_notify - UBI notification handler.
* @nb: registered notifier block
* @l: notification type
- * @ptr: pointer to the &struct ubi_notification object
+ * @ns_ptr: pointer to the &struct ubi_notification object
*/
static int gluebi_notify(struct notifier_block *nb, unsigned long l,
void *ns_ptr)
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 9718f5aaaf69..0fce99ff29b5 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -450,7 +450,7 @@ EXPORT_SYMBOL_GPL(ubi_leb_read);
* ubi_leb_read_sg - read data into a scatter gather list.
* @desc: volume descriptor
* @lnum: logical eraseblock number to read from
- * @buf: buffer where to store the read data
+ * @sgl: UBI scatter gather list to store the read data
* @offset: offset within the logical eraseblock to read from
* @len: how many bytes to read
* @check: whether UBI has to check the read data's CRC or not.
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 7847de75a74c..8455f1d47f3c 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -575,6 +575,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
* @vol_id: the volume ID that last used this PEB
* @lnum: the last used logical eraseblock number for the PEB
* @torture: if the physical eraseblock has to be tortured
+ * @nested: denotes whether the work_sem is already held in read mode
*
* This function returns zero in case of success and a %-ENOMEM in case of
* failure.
@@ -1063,8 +1064,6 @@ out_unlock:
* __erase_worker - physical eraseblock erase worker function.
* @ubi: UBI device description object
* @wl_wrk: the work object
- * @shutdown: non-zero if the worker has to free memory and exit
- * because the WL sub-system is shutting down
*
* This function erases a physical eraseblock and perform torture testing if
* needed. It also takes care about marking the physical eraseblock bad if