mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 20:54:10 +08:00
MTD core
* block2mtd: page index should use pgoff_t * maps: physmap: minimal Runtime PM support * maps: pcmciamtd: avoid possible sleep-in-atomic-context bugs * concat: Fix a comment referring to an unknown symbol Raw NAND * Macronix: Use match_string() helper * Atmel: switch to using devm_fwnode_gpiod_get() * Denali: rework the SKIP_BYTES feature and add reset controlling * Brcmnand: set appropriate DMA mask * Cadence: add unspecified HAS_IOMEM dependency * Various cleanup. Onenand * Rename Samsung and Omap2 drivers to avoid possible build warnings * Enable compile testing * Various build issues * Kconfig cleanup SPI-NAND * Support for Toshiba TC58CVG2S0HRAIJ SPI-NOR: - Add support for TB selection using SR bit 6, - Add support for few flashes. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAl4zMfgACgkQJWrqGEe9 VoS0xwf+KdaihRno4SkDovcHoF7K54N6CqBhwuV9uabfy4phEr38cyvaivYu0rG7 k/n3CUNRDghTh7DAUT7pBsjUeZn9XxvKyQaZz34TBgoQYwGz57ssp8lMRmJkYoA6 t9z95N9bRJ+IzZJlYELCbhNq+aOGyWYgWL+aaO0CE8OyOeWzdZumdd4k7cF7rSAu 9gWV/6iX/qP081NexfjPEVmMtNQ+0p4T7zQ01nQA7rIZiVoIgMKwBu41aRYycEEs LeuV5gNEDn2vGBl+u85w5oF6o1TIzDeTmh0G7Jm3NQGGco2kOOZ1O39a0hrDONrA hEoEIG/rAMKOtaLr6rCGnV/5/i/Tlw== =WC+m -----END PGP SIGNATURE----- Merge tag 'mtd/for-5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux Pull MTD updates from Miquel Raynal: "MTD core - block2mtd: page index should use pgoff_t - maps: physmap: minimal Runtime PM support - maps: pcmciamtd: avoid possible sleep-in-atomic-context bugs - concat: Fix a comment referring to an unknown symbol Raw NAND: - Macronix: Use match_string() helper - Atmel: switch to using devm_fwnode_gpiod_get() - Denali: rework the SKIP_BYTES feature and add reset controlling - Brcmnand: set appropriate DMA mask - Cadence: add unspecified HAS_IOMEM dependency - Various cleanup. Onenand: - Rename Samsung and Omap2 drivers to avoid possible build warnings - Enable compile testing - Various build issues - Kconfig cleanup SPI-NAND: - Support for Toshiba TC58CVG2S0HRAIJ SPI-NOR: - Add support for TB selection using SR bit 6, - Add support for few flashes" * tag 'mtd/for-5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (41 commits) mtd: concat: Fix a comment referring to an unknown symbol mtd: rawnand: add unspecified HAS_IOMEM dependency mtd: block2mtd: page index should use pgoff_t mtd: maps: physmap: Add minimal Runtime PM support mtd: maps: pcmciamtd: fix possible sleep-in-atomic-context bugs in pcmciamtd_set_vpp() mtd: onenand: Rename omap2 driver to avoid a build warning mtd: onenand: Use a better name for samsung driver mtd: rawnand: atmel: switch to using devm_fwnode_gpiod_get() mtd: spinand: add support for Toshiba TC58CVG2S0HRAIJ mtd: rawnand: macronix: Use match_string() helper to simplify the code mtd: sharpslpart: Fix unsigned comparison to zero mtd: onenand: Enable compile testing of OMAP and Samsung drivers mtd: onenand: samsung: Fix printing format for size_t on 64-bit mtd: onenand: samsung: Fix pointer cast -Wpointer-to-int-cast warnings on 64 bit mtd: rawnand: denali: remove hard-coded DENALI_DEFAULT_OOB_SKIP_BYTES mtd: rawnand: denali_dt: add reset controlling dt-bindings: mtd: denali_dt: document reset property mtd: rawnand: denali_dt: Add support for configuring SPARE_AREA_SKIP_BYTES mtd: rawnand: denali_dt: error out if platform has no associated data mtd: rawnand: brcmnand: Set appropriate DMA mask ...
This commit is contained in:
commit
35c222fd32
@ -14,6 +14,11 @@ Required properties:
|
||||
interface clock, and the ECC circuit clock.
|
||||
- clock-names: should contain "nand", "nand_x", "ecc"
|
||||
|
||||
Optional properties:
|
||||
- resets: may contain phandles to the controller core reset, the register
|
||||
reset
|
||||
- reset-names: may contain "nand", "reg"
|
||||
|
||||
Sub-nodes:
|
||||
Sub-nodes represent available NAND chips.
|
||||
|
||||
@ -46,6 +51,8 @@ nand: nand@ff900000 {
|
||||
reg-names = "nand_data", "denali_reg";
|
||||
clocks = <&nand_clk>, <&nand_x_clk>, <&nand_ecc_clk>;
|
||||
clock-names = "nand", "nand_x", "ecc";
|
||||
resets = <&nand_rst>, <&nand_reg_rst>;
|
||||
reset-names = "nand", "reg";
|
||||
interrupts = <0 144 4>;
|
||||
|
||||
nand@0 {
|
||||
|
@ -44,7 +44,7 @@ struct block2mtd_dev {
|
||||
static LIST_HEAD(blkmtd_device_list);
|
||||
|
||||
|
||||
static struct page *page_read(struct address_space *mapping, int index)
|
||||
static struct page *page_read(struct address_space *mapping, pgoff_t index)
|
||||
{
|
||||
return read_mapping_page(mapping, index, NULL);
|
||||
}
|
||||
@ -54,7 +54,7 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
|
||||
{
|
||||
struct address_space *mapping = dev->blkdev->bd_inode->i_mapping;
|
||||
struct page *page;
|
||||
int index = to >> PAGE_SHIFT; // page index
|
||||
pgoff_t index = to >> PAGE_SHIFT; // page index
|
||||
int pages = len >> PAGE_SHIFT;
|
||||
u_long *p;
|
||||
u_long *max;
|
||||
@ -103,7 +103,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
{
|
||||
struct block2mtd_dev *dev = mtd->priv;
|
||||
struct page *page;
|
||||
int index = from >> PAGE_SHIFT;
|
||||
pgoff_t index = from >> PAGE_SHIFT;
|
||||
int offset = from & (PAGE_SIZE-1);
|
||||
int cpylen;
|
||||
|
||||
@ -137,7 +137,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
|
||||
{
|
||||
struct page *page;
|
||||
struct address_space *mapping = dev->blkdev->bd_inode->i_mapping;
|
||||
int index = to >> PAGE_SHIFT; // page index
|
||||
pgoff_t index = to >> PAGE_SHIFT; // page index
|
||||
int offset = to & ~PAGE_MASK; // page offset
|
||||
int cpylen;
|
||||
|
||||
|
@ -294,16 +294,15 @@ static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *f
|
||||
}
|
||||
|
||||
|
||||
static DEFINE_SPINLOCK(pcmcia_vpp_lock);
|
||||
static DEFINE_MUTEX(pcmcia_vpp_lock);
|
||||
static int pcmcia_vpp_refcnt;
|
||||
static void pcmciamtd_set_vpp(struct map_info *map, int on)
|
||||
{
|
||||
struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
|
||||
struct pcmcia_device *link = dev->p_dev;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp);
|
||||
spin_lock_irqsave(&pcmcia_vpp_lock, flags);
|
||||
mutex_lock(&pcmcia_vpp_lock);
|
||||
if (on) {
|
||||
if (++pcmcia_vpp_refcnt == 1) /* first nested 'on' */
|
||||
pcmcia_fixup_vpp(link, dev->vpp);
|
||||
@ -311,7 +310,7 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on)
|
||||
if (--pcmcia_vpp_refcnt == 0) /* last nested 'off' */
|
||||
pcmcia_fixup_vpp(link, 0);
|
||||
}
|
||||
spin_unlock_irqrestore(&pcmcia_vpp_lock, flags);
|
||||
mutex_unlock(&pcmcia_vpp_lock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <linux/mtd/cfi_endian.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include "physmap-gemini.h"
|
||||
@ -64,16 +65,16 @@ static int physmap_flash_remove(struct platform_device *dev)
|
||||
{
|
||||
struct physmap_flash_info *info;
|
||||
struct physmap_flash_data *physmap_data;
|
||||
int i, err;
|
||||
int i, err = 0;
|
||||
|
||||
info = platform_get_drvdata(dev);
|
||||
if (!info)
|
||||
return 0;
|
||||
goto out;
|
||||
|
||||
if (info->cmtd) {
|
||||
err = mtd_device_unregister(info->cmtd);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
if (info->cmtd != info->mtds[0])
|
||||
mtd_concat_destroy(info->cmtd);
|
||||
@ -88,7 +89,10 @@ static int physmap_flash_remove(struct platform_device *dev)
|
||||
if (physmap_data && physmap_data->exit)
|
||||
physmap_data->exit(dev);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
pm_runtime_put(&dev->dev);
|
||||
pm_runtime_disable(&dev->dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void physmap_set_vpp(struct map_info *map, int state)
|
||||
@ -484,13 +488,19 @@ static int physmap_flash_probe(struct platform_device *dev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&dev->dev);
|
||||
pm_runtime_get_sync(&dev->dev);
|
||||
|
||||
if (dev->dev.of_node)
|
||||
err = physmap_flash_of_init(dev);
|
||||
else
|
||||
err = physmap_flash_pdata_init(dev);
|
||||
|
||||
if (err)
|
||||
if (err) {
|
||||
pm_runtime_put(&dev->dev);
|
||||
pm_runtime_disable(&dev->dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < info->nmaps; i++) {
|
||||
struct resource *res;
|
||||
|
@ -841,10 +841,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||
return &concat->mtd;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function destroys an MTD object obtained from concat_mtd_devs()
|
||||
*/
|
||||
|
||||
/* Cleans the context obtained from mtd_concat_create() */
|
||||
void mtd_concat_destroy(struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_concat *concat = CONCAT(mtd);
|
||||
|
@ -25,7 +25,7 @@ config MTD_ONENAND_GENERIC
|
||||
|
||||
config MTD_ONENAND_OMAP2
|
||||
tristate "OneNAND on OMAP2/OMAP3 support"
|
||||
depends on ARCH_OMAP2 || ARCH_OMAP3
|
||||
depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && ARM)
|
||||
depends on OF || COMPILE_TEST
|
||||
help
|
||||
Support for a OneNAND flash device connected to an OMAP2/OMAP3 SoC
|
||||
@ -33,12 +33,12 @@ config MTD_ONENAND_OMAP2
|
||||
Enable dmaengine and gpiolib for better performance.
|
||||
|
||||
config MTD_ONENAND_SAMSUNG
|
||||
tristate "OneNAND on Samsung SOC controller support"
|
||||
depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS4
|
||||
help
|
||||
Support for a OneNAND flash device connected to an Samsung SOC.
|
||||
S3C64XX uses command mapping method.
|
||||
S5PC110/S5PC210 use generic OneNAND method.
|
||||
tristate "OneNAND on Samsung SOC controller support"
|
||||
depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS4 || COMPILE_TEST
|
||||
help
|
||||
Support for a OneNAND flash device connected to an Samsung SOC.
|
||||
S3C64XX uses command mapping method.
|
||||
S5PC110/S5PC210 use generic OneNAND method.
|
||||
|
||||
config MTD_ONENAND_OTP
|
||||
bool "OneNAND OTP Support"
|
||||
|
@ -8,7 +8,7 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o
|
||||
|
||||
# Board specific.
|
||||
obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o
|
||||
obj-$(CONFIG_MTD_ONENAND_OMAP2) += omap2.o
|
||||
obj-$(CONFIG_MTD_ONENAND_SAMSUNG) += samsung_mtd.o
|
||||
obj-$(CONFIG_MTD_ONENAND_OMAP2) += onenand_omap2.o
|
||||
obj-$(CONFIG_MTD_ONENAND_SAMSUNG) += onenand_samsung.o
|
||||
|
||||
onenand-objs = onenand_base.o onenand_bbt.o
|
||||
|
@ -1248,44 +1248,44 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||
|
||||
stats = mtd->ecc_stats;
|
||||
|
||||
/* Read-while-load method */
|
||||
/* Read-while-load method */
|
||||
|
||||
/* Do first load to bufferRAM */
|
||||
if (read < len) {
|
||||
if (!onenand_check_bufferram(mtd, from)) {
|
||||
/* Do first load to bufferRAM */
|
||||
if (read < len) {
|
||||
if (!onenand_check_bufferram(mtd, from)) {
|
||||
this->command(mtd, ONENAND_CMD_READ, from, writesize);
|
||||
ret = this->wait(mtd, FL_READING);
|
||||
onenand_update_bufferram(mtd, from, !ret);
|
||||
ret = this->wait(mtd, FL_READING);
|
||||
onenand_update_bufferram(mtd, from, !ret);
|
||||
if (mtd_is_eccerr(ret))
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thislen = min_t(int, writesize, len - read);
|
||||
column = from & (writesize - 1);
|
||||
if (column + thislen > writesize)
|
||||
thislen = writesize - column;
|
||||
|
||||
while (!ret) {
|
||||
/* If there is more to load then start next load */
|
||||
from += thislen;
|
||||
if (read + thislen < len) {
|
||||
while (!ret) {
|
||||
/* If there is more to load then start next load */
|
||||
from += thislen;
|
||||
if (read + thislen < len) {
|
||||
this->command(mtd, ONENAND_CMD_READ, from, writesize);
|
||||
/*
|
||||
* Chip boundary handling in DDP
|
||||
* Now we issued chip 1 read and pointed chip 1
|
||||
/*
|
||||
* Chip boundary handling in DDP
|
||||
* Now we issued chip 1 read and pointed chip 1
|
||||
* bufferram so we have to point chip 0 bufferram.
|
||||
*/
|
||||
if (ONENAND_IS_DDP(this) &&
|
||||
unlikely(from == (this->chipsize >> 1))) {
|
||||
this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
|
||||
boundary = 1;
|
||||
} else
|
||||
boundary = 0;
|
||||
ONENAND_SET_PREV_BUFFERRAM(this);
|
||||
}
|
||||
/* While load is going, read from last bufferRAM */
|
||||
this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
|
||||
*/
|
||||
if (ONENAND_IS_DDP(this) &&
|
||||
unlikely(from == (this->chipsize >> 1))) {
|
||||
this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
|
||||
boundary = 1;
|
||||
} else
|
||||
boundary = 0;
|
||||
ONENAND_SET_PREV_BUFFERRAM(this);
|
||||
}
|
||||
/* While load is going, read from last bufferRAM */
|
||||
this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
|
||||
|
||||
/* Read oob area if needed */
|
||||
if (oobbuf) {
|
||||
@ -1301,24 +1301,24 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||
oobcolumn = 0;
|
||||
}
|
||||
|
||||
/* See if we are done */
|
||||
read += thislen;
|
||||
if (read == len)
|
||||
break;
|
||||
/* Set up for next read from bufferRAM */
|
||||
if (unlikely(boundary))
|
||||
this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
|
||||
ONENAND_SET_NEXT_BUFFERRAM(this);
|
||||
buf += thislen;
|
||||
/* See if we are done */
|
||||
read += thislen;
|
||||
if (read == len)
|
||||
break;
|
||||
/* Set up for next read from bufferRAM */
|
||||
if (unlikely(boundary))
|
||||
this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
|
||||
ONENAND_SET_NEXT_BUFFERRAM(this);
|
||||
buf += thislen;
|
||||
thislen = min_t(int, writesize, len - read);
|
||||
column = 0;
|
||||
cond_resched();
|
||||
/* Now wait for load */
|
||||
ret = this->wait(mtd, FL_READING);
|
||||
onenand_update_bufferram(mtd, from, !ret);
|
||||
column = 0;
|
||||
cond_resched();
|
||||
/* Now wait for load */
|
||||
ret = this->wait(mtd, FL_READING);
|
||||
onenand_update_bufferram(mtd, from, !ret);
|
||||
if (mtd_is_eccerr(ret))
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return success, if no ECC failures, else -EBADMSG
|
||||
|
@ -248,7 +248,7 @@ static unsigned short s3c_onenand_readw(void __iomem *addr)
|
||||
}
|
||||
|
||||
/* BootRAM access control */
|
||||
if ((unsigned int) addr < ONENAND_DATARAM && onenand->bootram_command) {
|
||||
if ((unsigned long)addr < ONENAND_DATARAM && onenand->bootram_command) {
|
||||
if (word_addr == 0)
|
||||
return s3c_read_reg(MANUFACT_ID_OFFSET);
|
||||
if (word_addr == 1)
|
||||
@ -289,7 +289,7 @@ static void s3c_onenand_writew(unsigned short value, void __iomem *addr)
|
||||
}
|
||||
|
||||
/* BootRAM access control */
|
||||
if ((unsigned int)addr < ONENAND_DATARAM) {
|
||||
if ((unsigned long)addr < ONENAND_DATARAM) {
|
||||
if (value == ONENAND_CMD_READID) {
|
||||
onenand->bootram_command = 1;
|
||||
return;
|
||||
@ -658,7 +658,7 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
|
||||
dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE);
|
||||
}
|
||||
if (dma_mapping_error(dev, dma_dst)) {
|
||||
dev_err(dev, "Couldn't map a %d byte buffer for DMA\n", count);
|
||||
dev_err(dev, "Couldn't map a %zu byte buffer for DMA\n", count);
|
||||
goto normal;
|
||||
}
|
||||
err = s5pc110_dma_ops(dma_dst, dma_src,
|
||||
@ -728,13 +728,12 @@ static void s3c_onenand_check_lock_status(struct mtd_info *mtd)
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
struct device *dev = &onenand->pdev->dev;
|
||||
unsigned int block, end;
|
||||
int tmp;
|
||||
|
||||
end = this->chipsize >> this->erase_shift;
|
||||
|
||||
for (block = 0; block < end; block++) {
|
||||
unsigned int mem_addr = onenand->mem_addr(block, 0, 0);
|
||||
tmp = s3c_read_cmd(CMD_MAP_01(onenand, mem_addr));
|
||||
s3c_read_cmd(CMD_MAP_01(onenand, mem_addr));
|
||||
|
||||
if (s3c_read_reg(INT_ERR_STAT_OFFSET) & LOCKED_BLK) {
|
||||
dev_err(dev, "block %d is write-protected!\n", block);
|
@ -452,7 +452,7 @@ config MTD_NAND_PLATFORM
|
||||
|
||||
config MTD_NAND_CADENCE
|
||||
tristate "Support Cadence NAND (HPNFC) controller"
|
||||
depends on OF || COMPILE_TEST
|
||||
depends on (OF || COMPILE_TEST) && HAS_IOMEM
|
||||
help
|
||||
Enable the driver for NAND flash on platforms using a Cadence NAND
|
||||
controller.
|
||||
|
@ -1578,9 +1578,8 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
|
||||
|
||||
nand->numcs = numcs;
|
||||
|
||||
gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "det", 0,
|
||||
&np->fwnode, GPIOD_IN,
|
||||
"nand-det");
|
||||
gpio = devm_fwnode_gpiod_get(nc->dev, of_fwnode_handle(np),
|
||||
"det", GPIOD_IN, "nand-det");
|
||||
if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
|
||||
dev_err(nc->dev,
|
||||
"Failed to get detect gpio (err = %ld)\n",
|
||||
@ -1624,9 +1623,10 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
|
||||
nand->cs[i].rb.type = ATMEL_NAND_NATIVE_RB;
|
||||
nand->cs[i].rb.id = val;
|
||||
} else {
|
||||
gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev,
|
||||
"rb", i, &np->fwnode,
|
||||
GPIOD_IN, "nand-rb");
|
||||
gpio = devm_fwnode_gpiod_get_index(nc->dev,
|
||||
of_fwnode_handle(np),
|
||||
"rb", i, GPIOD_IN,
|
||||
"nand-rb");
|
||||
if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
|
||||
dev_err(nc->dev,
|
||||
"Failed to get R/B gpio (err = %ld)\n",
|
||||
@ -1640,10 +1640,10 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
|
||||
}
|
||||
}
|
||||
|
||||
gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "cs",
|
||||
i, &np->fwnode,
|
||||
GPIOD_OUT_HIGH,
|
||||
"nand-cs");
|
||||
gpio = devm_fwnode_gpiod_get_index(nc->dev,
|
||||
of_fwnode_handle(np),
|
||||
"cs", i, GPIOD_OUT_HIGH,
|
||||
"nand-cs");
|
||||
if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
|
||||
dev_err(nc->dev,
|
||||
"Failed to get CS gpio (err = %ld)\n",
|
||||
|
@ -2635,6 +2635,16 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
|
||||
/* initialize the dma version */
|
||||
brcmnand_flash_dma_revision_init(ctrl);
|
||||
|
||||
ret = -EIO;
|
||||
if (ctrl->nand_version >= 0x0700)
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev,
|
||||
DMA_BIT_MASK(40));
|
||||
if (ret)
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev,
|
||||
DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* linked-list and stop on error */
|
||||
flash_dma_writel(ctrl, FLASH_DMA_MODE, FLASH_DMA_MODE_MASK);
|
||||
flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "denali.h"
|
||||
|
||||
#define DENALI_NAND_NAME "denali-nand"
|
||||
#define DENALI_DEFAULT_OOB_SKIP_BYTES 8
|
||||
|
||||
/* for Indexed Addressing */
|
||||
#define DENALI_INDEXED_CTRL 0x00
|
||||
@ -1302,15 +1301,16 @@ int denali_init(struct denali_controller *denali)
|
||||
|
||||
/*
|
||||
* Set how many bytes should be skipped before writing data in OOB.
|
||||
* If a non-zero value has already been set (by firmware or something),
|
||||
* just use it. Otherwise, set the driver's default.
|
||||
* If a platform requests a non-zero value, set it to the register.
|
||||
* Otherwise, read the value out, expecting it has already been set up
|
||||
* by firmware.
|
||||
*/
|
||||
denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
|
||||
if (!denali->oob_skip_bytes) {
|
||||
denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES;
|
||||
if (denali->oob_skip_bytes)
|
||||
iowrite32(denali->oob_skip_bytes,
|
||||
denali->reg + SPARE_AREA_SKIP_BYTES);
|
||||
}
|
||||
else
|
||||
denali->oob_skip_bytes = ioread32(denali->reg +
|
||||
SPARE_AREA_SKIP_BYTES);
|
||||
|
||||
iowrite32(0, denali->reg + TRANSFER_SPARE_REG);
|
||||
iowrite32(GENMASK(denali->nbanks - 1, 0), denali->reg + RB_PIN_ENABLED);
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
@ -14,6 +15,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "denali.h"
|
||||
|
||||
@ -22,11 +24,14 @@ struct denali_dt {
|
||||
struct clk *clk; /* core clock */
|
||||
struct clk *clk_x; /* bus interface clock */
|
||||
struct clk *clk_ecc; /* ECC circuit clock */
|
||||
struct reset_control *rst; /* core reset */
|
||||
struct reset_control *rst_reg; /* register reset */
|
||||
};
|
||||
|
||||
struct denali_dt_data {
|
||||
unsigned int revision;
|
||||
unsigned int caps;
|
||||
unsigned int oob_skip_bytes;
|
||||
const struct nand_ecc_caps *ecc_caps;
|
||||
};
|
||||
|
||||
@ -34,6 +39,7 @@ NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
|
||||
512, 8, 15);
|
||||
static const struct denali_dt_data denali_socfpga_data = {
|
||||
.caps = DENALI_CAP_HW_ECC_FIXUP,
|
||||
.oob_skip_bytes = 2,
|
||||
.ecc_caps = &denali_socfpga_ecc_caps,
|
||||
};
|
||||
|
||||
@ -42,6 +48,7 @@ NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
|
||||
static const struct denali_dt_data denali_uniphier_v5a_data = {
|
||||
.caps = DENALI_CAP_HW_ECC_FIXUP |
|
||||
DENALI_CAP_DMA_64BIT,
|
||||
.oob_skip_bytes = 8,
|
||||
.ecc_caps = &denali_uniphier_v5a_ecc_caps,
|
||||
};
|
||||
|
||||
@ -51,6 +58,7 @@ static const struct denali_dt_data denali_uniphier_v5b_data = {
|
||||
.revision = 0x0501,
|
||||
.caps = DENALI_CAP_HW_ECC_FIXUP |
|
||||
DENALI_CAP_DMA_64BIT,
|
||||
.oob_skip_bytes = 8,
|
||||
.ecc_caps = &denali_uniphier_v5b_ecc_caps,
|
||||
};
|
||||
|
||||
@ -118,11 +126,13 @@ static int denali_dt_probe(struct platform_device *pdev)
|
||||
denali = &dt->controller;
|
||||
|
||||
data = of_device_get_match_data(dev);
|
||||
if (data) {
|
||||
denali->revision = data->revision;
|
||||
denali->caps = data->caps;
|
||||
denali->ecc_caps = data->ecc_caps;
|
||||
}
|
||||
if (WARN_ON(!data))
|
||||
return -EINVAL;
|
||||
|
||||
denali->revision = data->revision;
|
||||
denali->caps = data->caps;
|
||||
denali->oob_skip_bytes = data->oob_skip_bytes;
|
||||
denali->ecc_caps = data->ecc_caps;
|
||||
|
||||
denali->dev = dev;
|
||||
denali->irq = platform_get_irq(pdev, 0);
|
||||
@ -151,6 +161,14 @@ static int denali_dt_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(dt->clk_ecc))
|
||||
return PTR_ERR(dt->clk_ecc);
|
||||
|
||||
dt->rst = devm_reset_control_get_optional_shared(dev, "nand");
|
||||
if (IS_ERR(dt->rst))
|
||||
return PTR_ERR(dt->rst);
|
||||
|
||||
dt->rst_reg = devm_reset_control_get_optional_shared(dev, "reg");
|
||||
if (IS_ERR(dt->rst_reg))
|
||||
return PTR_ERR(dt->rst_reg);
|
||||
|
||||
ret = clk_prepare_enable(dt->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -166,10 +184,30 @@ static int denali_dt_probe(struct platform_device *pdev)
|
||||
denali->clk_rate = clk_get_rate(dt->clk);
|
||||
denali->clk_x_rate = clk_get_rate(dt->clk_x);
|
||||
|
||||
ret = denali_init(denali);
|
||||
/*
|
||||
* Deassert the register reset, and the core reset in this order.
|
||||
* Deasserting the core reset while the register reset is asserted
|
||||
* will cause unpredictable behavior in the controller.
|
||||
*/
|
||||
ret = reset_control_deassert(dt->rst_reg);
|
||||
if (ret)
|
||||
goto out_disable_clk_ecc;
|
||||
|
||||
ret = reset_control_deassert(dt->rst);
|
||||
if (ret)
|
||||
goto out_assert_rst_reg;
|
||||
|
||||
/*
|
||||
* When the reset is deasserted, the initialization sequence is kicked
|
||||
* (bootstrap process). The driver must wait until it finished.
|
||||
* Otherwise, it will result in unpredictable behavior.
|
||||
*/
|
||||
usleep_range(200, 1000);
|
||||
|
||||
ret = denali_init(denali);
|
||||
if (ret)
|
||||
goto out_assert_rst;
|
||||
|
||||
for_each_child_of_node(dev->of_node, np) {
|
||||
ret = denali_dt_chip_init(denali, np);
|
||||
if (ret) {
|
||||
@ -184,6 +222,10 @@ static int denali_dt_probe(struct platform_device *pdev)
|
||||
|
||||
out_remove_denali:
|
||||
denali_remove(denali);
|
||||
out_assert_rst:
|
||||
reset_control_assert(dt->rst);
|
||||
out_assert_rst_reg:
|
||||
reset_control_assert(dt->rst_reg);
|
||||
out_disable_clk_ecc:
|
||||
clk_disable_unprepare(dt->clk_ecc);
|
||||
out_disable_clk_x:
|
||||
@ -199,6 +241,8 @@ static int denali_dt_remove(struct platform_device *pdev)
|
||||
struct denali_dt *dt = platform_get_drvdata(pdev);
|
||||
|
||||
denali_remove(&dt->controller);
|
||||
reset_control_assert(dt->rst);
|
||||
reset_control_assert(dt->rst_reg);
|
||||
clk_disable_unprepare(dt->clk_ecc);
|
||||
clk_disable_unprepare(dt->clk_x);
|
||||
clk_disable_unprepare(dt->clk);
|
||||
|
@ -438,7 +438,7 @@ static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
|
||||
buffer += blksize;
|
||||
offset += blksize;
|
||||
size -= blksize;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy data from/to NFC main and spare buffers */
|
||||
|
@ -59,7 +59,7 @@ static void macronix_nand_onfi_init(struct nand_chip *chip)
|
||||
*/
|
||||
static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
|
||||
{
|
||||
unsigned int i;
|
||||
int i;
|
||||
static const char * const broken_get_timings[] = {
|
||||
"MX30LF1G18AC",
|
||||
"MX30LF1G28AC",
|
||||
@ -80,12 +80,9 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
|
||||
if (!chip->parameters.supports_set_get_features)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(broken_get_timings); i++) {
|
||||
if (!strcmp(broken_get_timings[i], chip->parameters.model))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(broken_get_timings))
|
||||
i = match_string(broken_get_timings, ARRAY_SIZE(broken_get_timings),
|
||||
chip->parameters.model);
|
||||
if (i < 0)
|
||||
return;
|
||||
|
||||
bitmap_clear(chip->parameters.get_feature_list,
|
||||
|
@ -124,6 +124,16 @@ static const struct spinand_info toshiba_spinand_table[] = {
|
||||
0,
|
||||
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
|
||||
tc58cxgxsx_ecc_get_status)),
|
||||
/* 3.3V 4Gb */
|
||||
SPINAND_INFO("TC58CVG2S0", 0xED,
|
||||
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
|
||||
tc58cxgxsx_ecc_get_status)),
|
||||
/* 1.8V 1Gb */
|
||||
SPINAND_INFO("TC58CYG0S3", 0xB2,
|
||||
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
|
||||
|
@ -165,10 +165,10 @@ static int sharpsl_nand_get_logical_num(u8 *oob)
|
||||
|
||||
static int sharpsl_nand_init_ftl(struct mtd_info *mtd, struct sharpsl_ftl *ftl)
|
||||
{
|
||||
unsigned int block_num, log_num, phymax;
|
||||
unsigned int block_num, phymax;
|
||||
int i, ret, log_num;
|
||||
loff_t block_adr;
|
||||
u8 *oob;
|
||||
int i, ret;
|
||||
|
||||
oob = kzalloc(mtd->oobsize, GFP_KERNEL);
|
||||
if (!oob)
|
||||
|
@ -46,11 +46,11 @@ config SPI_CADENCE_QUADSPI
|
||||
Flash as an MTD device.
|
||||
|
||||
config SPI_HISI_SFC
|
||||
tristate "Hisilicon SPI-NOR Flash Controller(SFC)"
|
||||
tristate "Hisilicon FMC SPI-NOR Flash Controller(SFC)"
|
||||
depends on ARCH_HISI || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
This enables support for hisilicon SPI-NOR flash controller.
|
||||
This enables support for HiSilicon FMC SPI-NOR flash controller.
|
||||
|
||||
config SPI_MTK_QUADSPI
|
||||
tristate "MediaTek Quad SPI controller"
|
||||
|
@ -305,7 +305,7 @@ static void aspeed_smc_stop_user(struct spi_nor *nor)
|
||||
writel(ctl, chip->ctl); /* default to fread or read mode */
|
||||
}
|
||||
|
||||
static int aspeed_smc_prep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
static int aspeed_smc_prep(struct spi_nor *nor)
|
||||
{
|
||||
struct aspeed_smc_chip *chip = nor->priv;
|
||||
|
||||
@ -313,7 +313,7 @@ static int aspeed_smc_prep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aspeed_smc_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
static void aspeed_smc_unprep(struct spi_nor *nor)
|
||||
{
|
||||
struct aspeed_smc_chip *chip = nor->priv;
|
||||
|
||||
|
@ -1062,7 +1062,7 @@ static int cqspi_erase(struct spi_nor *nor, loff_t offs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cqspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
static int cqspi_prep(struct spi_nor *nor)
|
||||
{
|
||||
struct cqspi_flash_pdata *f_pdata = nor->priv;
|
||||
struct cqspi_st *cqspi = f_pdata->cqspi;
|
||||
@ -1072,7 +1072,7 @@ static int cqspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cqspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
static void cqspi_unprep(struct spi_nor *nor)
|
||||
{
|
||||
struct cqspi_flash_pdata *f_pdata = nor->priv;
|
||||
struct cqspi_st *cqspi = f_pdata->cqspi;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* HiSilicon SPI Nor Flash Controller Driver
|
||||
* HiSilicon FMC SPI-NOR flash controller driver
|
||||
*
|
||||
* Copyright (c) 2015-2016 HiSilicon Technologies Co., Ltd.
|
||||
*/
|
||||
@ -144,7 +144,7 @@ static void hisi_spi_nor_init(struct hifmc_host *host)
|
||||
writel(reg, host->regbase + FMC_SPI_TIMING_CFG);
|
||||
}
|
||||
|
||||
static int hisi_spi_nor_prep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
static int hisi_spi_nor_prep(struct spi_nor *nor)
|
||||
{
|
||||
struct hifmc_priv *priv = nor->priv;
|
||||
struct hifmc_host *host = priv->host;
|
||||
@ -167,7 +167,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hisi_spi_nor_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
static void hisi_spi_nor_unprep(struct spi_nor *nor)
|
||||
{
|
||||
struct hifmc_priv *priv = nor->priv;
|
||||
struct hifmc_host *host = priv->host;
|
||||
|
@ -70,10 +70,12 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&bxt_info },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
|
||||
|
@ -85,7 +85,7 @@ struct sfdp_header {
|
||||
#define BFPT_DWORD(i) ((i) - 1)
|
||||
#define BFPT_DWORD_MAX 16
|
||||
|
||||
/* The first version of JESB216 defined only 9 DWORDs. */
|
||||
/* The first version of JESD216 defined only 9 DWORDs. */
|
||||
#define BFPT_DWORD_MAX_JESD216 9
|
||||
|
||||
/* 1st DWORD. */
|
||||
@ -196,7 +196,7 @@ struct flash_info {
|
||||
u16 page_size;
|
||||
u16 addr_width;
|
||||
|
||||
u16 flags;
|
||||
u32 flags;
|
||||
#define SECT_4K BIT(0) /* SPINOR_OP_BE_4K works uniformly */
|
||||
#define SPI_NOR_NO_ERASE BIT(1) /* No erase command needed */
|
||||
#define SST_WRITE BIT(2) /* use SST byte programming */
|
||||
@ -233,6 +233,11 @@ struct flash_info {
|
||||
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
|
||||
#define USE_CLSR BIT(14) /* use CLSR command */
|
||||
#define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */
|
||||
#define SPI_NOR_TB_SR_BIT6 BIT(16) /*
|
||||
* Top/Bottom (TB) is bit 6 of
|
||||
* status register. Must be used with
|
||||
* SPI_NOR_HAS_TB.
|
||||
*/
|
||||
|
||||
/* Part specific fixup hooks. */
|
||||
const struct spi_nor_fixups *fixups;
|
||||
@ -1307,14 +1312,14 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
|
||||
}
|
||||
}
|
||||
|
||||
static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
static int spi_nor_lock_and_prep(struct spi_nor *nor)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&nor->lock);
|
||||
|
||||
if (nor->controller_ops && nor->controller_ops->prepare) {
|
||||
ret = nor->controller_ops->prepare(nor, ops);
|
||||
ret = nor->controller_ops->prepare(nor);
|
||||
if (ret) {
|
||||
mutex_unlock(&nor->lock);
|
||||
return ret;
|
||||
@ -1323,10 +1328,10 @@ static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
static void spi_nor_unlock_and_unprep(struct spi_nor *nor)
|
||||
{
|
||||
if (nor->controller_ops && nor->controller_ops->unprepare)
|
||||
nor->controller_ops->unprepare(nor, ops);
|
||||
nor->controller_ops->unprepare(nor);
|
||||
mutex_unlock(&nor->lock);
|
||||
}
|
||||
|
||||
@ -1688,7 +1693,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
addr = instr->addr;
|
||||
len = instr->len;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_ERASE);
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1751,7 +1756,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
ret = spi_nor_write_disable(nor);
|
||||
|
||||
erase_err:
|
||||
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1761,9 +1766,13 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
|
||||
{
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
|
||||
u8 tb_mask = SR_TB_BIT5;
|
||||
int shift = ffs(mask) - 1;
|
||||
int pow;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
|
||||
tb_mask = SR_TB_BIT6;
|
||||
|
||||
if (!(sr & mask)) {
|
||||
/* No protection */
|
||||
*ofs = 0;
|
||||
@ -1771,7 +1780,7 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
|
||||
} else {
|
||||
pow = ((sr & mask) ^ mask) >> shift;
|
||||
*len = mtd->size >> pow;
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask)
|
||||
*ofs = 0;
|
||||
else
|
||||
*ofs = mtd->size - *len;
|
||||
@ -1850,6 +1859,7 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
int ret, status_old, status_new;
|
||||
u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
|
||||
u8 tb_mask = SR_TB_BIT5;
|
||||
u8 shift = ffs(mask) - 1, pow, val;
|
||||
loff_t lock_len;
|
||||
bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
|
||||
@ -1886,6 +1896,9 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
else
|
||||
lock_len = ofs + len;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
|
||||
tb_mask = SR_TB_BIT6;
|
||||
|
||||
/*
|
||||
* Need smallest pow such that:
|
||||
*
|
||||
@ -1903,13 +1916,13 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
if (!(val & mask))
|
||||
return -EINVAL;
|
||||
|
||||
status_new = (status_old & ~mask & ~SR_TB) | val;
|
||||
status_new = (status_old & ~mask & ~tb_mask) | val;
|
||||
|
||||
/* Disallow further writes if WP pin is asserted */
|
||||
status_new |= SR_SRWD;
|
||||
|
||||
if (!use_top)
|
||||
status_new |= SR_TB;
|
||||
status_new |= tb_mask;
|
||||
|
||||
/* Don't bother if they're the same */
|
||||
if (status_new == status_old)
|
||||
@ -1932,6 +1945,7 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
int ret, status_old, status_new;
|
||||
u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
|
||||
u8 tb_mask = SR_TB_BIT5;
|
||||
u8 shift = ffs(mask) - 1, pow, val;
|
||||
loff_t lock_len;
|
||||
bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
|
||||
@ -1968,6 +1982,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
else
|
||||
lock_len = ofs;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
|
||||
tb_mask = SR_TB_BIT6;
|
||||
/*
|
||||
* Need largest pow such that:
|
||||
*
|
||||
@ -1987,14 +2003,14 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status_new = (status_old & ~mask & ~SR_TB) | val;
|
||||
status_new = (status_old & ~mask & ~tb_mask) | val;
|
||||
|
||||
/* Don't protect status register if we're fully unlocked */
|
||||
if (lock_len == 0)
|
||||
status_new &= ~SR_SRWD;
|
||||
|
||||
if (!use_top)
|
||||
status_new |= SR_TB;
|
||||
status_new |= tb_mask;
|
||||
|
||||
/* Don't bother if they're the same */
|
||||
if (status_new == status_old)
|
||||
@ -2036,13 +2052,13 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
struct spi_nor *nor = mtd_to_spi_nor(mtd);
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK);
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nor->params.locking_ops->lock(nor, ofs, len);
|
||||
|
||||
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2051,13 +2067,13 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
struct spi_nor *nor = mtd_to_spi_nor(mtd);
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nor->params.locking_ops->unlock(nor, ofs, len);
|
||||
|
||||
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2066,13 +2082,13 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
struct spi_nor *nor = mtd_to_spi_nor(mtd);
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nor->params.locking_ops->is_locked(nor, ofs, len);
|
||||
|
||||
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2309,6 +2325,9 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
|
||||
|
||||
{ "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) },
|
||||
@ -2373,6 +2392,11 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
|
||||
},
|
||||
{
|
||||
"gd25lq128d", INFO(0xc86018, 0, 64 * 1024, 256,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
|
||||
},
|
||||
{
|
||||
"gd25q128", INFO(0xc84018, 0, 64 * 1024, 256,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
@ -2381,7 +2405,8 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
{
|
||||
"gd25q256", INFO(0xc84019, 0, 64 * 1024, 512,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
|
||||
SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB |
|
||||
SPI_NOR_TB_SR_BIT6)
|
||||
.fixups = &gd25q256_fixups,
|
||||
},
|
||||
|
||||
@ -2436,6 +2461,8 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
|
||||
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
|
||||
{ "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512,
|
||||
@ -2456,20 +2483,35 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
{ "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
|
||||
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
|
||||
{ "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
|
||||
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
|
||||
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
|
||||
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
|
||||
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K |
|
||||
USE_FSR | SPI_NOR_QUAD_READ) },
|
||||
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K |
|
||||
USE_FSR | SPI_NOR_QUAD_READ) },
|
||||
{ "mt25ql256a", INFO6(0x20ba19, 0x104400, 64 * 1024, 512,
|
||||
SECT_4K | USE_FSR | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
|
||||
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K |
|
||||
USE_FSR | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ) },
|
||||
{ "mt25qu256a", INFO6(0x20bb19, 0x104400, 64 * 1024, 512,
|
||||
SECT_4K | USE_FSR | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
|
||||
{ "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K |
|
||||
USE_FSR | SPI_NOR_QUAD_READ) },
|
||||
{ "mt25ql512a", INFO6(0x20ba20, 0x104400, 64 * 1024, 1024,
|
||||
SECT_4K | USE_FSR | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
|
||||
{ "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
|
||||
{ "mt25qu512a", INFO6(0x20bb20, 0x104400, 64 * 1024, 1024,
|
||||
SECT_4K | USE_FSR | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
|
||||
{ "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K |
|
||||
USE_FSR | SPI_NOR_QUAD_READ) },
|
||||
{ "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
|
||||
{ "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
|
||||
{ "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096,
|
||||
SECT_4K | USE_FSR | SPI_NOR_QUAD_READ |
|
||||
NO_CHIP_ERASE) },
|
||||
{ "mt25qu512a (n25q512a)", INFO(0x20bb20, 0, 64 * 1024, 1024,
|
||||
SECT_4K | USE_FSR | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_4B_OPCODES) },
|
||||
{ "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
|
||||
|
||||
/* Micron */
|
||||
@ -2540,6 +2582,8 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
{ "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
|
||||
{ "sst26wf016b", INFO(0xbf2651, 0, 64 * 1024, 32, SECT_4K |
|
||||
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32, SECT_4K |
|
||||
SPI_NOR_DUAL_READ) },
|
||||
{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
|
||||
/* ST Microelectronics -- newer production may have feature updates */
|
||||
@ -2610,6 +2654,11 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
|
||||
},
|
||||
{
|
||||
"w25q32jwm", INFO(0xef8016, 0, 64 * 1024, 64,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
|
||||
},
|
||||
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{
|
||||
@ -2630,7 +2679,9 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
|
||||
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
|
||||
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
|
||||
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_4B_OPCODES) },
|
||||
{ "w25q256jvm", INFO(0xef7019, 0, 64 * 1024, 512,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "w25q256jw", INFO(0xef6019, 0, 64 * 1024, 512,
|
||||
@ -2701,7 +2752,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
|
||||
dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -2728,7 +2779,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
ret = 0;
|
||||
|
||||
read_err:
|
||||
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2741,7 +2792,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
|
||||
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -2814,7 +2865,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
}
|
||||
out:
|
||||
*retlen += actual;
|
||||
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2832,7 +2883,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
|
||||
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -2878,7 +2929,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
}
|
||||
|
||||
write_err:
|
||||
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -5143,8 +5194,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
|
||||
|
||||
if (info->flags & USE_FSR)
|
||||
nor->flags |= SNOR_F_USE_FSR;
|
||||
if (info->flags & SPI_NOR_HAS_TB)
|
||||
if (info->flags & SPI_NOR_HAS_TB) {
|
||||
nor->flags |= SNOR_F_HAS_SR_TB;
|
||||
if (info->flags & SPI_NOR_TB_SR_BIT6)
|
||||
nor->flags |= SNOR_F_HAS_SR_TB_BIT6;
|
||||
}
|
||||
|
||||
if (info->flags & NO_CHIP_ERASE)
|
||||
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
|
||||
if (info->flags & USE_CLSR)
|
||||
|
@ -128,7 +128,8 @@
|
||||
#define SR_BP0 BIT(2) /* Block protect 0 */
|
||||
#define SR_BP1 BIT(3) /* Block protect 1 */
|
||||
#define SR_BP2 BIT(4) /* Block protect 2 */
|
||||
#define SR_TB BIT(5) /* Top/Bottom protect */
|
||||
#define SR_TB_BIT5 BIT(5) /* Top/Bottom protect */
|
||||
#define SR_TB_BIT6 BIT(6) /* Top/Bottom protect */
|
||||
#define SR_SRWD BIT(7) /* SR write protect */
|
||||
/* Spansion/Cypress specific status bits */
|
||||
#define SR_E_ERR BIT(5)
|
||||
@ -224,14 +225,6 @@ static inline u8 spi_nor_get_protocol_width(enum spi_nor_protocol proto)
|
||||
return spi_nor_get_protocol_data_nbits(proto);
|
||||
}
|
||||
|
||||
enum spi_nor_ops {
|
||||
SPI_NOR_OPS_READ = 0,
|
||||
SPI_NOR_OPS_WRITE,
|
||||
SPI_NOR_OPS_ERASE,
|
||||
SPI_NOR_OPS_LOCK,
|
||||
SPI_NOR_OPS_UNLOCK,
|
||||
};
|
||||
|
||||
enum spi_nor_option_flags {
|
||||
SNOR_F_USE_FSR = BIT(0),
|
||||
SNOR_F_HAS_SR_TB = BIT(1),
|
||||
@ -244,6 +237,7 @@ enum spi_nor_option_flags {
|
||||
SNOR_F_HAS_LOCK = BIT(8),
|
||||
SNOR_F_HAS_16BIT_SR = BIT(9),
|
||||
SNOR_F_NO_READ_CR = BIT(10),
|
||||
SNOR_F_HAS_SR_TB_BIT6 = BIT(11),
|
||||
|
||||
};
|
||||
|
||||
@ -483,8 +477,8 @@ struct spi_nor;
|
||||
* opcode via write_reg().
|
||||
*/
|
||||
struct spi_nor_controller_ops {
|
||||
int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
int (*prepare)(struct spi_nor *nor);
|
||||
void (*unprepare)(struct spi_nor *nor);
|
||||
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, size_t len);
|
||||
int (*write_reg)(struct spi_nor *nor, u8 opcode, const u8 *buf,
|
||||
size_t len);
|
||||
|
Loading…
Reference in New Issue
Block a user