Commit 35c222fd authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents e84bcd61 4575243c
...@@ -14,6 +14,11 @@ Required properties: ...@@ -14,6 +14,11 @@ Required properties:
interface clock, and the ECC circuit clock. interface clock, and the ECC circuit clock.
- clock-names: should contain "nand", "nand_x", "ecc" - 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:
Sub-nodes represent available NAND chips. Sub-nodes represent available NAND chips.
...@@ -46,6 +51,8 @@ nand: nand@ff900000 { ...@@ -46,6 +51,8 @@ nand: nand@ff900000 {
reg-names = "nand_data", "denali_reg"; reg-names = "nand_data", "denali_reg";
clocks = <&nand_clk>, <&nand_x_clk>, <&nand_ecc_clk>; clocks = <&nand_clk>, <&nand_x_clk>, <&nand_ecc_clk>;
clock-names = "nand", "nand_x", "ecc"; clock-names = "nand", "nand_x", "ecc";
resets = <&nand_rst>, <&nand_reg_rst>;
reset-names = "nand", "reg";
interrupts = <0 144 4>; interrupts = <0 144 4>;
nand@0 { nand@0 {
......
...@@ -44,7 +44,7 @@ struct block2mtd_dev { ...@@ -44,7 +44,7 @@ struct block2mtd_dev {
static LIST_HEAD(blkmtd_device_list); 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); 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) ...@@ -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 address_space *mapping = dev->blkdev->bd_inode->i_mapping;
struct page *page; struct page *page;
int index = to >> PAGE_SHIFT; // page index pgoff_t index = to >> PAGE_SHIFT; // page index
int pages = len >> PAGE_SHIFT; int pages = len >> PAGE_SHIFT;
u_long *p; u_long *p;
u_long *max; u_long *max;
...@@ -103,7 +103,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -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 block2mtd_dev *dev = mtd->priv;
struct page *page; struct page *page;
int index = from >> PAGE_SHIFT; pgoff_t index = from >> PAGE_SHIFT;
int offset = from & (PAGE_SIZE-1); int offset = from & (PAGE_SIZE-1);
int cpylen; int cpylen;
...@@ -137,7 +137,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, ...@@ -137,7 +137,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
{ {
struct page *page; struct page *page;
struct address_space *mapping = dev->blkdev->bd_inode->i_mapping; 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 offset = to & ~PAGE_MASK; // page offset
int cpylen; int cpylen;
......
...@@ -294,16 +294,15 @@ static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *f ...@@ -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 int pcmcia_vpp_refcnt;
static void pcmciamtd_set_vpp(struct map_info *map, int on) static void pcmciamtd_set_vpp(struct map_info *map, int on)
{ {
struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
struct pcmcia_device *link = dev->p_dev; struct pcmcia_device *link = dev->p_dev;
unsigned long flags;
pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp); 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 (on) {
if (++pcmcia_vpp_refcnt == 1) /* first nested 'on' */ if (++pcmcia_vpp_refcnt == 1) /* first nested 'on' */
pcmcia_fixup_vpp(link, dev->vpp); pcmcia_fixup_vpp(link, dev->vpp);
...@@ -311,7 +310,7 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on) ...@@ -311,7 +310,7 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on)
if (--pcmcia_vpp_refcnt == 0) /* last nested 'off' */ if (--pcmcia_vpp_refcnt == 0) /* last nested 'off' */
pcmcia_fixup_vpp(link, 0); pcmcia_fixup_vpp(link, 0);
} }
spin_unlock_irqrestore(&pcmcia_vpp_lock, flags); mutex_unlock(&pcmcia_vpp_lock);
} }
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <linux/mtd/cfi_endian.h> #include <linux/mtd/cfi_endian.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include "physmap-gemini.h" #include "physmap-gemini.h"
...@@ -64,16 +65,16 @@ static int physmap_flash_remove(struct platform_device *dev) ...@@ -64,16 +65,16 @@ static int physmap_flash_remove(struct platform_device *dev)
{ {
struct physmap_flash_info *info; struct physmap_flash_info *info;
struct physmap_flash_data *physmap_data; struct physmap_flash_data *physmap_data;
int i, err; int i, err = 0;
info = platform_get_drvdata(dev); info = platform_get_drvdata(dev);
if (!info) if (!info)
return 0; goto out;
if (info->cmtd) { if (info->cmtd) {
err = mtd_device_unregister(info->cmtd); err = mtd_device_unregister(info->cmtd);
if (err) if (err)
return err; goto out;
if (info->cmtd != info->mtds[0]) if (info->cmtd != info->mtds[0])
mtd_concat_destroy(info->cmtd); mtd_concat_destroy(info->cmtd);
...@@ -88,7 +89,10 @@ static int physmap_flash_remove(struct platform_device *dev) ...@@ -88,7 +89,10 @@ static int physmap_flash_remove(struct platform_device *dev)
if (physmap_data && physmap_data->exit) if (physmap_data && physmap_data->exit)
physmap_data->exit(dev); 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) static void physmap_set_vpp(struct map_info *map, int state)
...@@ -484,13 +488,19 @@ static int physmap_flash_probe(struct platform_device *dev) ...@@ -484,13 +488,19 @@ static int physmap_flash_probe(struct platform_device *dev)
return -EINVAL; return -EINVAL;
} }
pm_runtime_enable(&dev->dev);
pm_runtime_get_sync(&dev->dev);
if (dev->dev.of_node) if (dev->dev.of_node)
err = physmap_flash_of_init(dev); err = physmap_flash_of_init(dev);
else else
err = physmap_flash_pdata_init(dev); err = physmap_flash_pdata_init(dev);
if (err) if (err) {
pm_runtime_put(&dev->dev);
pm_runtime_disable(&dev->dev);
return err; return err;
}
for (i = 0; i < info->nmaps; i++) { for (i = 0; i < info->nmaps; i++) {
struct resource *res; struct resource *res;
......
...@@ -841,10 +841,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c ...@@ -841,10 +841,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
return &concat->mtd; return &concat->mtd;
} }
/* /* Cleans the context obtained from mtd_concat_create() */
* This function destroys an MTD object obtained from concat_mtd_devs()
*/
void mtd_concat_destroy(struct mtd_info *mtd) void mtd_concat_destroy(struct mtd_info *mtd)
{ {
struct mtd_concat *concat = CONCAT(mtd); struct mtd_concat *concat = CONCAT(mtd);
......
...@@ -25,7 +25,7 @@ config MTD_ONENAND_GENERIC ...@@ -25,7 +25,7 @@ config MTD_ONENAND_GENERIC
config MTD_ONENAND_OMAP2 config MTD_ONENAND_OMAP2
tristate "OneNAND on OMAP2/OMAP3 support" 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 depends on OF || COMPILE_TEST
help help
Support for a OneNAND flash device connected to an OMAP2/OMAP3 SoC Support for a OneNAND flash device connected to an OMAP2/OMAP3 SoC
...@@ -33,12 +33,12 @@ config MTD_ONENAND_OMAP2 ...@@ -33,12 +33,12 @@ config MTD_ONENAND_OMAP2
Enable dmaengine and gpiolib for better performance. Enable dmaengine and gpiolib for better performance.
config MTD_ONENAND_SAMSUNG config MTD_ONENAND_SAMSUNG
tristate "OneNAND on Samsung SOC controller support" tristate "OneNAND on Samsung SOC controller support"
depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS4 depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS4 || COMPILE_TEST
help help
Support for a OneNAND flash device connected to an Samsung SOC. Support for a OneNAND flash device connected to an Samsung SOC.
S3C64XX uses command mapping method. S3C64XX uses command mapping method.
S5PC110/S5PC210 use generic OneNAND method. S5PC110/S5PC210 use generic OneNAND method.
config MTD_ONENAND_OTP config MTD_ONENAND_OTP
bool "OneNAND OTP Support" bool "OneNAND OTP Support"
......
...@@ -8,7 +8,7 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o ...@@ -8,7 +8,7 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o
# Board specific. # Board specific.
obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o
obj-$(CONFIG_MTD_ONENAND_OMAP2) += omap2.o obj-$(CONFIG_MTD_ONENAND_OMAP2) += onenand_omap2.o
obj-$(CONFIG_MTD_ONENAND_SAMSUNG) += samsung_mtd.o obj-$(CONFIG_MTD_ONENAND_SAMSUNG) += onenand_samsung.o
onenand-objs = onenand_base.o onenand_bbt.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, ...@@ -1248,44 +1248,44 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
stats = mtd->ecc_stats; stats = mtd->ecc_stats;
/* Read-while-load method */ /* Read-while-load method */
/* Do first load to bufferRAM */ /* Do first load to bufferRAM */
if (read < len) { if (read < len) {
if (!onenand_check_bufferram(mtd, from)) { if (!onenand_check_bufferram(mtd, from)) {
this->command(mtd, ONENAND_CMD_READ, from, writesize); this->command(mtd, ONENAND_CMD_READ, from, writesize);
ret = this->wait(mtd, FL_READING); ret = this->wait(mtd, FL_READING);
onenand_update_bufferram(mtd, from, !ret); onenand_update_bufferram(mtd, from, !ret);
if (mtd_is_eccerr(ret)) if (mtd_is_eccerr(ret))
ret = 0; ret = 0;
} }
} }
thislen = min_t(int, writesize, len - read); thislen = min_t(int, writesize, len - read);
column = from & (writesize - 1); column = from & (writesize - 1);
if (column + thislen > writesize) if (column + thislen > writesize)
thislen = writesize - column; thislen = writesize - column;
while (!ret) { while (!ret) {
/* If there is more to load then start next load */ /* If there is more to load then start next load */
from += thislen; from += thislen;
if (read + thislen < len) { if (read + thislen < len) {
this->command(mtd, ONENAND_CMD_READ, from, writesize); this->command(mtd, ONENAND_CMD_READ, from, writesize);
/* /*
* Chip boundary handling in DDP * Chip boundary handling in DDP
* Now we issued chip 1 read and pointed chip 1 * Now we issued chip 1 read and pointed chip 1
* bufferram so we have to point chip 0 bufferram. * bufferram so we have to point chip 0 bufferram.
*/ */
if (ONENAND_IS_DDP(this) && if (ONENAND_IS_DDP(this) &&
unlikely(from == (this->chipsize >> 1))) { unlikely(from == (this->chipsize >> 1))) {
this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2); this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
boundary = 1; boundary = 1;
} else } else
boundary = 0; boundary = 0;
ONENAND_SET_PREV_BUFFERRAM(this); ONENAND_SET_PREV_BUFFERRAM(this);
} }
/* While load is going, read from last bufferRAM */ /* While load is going, read from last bufferRAM */
this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
/* Read oob area if needed */ /* Read oob area if needed */
if (oobbuf) { if (oobbuf) {
...@@ -1301,24 +1301,24 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, ...@@ -1301,24 +1301,24 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
oobcolumn = 0; oobcolumn = 0;
} }
/* See if we are done */ /* See if we are done */
read += thislen; read += thislen;
if (read == len) if (read == len)
break; break;
/* Set up for next read from bufferRAM */ /* Set up for next read from bufferRAM */
if (unlikely(boundary)) if (unlikely(boundary))
this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2); this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
ONENAND_SET_NEXT_BUFFERRAM(this); ONENAND_SET_NEXT_BUFFERRAM(this);
buf += thislen; buf += thislen;
thislen = min_t(int, writesize, len - read); thislen = min_t(int, writesize, len - read);
column = 0; column = 0;
cond_resched(); cond_resched();
/* Now wait for load */ /* Now wait for load */
ret = this->wait(mtd, FL_READING); ret = this->wait(mtd, FL_READING);
onenand_update_bufferram(mtd, from, !ret); onenand_update_bufferram(mtd, from, !ret);
if (mtd_is_eccerr(ret)) if (mtd_is_eccerr(ret))
ret = 0; ret = 0;
} }
/* /*
* Return success, if no ECC failures, else -EBADMSG * Return success, if no ECC failures, else -EBADMSG
......
...@@ -248,7 +248,7 @@ static unsigned short s3c_onenand_readw(void __iomem *addr) ...@@ -248,7 +248,7 @@ static unsigned short s3c_onenand_readw(void __iomem *addr)
} }
/* BootRAM access control */ /* 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) if (word_addr == 0)
return s3c_read_reg(MANUFACT_ID_OFFSET); return s3c_read_reg(MANUFACT_ID_OFFSET);
if (word_addr == 1) if (word_addr == 1)
...@@ -289,7 +289,7 @@ static void s3c_onenand_writew(unsigned short value, void __iomem *addr) ...@@ -289,7 +289,7 @@ static void s3c_onenand_writew(unsigned short value, void __iomem *addr)
} }
/* BootRAM access control */ /* BootRAM access control */
if ((unsigned int)addr < ONENAND_DATARAM) { if ((unsigned long)addr < ONENAND_DATARAM) {
if (value == ONENAND_CMD_READID) { if (value == ONENAND_CMD_READID) {
onenand->bootram_command = 1; onenand->bootram_command = 1;
return; return;
...@@ -658,7 +658,7 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, ...@@ -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); dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE);
} }
if (dma_mapping_error(dev, dma_dst)) { 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; goto normal;
} }
err = s5pc110_dma_ops(dma_dst, dma_src, err = s5pc110_dma_ops(dma_dst, dma_src,
...@@ -728,13 +728,12 @@ static void s3c_onenand_check_lock_status(struct mtd_info *mtd) ...@@ -728,13 +728,12 @@ static void s3c_onenand_check_lock_status(struct mtd_info *mtd)
struct onenand_chip *this = mtd->priv; struct onenand_chip *this = mtd->priv;
struct device *dev = &onenand->pdev->dev; struct device *dev = &onenand->pdev->dev;
unsigned int block, end; unsigned int block, end;
int tmp;
end = this->chipsize >> this->erase_shift; end = this->chipsize >> this->erase_shift;
for (block = 0; block < end; block++) { for (block = 0; block < end; block++) {
unsigned int mem_addr = onenand->mem_addr(block, 0, 0); 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) { if (s3c_read_reg(INT_ERR_STAT_OFFSET) & LOCKED_BLK) {
dev_err(dev, "block %d is write-protected!\n", block); dev_err(dev, "block %d is write-protected!\n", block);
......
...@@ -452,7 +452,7 @@ config MTD_NAND_PLATFORM ...@@ -452,7 +452,7 @@ config MTD_NAND_PLATFORM
config MTD_NAND_CADENCE config MTD_NAND_CADENCE
tristate "Support Cadence NAND (HPNFC) controller" tristate "Support Cadence NAND (HPNFC) controller"
depends on OF || COMPILE_TEST depends on (OF || COMPILE_TEST) && HAS_IOMEM
help help
Enable the driver for NAND flash on platforms using a Cadence NAND Enable the driver for NAND flash on platforms using a Cadence NAND
controller. controller.
......
...@@ -1578,9 +1578,8 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc, ...@@ -1578,9 +1578,8 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
nand->numcs = numcs; nand->numcs = numcs;
gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "det", 0, gpio = devm_fwnode_gpiod_get(nc->dev, of_fwnode_handle(np),
&np->fwnode, GPIOD_IN, "det", GPIOD_IN, "nand-det");
"nand-det");
if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) { if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
dev_err(nc->dev, dev_err(nc->dev,
"Failed to get detect gpio (err = %ld)\n", "Failed to get detect gpio (err = %ld)\n",
...@@ -1624,9 +1623,10 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc, ...@@ -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.type = ATMEL_NAND_NATIVE_RB;
nand->cs[i].rb.id = val; nand->cs[i].rb.id = val;
} else { } else {
gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, gpio = devm_fwnode_gpiod_get_index(nc->dev,
"rb", i, &np->fwnode, of_fwnode_handle(np),
GPIOD_IN, "nand-rb"); "rb", i, GPIOD_IN,
"nand-rb");
if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) { if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
dev_err(nc->dev, dev_err(nc->dev,
"Failed to get R/B gpio (err = %ld)\n", "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, ...@@ -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", gpio = devm_fwnode_gpiod_get_index(nc->dev,
i, &np->fwnode, of_fwnode_handle(np),
GPIOD_OUT_HIGH, "cs", i, GPIOD_OUT_HIGH,
"nand-cs"); "nand-cs");
if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) { if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
dev_err(nc->dev, dev_err(nc->dev,
"Failed to get CS gpio (err = %ld)\n", "Failed to get CS gpio (err = %ld)\n",
......
...@@ -2635,6 +2635,16 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) ...@@ -2635,6 +2635,16 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
/* initialize the dma version */ /* initialize the dma version */
brcmnand_flash_dma_revision_init(ctrl); 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 */ /* linked-list and stop on error */
flash_dma_writel(ctrl, FLASH_DMA_MODE, FLASH_DMA_MODE_MASK); flash_dma_writel(ctrl, FLASH_DMA_MODE, FLASH_DMA_MODE_MASK);
flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0); flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include "denali.h" #include "denali.h"
#define DENALI_NAND_NAME "denali-nand" #define DENALI_NAND_NAME "denali-nand"
#define DENALI_DEFAULT_OOB_SKIP_BYTES 8
/* for Indexed Addressing */ /* for Indexed Addressing */
#define DENALI_INDEXED_CTRL 0x00 #define DENALI_INDEXED_CTRL 0x00
...@@ -1302,15 +1301,16 @@ int denali_init(struct denali_controller *denali) ...@@ -1302,15 +1301,16 @@ int denali_init(struct denali_controller *denali)
/* /*
* Set how many bytes should be skipped before writing data in OOB. * 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), * If a platform requests a non-zero value, set it to the register.
* just use it. Otherwise, set the driver's default. * 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)
if (!denali->oob_skip_bytes) {
denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES;
iowrite32(denali->oob_skip_bytes, iowrite32(denali->oob_skip_bytes,
denali->reg + SPARE_AREA_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(0, denali->reg + TRANSFER_SPARE_REG);
iowrite32(GENMASK(denali->nbanks - 1, 0), denali->reg + RB_PIN_ENABLED); iowrite32(GENMASK(denali->nbanks - 1, 0), denali->reg + RB_PIN_ENABLED);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/ioport.h> #include <linux/ioport.h>
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset.h>
#include "denali.h" #include "denali.h"
...@@ -22,11 +24,14 @@ struct denali_dt { ...@@ -22,11 +24,14 @@ struct denali_dt {
struct clk *clk; /* core clock */ struct clk *clk; /* core clock */
struct clk *clk_x; /* bus interface clock */ struct clk *clk_x; /* bus interface clock */
struct clk *clk_ecc; /* ECC circuit 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 { struct denali_dt_data {
unsigned int revision; unsigned int revision;
unsigned int caps; unsigned int caps;
unsigned int oob_skip_bytes;
const struct nand_ecc_caps *ecc_caps; const struct nand_ecc_caps *ecc_caps;
}; };
...@@ -34,6 +39,7 @@ NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes, ...@@ -34,6 +39,7 @@ NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
512, 8, 15); 512, 8, 15);
static const struct denali_dt_data denali_socfpga_data = { static const struct denali_dt_data denali_socfpga_data = {
.caps = DENALI_CAP_HW_ECC_FIXUP, .caps = DENALI_CAP_HW_ECC_FIXUP,
.oob_skip_bytes = 2,
.ecc_caps = &denali_socfpga_ecc_caps, .ecc_caps = &denali_socfpga_ecc_caps,
}; };
...@@ -42,6 +48,7 @@ NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes, ...@@ -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 = { static const struct denali_dt_data denali_uniphier_v5a_data = {
.caps = DENALI_CAP_HW_ECC_FIXUP | .caps = DENALI_CAP_HW_ECC_FIXUP |
DENALI_CAP_DMA_64BIT, DENALI_CAP_DMA_64BIT,
.oob_skip_bytes = 8,
.ecc_caps = &denali_uniphier_v5a_ecc_caps, .ecc_caps = &denali_uniphier_v5a_ecc_caps,
}; };
...@@ -51,6 +58,7 @@ static const struct denali_dt_data denali_uniphier_v5b_data = { ...@@ -51,6 +58,7 @@ static const struct denali_dt_data denali_uniphier_v5b_data = {
.revision = 0x0501, .revision = 0x0501,
.caps = DENALI_CAP_HW_ECC_FIXUP | .caps = DENALI_CAP_HW_ECC_FIXUP |
DENALI_CAP_DMA_64BIT, DENALI_CAP_DMA_64BIT,
.oob_skip_bytes = 8,
.ecc_caps = &denali_uniphier_v5b_ecc_caps, .ecc_caps = &denali_uniphier_v5b_ecc_caps,
}; };
...@@ -118,11 +126,13 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -118,11 +126,13 @@ static int denali_dt_probe(struct platform_device *pdev)
denali = &dt->controller; denali = &dt->controller;
data = of_device_get_match_data(dev); data = of_device_get_match_data(dev);
if (data) { if (WARN_ON(!data))
denali->revision = data->revision; return -EINVAL;
denali->caps = data->caps;
denali->ecc_caps = data->ecc_caps; 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->dev = dev;
denali->irq = platform_get_irq(pdev, 0); denali->irq = platform_get_irq(pdev, 0);
...@@ -151,6 +161,14 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -151,6 +161,14 @@ static int denali_dt_probe(struct platform_device *pdev)
if (IS_ERR(dt->clk_ecc)) if (IS_ERR(dt->clk_ecc))
return PTR_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); ret = clk_prepare_enable(dt->clk);
if (ret) if (ret)
return ret; return ret;
...@@ -166,10 +184,30 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -166,10 +184,30 @@ static int denali_dt_probe(struct platform_device *pdev)
denali->clk_rate = clk_get_rate(dt->clk); denali->clk_rate = clk_get_rate(dt->clk);
denali->clk_x_rate = clk_get_rate(dt->clk_x); 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) if (ret)
goto out_disable_clk_ecc; 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) { for_each_child_of_node(dev->of_node, np) {
ret = denali_dt_chip_init(denali, np); ret = denali_dt_chip_init(denali, np);
if (ret) { if (ret) {
...@@ -184,6 +222,10 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -184,6 +222,10 @@ static int denali_dt_probe(struct platform_device *pdev)
out_remove_denali: out_remove_denali:
denali_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: out_disable_clk_ecc:
clk_disable_unprepare(dt->clk_ecc); clk_disable_unprepare(dt->clk_ecc);
out_disable_clk_x: out_disable_clk_x:
...@@ -199,6 +241,8 @@ static int denali_dt_remove(struct platform_device *pdev) ...@@ -199,6 +241,8 @@ static int denali_dt_remove(struct platform_device *pdev)
struct denali_dt *dt = platform_get_drvdata(pdev); struct denali_dt *dt = platform_get_drvdata(pdev);
denali_remove(&dt->controller); 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_ecc);
clk_disable_unprepare(dt->clk_x); clk_disable_unprepare(dt->clk_x);
clk_disable_unprepare(dt->clk); clk_disable_unprepare(dt->clk);
......
...@@ -438,7 +438,7 @@ static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset, ...@@ -438,7 +438,7 @@ static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
buffer += blksize; buffer += blksize;
offset += blksize; offset += blksize;
size -= blksize; size -= blksize;
}; }
} }
/* Copy data from/to NFC main and spare buffers */ /* Copy data from/to NFC main and spare buffers */
......
...@@ -59,7 +59,7 @@ static void macronix_nand_onfi_init(struct nand_chip *chip) ...@@ -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) static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
{ {
unsigned int i; int i;
static const char * const broken_get_timings[] = { static const char * const broken_get_timings[] = {
"MX30LF1G18AC", "MX30LF1G18AC",
"MX30LF1G28AC", "MX30LF1G28AC",
...@@ -80,12 +80,9 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip) ...@@ -80,12 +80,9 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
if (!chip->parameters.supports_set_get_features) if (!chip->parameters.supports_set_get_features)
return; return;
for (i = 0; i < ARRAY_SIZE(broken_get_timings); i++) { i = match_string(broken_get_timings, ARRAY_SIZE(broken_get_timings),
if (!strcmp(broken_get_timings[i], chip->parameters.model)) chip->parameters.model);
break; if (i < 0)
}
if (i == ARRAY_SIZE(broken_get_timings))
return; return;
bitmap_clear(chip->parameters.get_feature_list, bitmap_clear(chip->parameters.get_feature_list,
......
...@@ -124,6 +124,16 @@ static const struct spinand_info toshiba_spinand_table[] = { ...@@ -124,6 +124,16 @@ static const struct spinand_info toshiba_spinand_table[] = {
0, 0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)), 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 */ /* 1.8V 1Gb */
SPINAND_INFO("TC58CYG0S3", 0xB2, SPINAND_INFO("TC58CYG0S3", 0xB2,
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
......
...@@ -165,10 +165,10 @@ static int sharpsl_nand_get_logical_num(u8 *oob) ...@@ -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) 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; loff_t block_adr;
u8 *oob; u8 *oob;
int i, ret;
oob = kzalloc(mtd->oobsize, GFP_KERNEL); oob = kzalloc(mtd->oobsize, GFP_KERNEL);
if (!oob) if (!oob)
......
...@@ -46,11 +46,11 @@ config SPI_CADENCE_QUADSPI ...@@ -46,11 +46,11 @@ config SPI_CADENCE_QUADSPI
Flash as an MTD device. Flash as an MTD device.
config SPI_HISI_SFC 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 ARCH_HISI || COMPILE_TEST
depends on HAS_IOMEM depends on HAS_IOMEM
help help
This enables support for hisilicon SPI-NOR flash controller. This enables support for HiSilicon FMC SPI-NOR flash controller.
config SPI_MTK_QUADSPI config SPI_MTK_QUADSPI
tristate "MediaTek Quad SPI controller" tristate "MediaTek Quad SPI controller"
......
...@@ -305,7 +305,7 @@ static void aspeed_smc_stop_user(struct spi_nor *nor) ...@@ -305,7 +305,7 @@ static void aspeed_smc_stop_user(struct spi_nor *nor)
writel(ctl, chip->ctl); /* default to fread or read mode */ 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; 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) ...@@ -313,7 +313,7 @@ static int aspeed_smc_prep(struct spi_nor *nor, enum spi_nor_ops ops)
return 0; 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; struct aspeed_smc_chip *chip = nor->priv;
......
...@@ -1062,7 +1062,7 @@ static int cqspi_erase(struct spi_nor *nor, loff_t offs) ...@@ -1062,7 +1062,7 @@ static int cqspi_erase(struct spi_nor *nor, loff_t offs)
return 0; 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_flash_pdata *f_pdata = nor->priv;
struct cqspi_st *cqspi = f_pdata->cqspi; struct cqspi_st *cqspi = f_pdata->cqspi;
...@@ -1072,7 +1072,7 @@ static int cqspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) ...@@ -1072,7 +1072,7 @@ static int cqspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
return 0; 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_flash_pdata *f_pdata = nor->priv;
struct cqspi_st *cqspi = f_pdata->cqspi; struct cqspi_st *cqspi = f_pdata->cqspi;
......
// SPDX-License-Identifier: GPL-2.0-or-later // 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. * Copyright (c) 2015-2016 HiSilicon Technologies Co., Ltd.
*/ */
...@@ -144,7 +144,7 @@ static void hisi_spi_nor_init(struct hifmc_host *host) ...@@ -144,7 +144,7 @@ static void hisi_spi_nor_init(struct hifmc_host *host)
writel(reg, host->regbase + FMC_SPI_TIMING_CFG); 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_priv *priv = nor->priv;
struct hifmc_host *host = priv->host; struct hifmc_host *host = priv->host;
...@@ -167,7 +167,7 @@ static int hisi_spi_nor_prep(struct spi_nor *nor, enum spi_nor_ops ops) ...@@ -167,7 +167,7 @@ static int hisi_spi_nor_prep(struct spi_nor *nor, enum spi_nor_ops ops)
return ret; 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_priv *priv = nor->priv;
struct hifmc_host *host = priv->host; struct hifmc_host *host = priv->host;
......
...@@ -70,10 +70,12 @@ static const struct pci_device_id intel_spi_pci_ids[] = { ...@@ -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, 0x19e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x4b24), (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, 0xa0a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_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); MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
......
...@@ -85,7 +85,7 @@ struct sfdp_header { ...@@ -85,7 +85,7 @@ struct sfdp_header {
#define BFPT_DWORD(i) ((i) - 1) #define BFPT_DWORD(i) ((i) - 1)
#define BFPT_DWORD_MAX 16 #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 #define BFPT_DWORD_MAX_JESD216 9
/* 1st DWORD. */ /* 1st DWORD. */
...@@ -196,7 +196,7 @@ struct flash_info { ...@@ -196,7 +196,7 @@ struct flash_info {
u16 page_size; u16 page_size;
u16 addr_width; u16 addr_width;
u16 flags; u32 flags;
#define SECT_4K BIT(0) /* SPINOR_OP_BE_4K works uniformly */ #define SECT_4K BIT(0) /* SPINOR_OP_BE_4K works uniformly */
#define SPI_NOR_NO_ERASE BIT(1) /* No erase command needed */ #define SPI_NOR_NO_ERASE BIT(1) /* No erase command needed */
#define SST_WRITE BIT(2) /* use SST byte programming */ #define SST_WRITE BIT(2) /* use SST byte programming */
...@@ -233,6 +233,11 @@ struct flash_info { ...@@ -233,6 +233,11 @@ struct flash_info {
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
#define USE_CLSR BIT(14) /* use CLSR command */ #define USE_CLSR BIT(14) /* use CLSR command */
#define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */ #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. */ /* Part specific fixup hooks. */
const struct spi_nor_fixups *fixups; const struct spi_nor_fixups *fixups;
...@@ -1307,14 +1312,14 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor) ...@@ -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; int ret = 0;
mutex_lock(&nor->lock); mutex_lock(&nor->lock);
if (nor->controller_ops && nor->controller_ops->prepare) { if (nor->controller_ops && nor->controller_ops->prepare) {
ret = nor->controller_ops->prepare(nor, ops); ret = nor->controller_ops->prepare(nor);
if (ret) { if (ret) {
mutex_unlock(&nor->lock); mutex_unlock(&nor->lock);
return ret; return ret;
...@@ -1323,10 +1328,10 @@ static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops) ...@@ -1323,10 +1328,10 @@ static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
return ret; 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) if (nor->controller_ops && nor->controller_ops->unprepare)
nor->controller_ops->unprepare(nor, ops); nor->controller_ops->unprepare(nor);
mutex_unlock(&nor->lock); mutex_unlock(&nor->lock);
} }
...@@ -1688,7 +1693,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -1688,7 +1693,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
addr = instr->addr; addr = instr->addr;
len = instr->len; len = instr->len;
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_ERASE); ret = spi_nor_lock_and_prep(nor);
if (ret) if (ret)
return ret; return ret;
...@@ -1751,7 +1756,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -1751,7 +1756,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
ret = spi_nor_write_disable(nor); ret = spi_nor_write_disable(nor);
erase_err: erase_err:
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); spi_nor_unlock_and_unprep(nor);
return ret; return ret;
} }
...@@ -1761,9 +1766,13 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs, ...@@ -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; struct mtd_info *mtd = &nor->mtd;
u8 mask = SR_BP2 | SR_BP1 | SR_BP0; u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
u8 tb_mask = SR_TB_BIT5;
int shift = ffs(mask) - 1; int shift = ffs(mask) - 1;
int pow; int pow;
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
tb_mask = SR_TB_BIT6;
if (!(sr & mask)) { if (!(sr & mask)) {
/* No protection */ /* No protection */
*ofs = 0; *ofs = 0;
...@@ -1771,7 +1780,7 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs, ...@@ -1771,7 +1780,7 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
} else { } else {
pow = ((sr & mask) ^ mask) >> shift; pow = ((sr & mask) ^ mask) >> shift;
*len = mtd->size >> pow; *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; *ofs = 0;
else else
*ofs = mtd->size - *len; *ofs = mtd->size - *len;
...@@ -1850,6 +1859,7 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t 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; struct mtd_info *mtd = &nor->mtd;
int ret, status_old, status_new; int ret, status_old, status_new;
u8 mask = SR_BP2 | SR_BP1 | SR_BP0; u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
u8 tb_mask = SR_TB_BIT5;
u8 shift = ffs(mask) - 1, pow, val; u8 shift = ffs(mask) - 1, pow, val;
loff_t lock_len; loff_t lock_len;
bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; 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) ...@@ -1886,6 +1896,9 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
else else
lock_len = ofs + len; lock_len = ofs + len;
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
tb_mask = SR_TB_BIT6;
/* /*
* Need smallest pow such that: * Need smallest pow such that:
* *
...@@ -1903,13 +1916,13 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) ...@@ -1903,13 +1916,13 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
if (!(val & mask)) if (!(val & mask))
return -EINVAL; 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 */ /* Disallow further writes if WP pin is asserted */
status_new |= SR_SRWD; status_new |= SR_SRWD;
if (!use_top) if (!use_top)
status_new |= SR_TB; status_new |= tb_mask;
/* Don't bother if they're the same */ /* Don't bother if they're the same */
if (status_new == status_old) if (status_new == status_old)
...@@ -1932,6 +1945,7 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) ...@@ -1932,6 +1945,7 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
struct mtd_info *mtd = &nor->mtd; struct mtd_info *mtd = &nor->mtd;
int ret, status_old, status_new; int ret, status_old, status_new;
u8 mask = SR_BP2 | SR_BP1 | SR_BP0; u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
u8 tb_mask = SR_TB_BIT5;
u8 shift = ffs(mask) - 1, pow, val; u8 shift = ffs(mask) - 1, pow, val;
loff_t lock_len; loff_t lock_len;
bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; 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) ...@@ -1968,6 +1982,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
else else
lock_len = ofs; lock_len = ofs;
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
tb_mask = SR_TB_BIT6;
/* /*
* Need largest pow such that: * Need largest pow such that:
* *
...@@ -1987,14 +2003,14 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) ...@@ -1987,14 +2003,14 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
return -EINVAL; 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 */ /* Don't protect status register if we're fully unlocked */
if (lock_len == 0) if (lock_len == 0)
status_new &= ~SR_SRWD; status_new &= ~SR_SRWD;
if (!use_top) if (!use_top)
status_new |= SR_TB; status_new |= tb_mask;
/* Don't bother if they're the same */ /* Don't bother if they're the same */
if (status_new == status_old) if (status_new == status_old)
...@@ -2036,13 +2052,13 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -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); struct spi_nor *nor = mtd_to_spi_nor(mtd);
int ret; int ret;
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); ret = spi_nor_lock_and_prep(nor);
if (ret) if (ret)
return ret; return ret;
ret = nor->params.locking_ops->lock(nor, ofs, len); 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; return ret;
} }
...@@ -2051,13 +2067,13 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -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); struct spi_nor *nor = mtd_to_spi_nor(mtd);
int ret; int ret;
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); ret = spi_nor_lock_and_prep(nor);
if (ret) if (ret)
return ret; return ret;
ret = nor->params.locking_ops->unlock(nor, ofs, len); 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; return ret;
} }
...@@ -2066,13 +2082,13 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -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); struct spi_nor *nor = mtd_to_spi_nor(mtd);
int ret; int ret;
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); ret = spi_nor_lock_and_prep(nor);
if (ret) if (ret)
return ret; return ret;
ret = nor->params.locking_ops->is_locked(nor, ofs, len); 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; return ret;
} }
...@@ -2309,6 +2325,9 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -2309,6 +2325,9 @@ static const struct flash_info spi_nor_ids[] = {
{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) },
{ "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, 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) }, { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) },
{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
...@@ -2373,6 +2392,11 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -2373,6 +2392,11 @@ static const struct flash_info spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) 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, "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
...@@ -2381,7 +2405,8 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -2381,7 +2405,8 @@ static const struct flash_info spi_nor_ids[] = {
{ {
"gd25q256", INFO(0xc84019, 0, 64 * 1024, 512, "gd25q256", INFO(0xc84019, 0, 64 * 1024, 512,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | 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, .fixups = &gd25q256_fixups,
}, },
...@@ -2436,6 +2461,8 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -2436,6 +2461,8 @@ static const struct flash_info spi_nor_ids[] = {
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256, { "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512,
...@@ -2456,20 +2483,35 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -2456,20 +2483,35 @@ static const struct flash_info spi_nor_ids[] = {
{ "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | 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) }, { "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K |
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K |
{ "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, 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) }, { "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) }, { "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) }, { "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, { "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096,
SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SECT_4K | USE_FSR | SPI_NOR_QUAD_READ |
NO_CHIP_ERASE) }, 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) }, { "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
/* Micron */ /* Micron */
...@@ -2540,6 +2582,8 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -2540,6 +2582,8 @@ static const struct flash_info spi_nor_ids[] = {
{ "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, { "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
{ "sst26wf016b", INFO(0xbf2651, 0, 64 * 1024, 32, SECT_4K | { "sst26wf016b", INFO(0xbf2651, 0, 64 * 1024, 32, SECT_4K |
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, 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) }, { "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 */ /* ST Microelectronics -- newer production may have feature updates */
...@@ -2610,6 +2654,11 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -2610,6 +2654,11 @@ static const struct flash_info spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) 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) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 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[] = { ...@@ -2630,7 +2679,9 @@ static const struct flash_info spi_nor_ids[] = {
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | 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, { "w25q256jvm", INFO(0xef7019, 0, 64 * 1024, 512,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "w25q256jw", INFO(0xef6019, 0, 64 * 1024, 512, { "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, ...@@ -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); 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) if (ret)
return ret; return ret;
...@@ -2728,7 +2779,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -2728,7 +2779,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
ret = 0; ret = 0;
read_err: read_err:
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ); spi_nor_unlock_and_unprep(nor);
return ret; return ret;
} }
...@@ -2741,7 +2792,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -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); 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) if (ret)
return ret; return ret;
...@@ -2814,7 +2865,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -2814,7 +2865,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
} }
out: out:
*retlen += actual; *retlen += actual;
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); spi_nor_unlock_and_unprep(nor);
return ret; return ret;
} }
...@@ -2832,7 +2883,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -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); 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) if (ret)
return ret; return ret;
...@@ -2878,7 +2929,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -2878,7 +2929,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
} }
write_err: write_err:
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); spi_nor_unlock_and_unprep(nor);
return ret; return ret;
} }
...@@ -5143,8 +5194,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, ...@@ -5143,8 +5194,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (info->flags & USE_FSR) if (info->flags & USE_FSR)
nor->flags |= SNOR_F_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; 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) if (info->flags & NO_CHIP_ERASE)
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
if (info->flags & USE_CLSR) if (info->flags & USE_CLSR)
......
...@@ -128,7 +128,8 @@ ...@@ -128,7 +128,8 @@
#define SR_BP0 BIT(2) /* Block protect 0 */ #define SR_BP0 BIT(2) /* Block protect 0 */
#define SR_BP1 BIT(3) /* Block protect 1 */ #define SR_BP1 BIT(3) /* Block protect 1 */
#define SR_BP2 BIT(4) /* Block protect 2 */ #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 */ #define SR_SRWD BIT(7) /* SR write protect */
/* Spansion/Cypress specific status bits */ /* Spansion/Cypress specific status bits */
#define SR_E_ERR BIT(5) #define SR_E_ERR BIT(5)
...@@ -224,14 +225,6 @@ static inline u8 spi_nor_get_protocol_width(enum spi_nor_protocol proto) ...@@ -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); 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 { enum spi_nor_option_flags {
SNOR_F_USE_FSR = BIT(0), SNOR_F_USE_FSR = BIT(0),
SNOR_F_HAS_SR_TB = BIT(1), SNOR_F_HAS_SR_TB = BIT(1),
...@@ -244,6 +237,7 @@ enum spi_nor_option_flags { ...@@ -244,6 +237,7 @@ enum spi_nor_option_flags {
SNOR_F_HAS_LOCK = BIT(8), SNOR_F_HAS_LOCK = BIT(8),
SNOR_F_HAS_16BIT_SR = BIT(9), SNOR_F_HAS_16BIT_SR = BIT(9),
SNOR_F_NO_READ_CR = BIT(10), SNOR_F_NO_READ_CR = BIT(10),
SNOR_F_HAS_SR_TB_BIT6 = BIT(11),
}; };
...@@ -483,8 +477,8 @@ struct spi_nor; ...@@ -483,8 +477,8 @@ struct spi_nor;
* opcode via write_reg(). * opcode via write_reg().
*/ */
struct spi_nor_controller_ops { struct spi_nor_controller_ops {
int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); int (*prepare)(struct spi_nor *nor);
void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops); void (*unprepare)(struct spi_nor *nor);
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, size_t len); 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, int (*write_reg)(struct spi_nor *nor, u8 opcode, const u8 *buf,
size_t len); size_t len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment