diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt index b32aed1db46d..98916a84bbf6 100644 --- a/Documentation/devicetree/bindings/mtd/denali-nand.txt +++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt @@ -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 { diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 410a321682e6..36aa082f6db0 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -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; diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 70bb403f69f7..2ac79e1cedd9 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -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); } diff --git a/drivers/mtd/maps/physmap-core.c b/drivers/mtd/maps/physmap-core.c index a9f7964e2edb..8f7f966fa9a7 100644 --- a/drivers/mtd/maps/physmap-core.c +++ b/drivers/mtd/maps/physmap-core.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #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; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 170a7221b35f..1d6c9e7e7b7d 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -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); diff --git a/drivers/mtd/nand/onenand/Kconfig b/drivers/mtd/nand/onenand/Kconfig index ae0b8fe5b990..572b8fe69abb 100644 --- a/drivers/mtd/nand/onenand/Kconfig +++ b/drivers/mtd/nand/onenand/Kconfig @@ -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" diff --git a/drivers/mtd/nand/onenand/Makefile b/drivers/mtd/nand/onenand/Makefile index a27b635eb23a..a0761c7e0288 100644 --- a/drivers/mtd/nand/onenand/Makefile +++ b/drivers/mtd/nand/onenand/Makefile @@ -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 diff --git a/drivers/mtd/nand/onenand/onenand_base.c b/drivers/mtd/nand/onenand/onenand_base.c index 85640ee11c86..d5326d19b136 100644 --- a/drivers/mtd/nand/onenand/onenand_base.c +++ b/drivers/mtd/nand/onenand/onenand_base.c @@ -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 diff --git a/drivers/mtd/nand/onenand/omap2.c b/drivers/mtd/nand/onenand/onenand_omap2.c similarity index 100% rename from drivers/mtd/nand/onenand/omap2.c rename to drivers/mtd/nand/onenand/onenand_omap2.c diff --git a/drivers/mtd/nand/onenand/samsung_mtd.c b/drivers/mtd/nand/onenand/onenand_samsung.c similarity index 99% rename from drivers/mtd/nand/onenand/samsung_mtd.c rename to drivers/mtd/nand/onenand/onenand_samsung.c index beb7987e4c2b..87b28e397d67 100644 --- a/drivers/mtd/nand/onenand/samsung_mtd.c +++ b/drivers/mtd/nand/onenand/onenand_samsung.c @@ -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); diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 74fb91adeb46..a80a46bb5b8b 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -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. diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 8d6be90a6fe8..3ba17a98df4d 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -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", diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 1a66b1cd51c0..44518dada75b 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -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); diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 3102ddbd8abd..fafd0a0aa8e2 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -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); diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c index 8b779a899dcf..f08740ae282b 100644 --- a/drivers/mtd/nand/raw/denali_dt.c +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #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); diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index 8b90def6686f..a2fcb739e5f8 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -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 */ diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index 58511aeb0c9a..3ff7ce00cbdb 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -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, diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c index 1cb3760ff779..0db5ee4e82af 100644 --- a/drivers/mtd/nand/spi/toshiba.c +++ b/drivers/mtd/nand/spi/toshiba.c @@ -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), diff --git a/drivers/mtd/parsers/sharpslpart.c b/drivers/mtd/parsers/sharpslpart.c index e5ea6127ab5a..671a61845bd5 100644 --- a/drivers/mtd/parsers/sharpslpart.c +++ b/drivers/mtd/parsers/sharpslpart.c @@ -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) diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index f237fcdf7f86..c1eda67d1ad2 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -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" diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c index 2b7cabbb680c..395127349aa8 100644 --- a/drivers/mtd/spi-nor/aspeed-smc.c +++ b/drivers/mtd/spi-nor/aspeed-smc.c @@ -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; diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index 06f997247d0f..494dcab4aaaa 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -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; diff --git a/drivers/mtd/spi-nor/hisi-sfc.c b/drivers/mtd/spi-nor/hisi-sfc.c index a1258216f89d..6c7a4118752e 100644 --- a/drivers/mtd/spi-nor/hisi-sfc.c +++ b/drivers/mtd/spi-nor/hisi-sfc.c @@ -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; diff --git a/drivers/mtd/spi-nor/intel-spi-pci.c b/drivers/mtd/spi-nor/intel-spi-pci.c index 3d8987baea2a..81329f680bec 100644 --- a/drivers/mtd/spi-nor/intel-spi-pci.c +++ b/drivers/mtd/spi-nor/intel-spi-pci.c @@ -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); diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b0cd443dd758..4fc632ec18fe 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -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) diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 5a4623fc586b..5abd91cc6dfa 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -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);