diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-23 01:09:22 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-23 01:09:22 +0100 |
commit | a36cf6865120d7534fcb132d311f03e5159f2da7 (patch) | |
tree | 1c9beded305965ce4493502e9873ffb43bf04880 /drivers/mtd | |
parent | b8e445b6895cfe76c5959a7135a3216703fe32d4 (diff) | |
parent | 042c1a5a6021f73c10dc84958c287eb2a2a26f7c (diff) |
Merge tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd
Pull mtd updates from Boris Brezillon:
"SPI NOR core changes:
- Support non-uniform erase size
- Support controllers with limited TX fifo size
Driver changes:
- m25p80: Re-issue a WREN command after each write access
- cadence: Pass a proper dir value to dma_[un]map_single()
- fsl-qspi: Check fsl_qspi_get_seqid() return val make sure 4B
addressing opcodes are properly handled
- intel-spi: Add a new PCI entry for Ice Lake
Raw NAND core changes:
- Two batchs of cleanups of the NAND API, including:
* Deprecating a lot of interfaces (now replaced by ->exec_op()).
* Moving code in separate drivers (JEDEC, ONFI), in private files
(internals), in platform drivers, etc.
* Functions/structures reordering.
* Exclusive use of the nand_chip structure instead of the MTD one
all across the subsystem.
- Addition of the nand_wait_readrdy/rdy_op() helpers.
Raw NAND controllers drivers changes:
- Various coccinelle patches.
- Marvell:
* Use regmap_update_bits() for syscon access.
* More documentation.
* BCH failure path rework.
* More layouts to be supported.
* IRQ handler complete() condition fixed.
- Fsl_ifc:
* SRAM initialization fixed for newer controller versions.
- Denali:
* Fix licenses mismatch and use a SPDX tag.
* Set SPARE_AREA_SKIP_BYTES register to 8 if unset.
- Qualcomm:
* Do not include dma-direct.h.
- Docg4:
* Removed.
- Ams-delta:
* Use of a GPIO lookup table
* Internal machinery changes.
Raw NAND chip drivers changes:
- Toshiba:
* Add support for Toshiba memory BENAND
* Pass a single nand_chip object to the status helper.
- ESMT:
* New driver to retrieve the ECC requirements from the 5th ID
byte.
MTD changes:
- physmap cleanups/fixe
- gpio-addr-flash cleanups/fixes"
* tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd: (93 commits)
jffs2: free jffs2_sb_info through jffs2_kill_sb()
mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
mtd: spi-nor: intel-spi: Add support for Intel Ice Lake SPI serial flash
mtd: maps: gpio-addr-flash: Convert to gpiod
mtd: maps: gpio-addr-flash: Replace array with an integer
mtd: maps: gpio-addr-flash: Use order instead of size
mtd: spi-nor: fsl-quadspi: Don't let -EINVAL on the bus
mtd: devices: m25p80: Make sure WRITE_EN is issued before each write
mtd: spi-nor: Support controllers with limited TX FIFO size
mtd: spi-nor: cadence-quadspi: Use proper enum for dma_[un]map_single
mtd: spi-nor: parse SFDP Sector Map Parameter Table
mtd: spi-nor: add support to non-uniform SFDP SPI NOR flash memories
mtd: rawnand: marvell: fix the IRQ handler complete() condition
mtd: rawnand: denali: set SPARE_AREA_SKIP_BYTES register to 8 if unset
mtd: rawnand: r852: fix spelling mistake "card_registred" -> "card_registered"
mtd: rawnand: toshiba: Pass a single nand_chip object to the status helper
mtd: maps: gpio-addr-flash: Use devm_* functions
mtd: maps: gpio-addr-flash: Fix ioremapped size
mtd: maps: gpio-addr-flash: Replace custom printk
mtd: physmap_of: Release resources on error
...
Diffstat (limited to 'drivers/mtd')
85 files changed, 4644 insertions, 5150 deletions
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 270d3c9580c5..c4a1d04b8c80 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -90,7 +90,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, SPI_MEM_OP_ADDR(nor->addr_width, to, 1), SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_OUT(len, buf, 1)); - size_t remaining = len; int ret; /* get transfer protocols. */ @@ -101,22 +100,16 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) op.addr.nbytes = 0; - while (remaining) { - op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX; - ret = spi_mem_adjust_op_size(flash->spimem, &op); - if (ret) - return ret; - - ret = spi_mem_exec_op(flash->spimem, &op); - if (ret) - return ret; + ret = spi_mem_adjust_op_size(flash->spimem, &op); + if (ret) + return ret; + op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes; - op.addr.val += op.data.nbytes; - remaining -= op.data.nbytes; - op.data.buf.out += op.data.nbytes; - } + ret = spi_mem_exec_op(flash->spimem, &op); + if (ret) + return ret; - return len; + return op.data.nbytes; } /* diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 9d9723693217..a20e85aa770e 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -14,6 +14,7 @@ */ #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> @@ -25,28 +26,24 @@ #include <linux/slab.h> #include <linux/types.h> -#define pr_devinit(fmt, args...) \ - ({ static const char __fmt[] = fmt; printk(__fmt, ## args); }) +#define win_mask(x) ((BIT(x)) - 1) #define DRIVER_NAME "gpio-addr-flash" -#define PFX DRIVER_NAME ": " /** * struct async_state - keep GPIO flash state * @mtd: MTD state for this mapping * @map: MTD map state for this flash - * @gpio_count: number of GPIOs used to address - * @gpio_addrs: array of GPIOs to twiddle + * @gpios: Struct containing the array of GPIO descriptors * @gpio_values: cached GPIO values - * @win_size: dedicated memory size (if no GPIOs) + * @win_order: dedicated memory size (if no GPIOs) */ struct async_state { struct mtd_info *mtd; struct map_info map; - size_t gpio_count; - unsigned *gpio_addrs; - int *gpio_values; - unsigned long win_size; + struct gpio_descs *gpios; + unsigned int gpio_values; + unsigned int win_order; }; #define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1) @@ -57,21 +54,25 @@ struct async_state { * * Rather than call the GPIO framework every time, cache the last-programmed * value. This speeds up sequential accesses (which are by far the most common - * type). We rely on the GPIO framework to treat non-zero value as high so - * that we don't have to normalize the bits. + * type). */ static void gf_set_gpios(struct async_state *state, unsigned long ofs) { - size_t i = 0; - int value; - ofs /= state->win_size; - do { - value = ofs & (1 << i); - if (state->gpio_values[i] != value) { - gpio_set_value(state->gpio_addrs[i], value); - state->gpio_values[i] = value; - } - } while (++i < state->gpio_count); + int i; + + ofs >>= state->win_order; + + if (ofs == state->gpio_values) + return; + + for (i = 0; i < state->gpios->ndescs; i++) { + if ((ofs & BIT(i)) == (state->gpio_values & BIT(i))) + continue; + + gpiod_set_value(state->gpios->desc[i], !!(ofs & BIT(i))); + } + + state->gpio_values = ofs; } /** @@ -87,7 +88,7 @@ static map_word gf_read(struct map_info *map, unsigned long ofs) gf_set_gpios(state, ofs); - word = readw(map->virt + (ofs % state->win_size)); + word = readw(map->virt + (ofs & win_mask(state->win_order))); test.x[0] = word; return test; } @@ -109,14 +110,14 @@ static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssi int this_len; while (len) { - if ((from % state->win_size) + len > state->win_size) - this_len = state->win_size - (from % state->win_size); - else - this_len = len; + this_len = from & win_mask(state->win_order); + this_len = BIT(state->win_order) - this_len; + this_len = min_t(int, len, this_len); gf_set_gpios(state, from); - memcpy_fromio(to, map->virt + (from % state->win_size), - this_len); + memcpy_fromio(to, + map->virt + (from & win_mask(state->win_order)), + this_len); len -= this_len; from += this_len; to += this_len; @@ -136,7 +137,7 @@ static void gf_write(struct map_info *map, map_word d1, unsigned long ofs) gf_set_gpios(state, ofs); d = d1.x[0]; - writew(d, map->virt + (ofs % state->win_size)); + writew(d, map->virt + (ofs & win_mask(state->win_order))); } /** @@ -156,13 +157,13 @@ static void gf_copy_to(struct map_info *map, unsigned long to, int this_len; while (len) { - if ((to % state->win_size) + len > state->win_size) - this_len = state->win_size - (to % state->win_size); - else - this_len = len; + this_len = to & win_mask(state->win_order); + this_len = BIT(state->win_order) - this_len; + this_len = min_t(int, len, this_len); gf_set_gpios(state, to); - memcpy_toio(map->virt + (to % state->win_size), from, len); + memcpy_toio(map->virt + (to & win_mask(state->win_order)), + from, len); len -= this_len; to += this_len; @@ -180,18 +181,22 @@ static const char * const part_probe_types[] = { * The platform resource layout expected looks something like: * struct mtd_partition partitions[] = { ... }; * struct physmap_flash_data flash_data = { ... }; - * unsigned flash_gpios[] = { GPIO_XX, GPIO_XX, ... }; + * static struct gpiod_lookup_table addr_flash_gpios = { + * .dev_id = "gpio-addr-flash.0", + * .table = { + * GPIO_LOOKUP_IDX("gpio.0", 15, "addr", 0, GPIO_ACTIVE_HIGH), + * GPIO_LOOKUP_IDX("gpio.0", 16, "addr", 1, GPIO_ACTIVE_HIGH), + * ); + * }; + * gpiod_add_lookup_table(&addr_flash_gpios); + * * struct resource flash_resource[] = { * { * .name = "cfi_probe", * .start = 0x20000000, * .end = 0x201fffff, * .flags = IORESOURCE_MEM, - * }, { - * .start = (unsigned long)flash_gpios, - * .end = ARRAY_SIZE(flash_gpios), - * .flags = IORESOURCE_IRQ, - * } + * }, * }; * struct platform_device flash_device = { * .name = "gpio-addr-flash", @@ -203,33 +208,25 @@ static const char * const part_probe_types[] = { */ static int gpio_flash_probe(struct platform_device *pdev) { - size_t i, arr_size; struct physmap_flash_data *pdata; struct resource *memory; - struct resource *gpios; struct async_state *state; pdata = dev_get_platdata(&pdev->dev); memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); - gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!memory || !gpios || !gpios->end) + if (!memory) return -EINVAL; - arr_size = sizeof(int) * gpios->end; - state = kzalloc(sizeof(*state) + arr_size, GFP_KERNEL); + state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; - /* - * We cast start/end to known types in the boards file, so cast - * away their pointer types here to the known types (gpios->xxx). - */ - state->gpio_count = gpios->end; - state->gpio_addrs = (void *)(unsigned long)gpios->start; - state->gpio_values = (void *)(state + 1); - state->win_size = resource_size(memory); - memset(state->gpio_values, 0xff, arr_size); + state->gpios = devm_gpiod_get_array(&pdev->dev, "addr", GPIOD_OUT_LOW); + if (IS_ERR(state->gpios)) + return PTR_ERR(state->gpios); + + state->win_order = get_bitmask_order(resource_size(memory)) - 1; state->map.name = DRIVER_NAME; state->map.read = gf_read; @@ -237,38 +234,21 @@ static int gpio_flash_probe(struct platform_device *pdev) state->map.write = gf_write; state->map.copy_to = gf_copy_to; state->map.bankwidth = pdata->width; - state->map.size = state->win_size * (1 << state->gpio_count); - state->map.virt = ioremap_nocache(memory->start, state->map.size); - if (!state->map.virt) - return -ENOMEM; + state->map.size = BIT(state->win_order + state->gpios->ndescs); + state->map.virt = devm_ioremap_resource(&pdev->dev, memory); + if (IS_ERR(state->map.virt)) + return PTR_ERR(state->map.virt); state->map.phys = NO_XIP; state->map.map_priv_1 = (unsigned long)state; platform_set_drvdata(pdev, state); - i = 0; - do { - if (gpio_request(state->gpio_addrs[i], DRIVER_NAME)) { - pr_devinit(KERN_ERR PFX "failed to request gpio %d\n", - state->gpio_addrs[i]); - while (i--) - gpio_free(state->gpio_addrs[i]); - kfree(state); - return -EBUSY; - } - gpio_direction_output(state->gpio_addrs[i], 0); - } while (++i < state->gpio_count); - - pr_devinit(KERN_NOTICE PFX "probing %d-bit flash bus\n", - state->map.bankwidth * 8); + dev_notice(&pdev->dev, "probing %d-bit flash bus\n", + state->map.bankwidth * 8); state->mtd = do_map_probe(memory->name, &state->map); - if (!state->mtd) { - for (i = 0; i < state->gpio_count; ++i) - gpio_free(state->gpio_addrs[i]); - kfree(state); + if (!state->mtd) return -ENXIO; - } state->mtd->dev.parent = &pdev->dev; mtd_device_parse_register(state->mtd, part_probe_types, NULL, @@ -280,13 +260,9 @@ static int gpio_flash_probe(struct platform_device *pdev) static int gpio_flash_remove(struct platform_device *pdev) { struct async_state *state = platform_get_drvdata(pdev); - size_t i = 0; - do { - gpio_free(state->gpio_addrs[i]); - } while (++i < state->gpio_count); + mtd_device_unregister(state->mtd); map_destroy(state->mtd); - kfree(state); return 0; } diff --git a/drivers/mtd/maps/physmap_of_core.c b/drivers/mtd/maps/physmap_of_core.c index 4129535b8e46..ece605d78c21 100644 --- a/drivers/mtd/maps/physmap_of_core.c +++ b/drivers/mtd/maps/physmap_of_core.c @@ -31,7 +31,6 @@ struct of_flash_list { struct mtd_info *mtd; struct map_info map; - struct resource *res; }; struct of_flash { @@ -56,18 +55,10 @@ static int of_flash_remove(struct platform_device *dev) mtd_concat_destroy(info->cmtd); } - for (i = 0; i < info->list_size; i++) { + for (i = 0; i < info->list_size; i++) if (info->list[i].mtd) map_destroy(info->list[i].mtd); - if (info->list[i].map.virt) - iounmap(info->list[i].map.virt); - - if (info->list[i].res) { - release_resource(info->list[i].res); - kfree(info->list[i].res); - } - } return 0; } @@ -215,10 +206,11 @@ static int of_flash_probe(struct platform_device *dev) err = -EBUSY; res_size = resource_size(&res); - info->list[i].res = request_mem_region(res.start, res_size, - dev_name(&dev->dev)); - if (!info->list[i].res) + info->list[i].map.virt = devm_ioremap_resource(&dev->dev, &res); + if (IS_ERR(info->list[i].map.virt |