diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-04-26 16:16:09 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-04-26 16:16:09 -0700 |
commit | 070a7252d21b8e8900ee8540f82f0f1a348f8816 (patch) | |
tree | 4383b804e188d40f0004f96229a5f312b3b7860d /drivers/mtd/parsers/ofpart_core.c | |
parent | e19eede54240d64b4baf9b0df4dfb8191f7ae48b (diff) | |
parent | a881537dfaf281bfcb94313d69dcf9ef8fc89afe (diff) |
Merge tag 'mtd/for-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull mtd updates from Miquel Raynal:
"MTD core:
- Handle possible -EPROBE_DEFER from parse_mtd_partitions()
- Constify buf in mtd_write_user_prot_reg()
- Constify name param in mtd_bdi_init
- Fix fall-through warnings for Clang
- Get rid of Big MTD Lock ouf of mtdchar
- Drop mtd_mutex usage from mtdchar_open()
- Don't lock when recursively deleting partitions
- Use module_mtd_blktrans() to register driver when relevant
- Parse MTD as NVMEM cells
- New OTP (one-time-programmable) erase ioctl
- Require write permissions for locking and badblock ioctls
- physmap:
- Fix error return code of physmap_flash_remove()
- physmap-bt1-rom: Fix unintentional stack access
- ofpart parser:
- Support Linksys Northstar partitions
- Make symbol 'bcm4908_partitions_quirks' static
- Limit parsing of deprecated DT syntax
- Support BCM4908 fixed partitions
- Qcom parser:
- Incompatible with spi-nor 4k sectors
- Fix error condition
- Extend Qcom SMEM parser to SPI flash
CFI:
- Disable broken buffered writes for CFI chips within ID 0x2201
- Address a Coverity report for unused value
SPI NOR core:
- Add OTP support
- Fix module unload while an op in progress
- Add various cleanup patches
- Add Michael and Pratyush as designated reviewers in MAINTAINERS
SPI NOR controller drivers:
- intel-spi:
- Move platform data header to x86 subfolder
NAND core:
- Fix error handling in nand_prog_page_op() (x2)
- Add a helper to retrieve the number of ECC bytes per step
- Add a helper to retrieve the number of ECC steps
- Let ECC engines advertize the exact number of steps
- ECC Hamming:
- Populate the public nsteps field
- Use the public nsteps field
- ECC BCH:
- Populate the public nsteps field
- Use the public nsteps field
Raw NAND core:
- Add support for secure regions in NAND memory
- Try not to use the ECC private structures
- Remove duplicate include in rawnand.h
- BBT:
- Skip bad blocks when searching for the BBT in NAND (APPLIED THEN REVERTED)
Raw NAND controller drivers:
- Qcom:
- Convert bindings to YAML
- Use dma_mapping_error() for error check
- Add missing nand_cleanup() in error path
- Return actual error code instead of -ENODEV
- Update last code word register
- Add helper to configure location register
- Rename parameter name in macro
- Add helper to check last code word
- Convert nandc to chip in Read/Write helper
- Update register macro name for 0x2c offset
- GPMI:
- Fix a double free in gpmi_nand_init
- Rockchip:
- Use flexible-array member instead of zero-length array
- Atmel:
- Update ecc_stats.corrected counter
- MXC:
- Remove unneeded of_match_ptr()
- R852:
- replace spin_lock_irqsave by spin_lock in hard IRQ
- Brcmnand:
- Move to polling in pio mode on oops write
- Read/write oob during EDU transfer
- Fix OOB R/W with Hamming ECC
- FSMC:
- Fix error code in fsmc_nand_probe()
- OMAP:
- Use ECC information from the generic structures
SPI-NAND core:
- Add missing MODULE_DEVICE_TABLE()
SPI-NAND drivers:
- gigadevice: Support GD5F1GQ5UExxG"
* tag 'mtd/for-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (89 commits)
Revert "mtd: rawnand: bbt: Skip bad blocks when searching for the BBT in NAND"
mtd: core: Constify buf in mtd_write_user_prot_reg()
Revert "mtd: spi-nor: macronix: Add support for mx25l51245g"
mtd: spi-nor: core: Fix an issue of releasing resources during read/write
mtd: cfi_cmdset_0002: remove redundant assignment to variable timeo
mtd: cfi_cmdset_0002: Disable buffered writes for AMD chip 0x2201
mtd: rawnand: qcom: Use dma_mapping_error() for error check
mtd: rawnand: gpmi: Fix a double free in gpmi_nand_init
mtd: rawnand: qcom: Add missing nand_cleanup() in error path
mtd: rawnand: Add support for secure regions in NAND memory
dt-bindings: mtd: Add a property to declare secure regions in NAND chips
dt-bindings: mtd: Convert Qcom NANDc binding to YAML
mtd: spi-nor: winbond: add OTP support to w25q32fw/jw
mtd: spi-nor: implement OTP support for Winbond and similar flashes
mtd: spi-nor: add OTP support
mtd: spi-nor: swp: Improve code around spi_nor_check_lock_status_sr()
mtd: spi-nor: Move Software Write Protection logic out of the core
mtd: rawnand: bbt: Skip bad blocks when searching for the BBT in NAND
include: linux: mtd: Remove duplicate include of nand.h
mtd: parsers: ofpart: support Linksys Northstar partitions
...
Diffstat (limited to 'drivers/mtd/parsers/ofpart_core.c')
-rw-r--r-- | drivers/mtd/parsers/ofpart_core.c | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c new file mode 100644 index 000000000000..0fd8d2a0db97 --- /dev/null +++ b/drivers/mtd/parsers/ofpart_core.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Flash partitions described by the OF (or flattened) device tree + * + * Copyright © 2006 MontaVista Software Inc. + * Author: Vitaly Wool <vwool@ru.mvista.com> + * + * Revised to handle newer style flash binding by: + * Copyright © 2007 David Gibson, IBM Corporation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/of.h> +#include <linux/mtd/mtd.h> +#include <linux/slab.h> +#include <linux/mtd/partitions.h> + +#include "ofpart_bcm4908.h" +#include "ofpart_linksys_ns.h" + +struct fixed_partitions_quirks { + int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts); +}; + +static struct fixed_partitions_quirks bcm4908_partitions_quirks = { + .post_parse = bcm4908_partitions_post_parse, +}; + +static struct fixed_partitions_quirks linksys_ns_partitions_quirks = { + .post_parse = linksys_ns_partitions_post_parse, +}; + +static const struct of_device_id parse_ofpart_match_table[]; + +static bool node_has_compatible(struct device_node *pp) +{ + return of_get_property(pp, "compatible", NULL); +} + +static int parse_fixed_partitions(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + const struct fixed_partitions_quirks *quirks; + const struct of_device_id *of_id; + struct mtd_partition *parts; + struct device_node *mtd_node; + struct device_node *ofpart_node; + const char *partname; + struct device_node *pp; + int nr_parts, i, ret = 0; + bool dedicated = true; + + /* Pull of_node from the master device node */ + mtd_node = mtd_get_of_node(master); + if (!mtd_node) + return 0; + + ofpart_node = of_get_child_by_name(mtd_node, "partitions"); + if (!ofpart_node && !master->parent) { + /* + * We might get here even when ofpart isn't used at all (e.g., + * when using another parser), so don't be louder than + * KERN_DEBUG + */ + pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", + master->name, mtd_node); + ofpart_node = mtd_node; + dedicated = false; + } + if (!ofpart_node) + return 0; + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { + /* The 'partitions' subnode might be used by another parser */ + return 0; + } + + quirks = of_id ? of_id->data : NULL; + + /* First count the subnodes */ + nr_parts = 0; + for_each_child_of_node(ofpart_node, pp) { + if (!dedicated && node_has_compatible(pp)) + continue; + + nr_parts++; + } + + if (nr_parts == 0) + return 0; + + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + i = 0; + for_each_child_of_node(ofpart_node, pp) { + const __be32 *reg; + int len; + int a_cells, s_cells; + + if (!dedicated && node_has_compatible(pp)) + continue; + + reg = of_get_property(pp, "reg", &len); + if (!reg) { + if (dedicated) { + pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n", + master->name, pp, + mtd_node); + goto ofpart_fail; + } else { + nr_parts--; + continue; + } + } + + a_cells = of_n_addr_cells(pp); + s_cells = of_n_size_cells(pp); + if (len / 4 != a_cells + s_cells) { + pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n", + master->name, pp, + mtd_node); + goto ofpart_fail; + } + + parts[i].offset = of_read_number(reg, a_cells); + parts[i].size = of_read_number(reg + a_cells, s_cells); + parts[i].of_node = pp; + + partname = of_get_property(pp, "label", &len); + if (!partname) + partname = of_get_property(pp, "name", &len); + parts[i].name = partname; + + if (of_get_property(pp, "read-only", &len)) + parts[i].mask_flags |= MTD_WRITEABLE; + + if (of_get_property(pp, "lock", &len)) + parts[i].mask_flags |= MTD_POWERUP_LOCK; + + if (of_property_read_bool(pp, "slc-mode")) + parts[i].add_flags |= MTD_SLC_ON_MLC_EMULATION; + + i++; + } + + if (!nr_parts) + goto ofpart_none; + + if (quirks && quirks->post_parse) + quirks->post_parse(master, parts, nr_parts); + + *pparts = parts; + return nr_parts; + +ofpart_fail: + pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", + master->name, pp, mtd_node); + ret = -EINVAL; +ofpart_none: + of_node_put(pp); + kfree(parts); + return ret; +} + +static const struct of_device_id parse_ofpart_match_table[] = { + /* Generic */ + { .compatible = "fixed-partitions" }, + /* Customized */ + { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, }, + { .compatible = "linksys,ns-partitions", .data = &linksys_ns_partitions_quirks, }, + {}, +}; +MODULE_DEVICE_TABLE(of, parse_ofpart_match_table); + +static struct mtd_part_parser ofpart_parser = { + .parse_fn = parse_fixed_partitions, + .name = "fixed-partitions", + .of_match_table = parse_ofpart_match_table, +}; + +static int parse_ofoldpart_partitions(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + struct device_node *dp; + int i, plen, nr_parts; + const struct { + __be32 offset, len; + } *part; + const char *names; + + /* Pull of_node from the master device node */ + dp = mtd_get_of_node(master); + if (!dp) + return 0; + + part = of_get_property(dp, "partitions", &plen); + if (!part) + return 0; /* No partitions found */ + + pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp); + + nr_parts = plen / sizeof(part[0]); + + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + names = of_get_property(dp, "partition-names", &plen); + + for (i = 0; i < nr_parts; i++) { + parts[i].offset = be32_to_cpu(part->offset); + parts[i].size = be32_to_cpu(part->len) & ~1; + /* bit 0 set signifies read only partition */ + if (be32_to_cpu(part->len) & 1) + parts[i].mask_flags = MTD_WRITEABLE; + + if (names && (plen > 0)) { + int len = strlen(names) + 1; + + parts[i].name = names; + plen -= len; + names += len; + } else { + parts[i].name = "unnamed"; + } + + part++; + } + + *pparts = parts; + return nr_parts; +} + +static struct mtd_part_parser ofoldpart_parser = { + .parse_fn = parse_ofoldpart_partitions, + .name = "ofoldpart", +}; + +static int __init ofpart_parser_init(void) +{ + register_mtd_parser(&ofpart_parser); + register_mtd_parser(&ofoldpart_parser); + return 0; +} + +static void __exit ofpart_parser_exit(void) +{ + deregister_mtd_parser(&ofpart_parser); + deregister_mtd_parser(&ofoldpart_parser); +} + +module_init(ofpart_parser_init); +module_exit(ofpart_parser_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree"); +MODULE_AUTHOR("Vitaly Wool, David Gibson"); +/* + * When MTD core cannot find the requested parser, it tries to load the module + * with the same name. Since we provide the ofoldpart parser, we should have + * the corresponding alias. + */ +MODULE_ALIAS("fixed-partitions"); +MODULE_ALIAS("ofoldpart"); |