diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2020-12-11 13:31:14 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2020-12-11 13:31:14 +0100 |
commit | 5f2377ac5502559ecfb7d70c2c99e5d553de1cd5 (patch) | |
tree | 8502a36e8b01c7f251a5a2a9a3d98a923c886feb | |
parent | b33e3e0f99946260200a43e783488416eeed112a (diff) | |
parent | 41716009e150053a04c19bc2028ff7e1016a5fde (diff) | |
download | barebox-5f2377ac5502559ecfb7d70c2c99e5d553de1cd5.tar.gz barebox-5f2377ac5502559ecfb7d70c2c99e5d553de1cd5.tar.xz |
Merge branch 'for-next/mtd'
-rw-r--r-- | drivers/mtd/core.c | 31 | ||||
-rw-r--r-- | drivers/mtd/nand/Kconfig | 9 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 7 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_denali_dt.c | 57 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_omap_gpmc.c | 9 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 9 | ||||
-rw-r--r-- | drivers/of/partition.c | 37 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 3 | ||||
-rw-r--r-- | include/of.h | 17 |
9 files changed, 158 insertions, 21 deletions
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c index 1b1ed53a61..af33ad665c 100644 --- a/drivers/mtd/core.c +++ b/drivers/mtd/core.c @@ -639,6 +639,34 @@ static int mtd_detect(struct device_d *dev) return ret; } +static int mtd_partition_fixup_generic(struct mtd_info *mtd, struct device_node *root) +{ + struct cdev *cdev = &mtd->cdev; + struct device_node *np, *mtdnp = mtd_get_of_node(mtd); + char *name; + + name = of_get_reproducible_name(mtdnp); + np = of_find_node_by_reproducible_name(root, name); + free(name); + if (!np) { + dev_err(&mtd->dev, "Cannot find nodepath %s, cannot fixup\n", + mtdnp->full_name); + return -EINVAL; + } + + return of_fixup_partitions(np, cdev); +} + +static int mtd_partition_fixup(struct device_node *root, void *ctx) +{ + struct mtd_info *mtd = ctx; + + if (mtd->of_fixup) + return mtd->of_fixup(mtd, root); + + return mtd_partition_fixup_generic(mtd, root); +} + int add_mtd_device(struct mtd_info *mtd, const char *devname, int device_id) { struct mtddev_hook *hook; @@ -706,8 +734,7 @@ int add_mtd_device(struct mtd_info *mtd, const char *devname, int device_id) dev_add_param_string(&mtd->dev, "partitions", mtd_partition_set, mtd_partition_get, &mtd->partition_string, mtd); if (IS_ENABLED(CONFIG_OFDEVICE) && np) { of_parse_partitions(&mtd->cdev, np); - mtd->of_path = xstrdup(np->full_name); - ret = of_partitions_register_fixup(&mtd->cdev); + ret = of_register_fixup(mtd_partition_fixup, mtd); if (ret) goto err1; } diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 97819e5c0b..7c93260892 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -7,11 +7,20 @@ menuconfig NAND if NAND +config MTD_NAND_ECC_SOFT + bool + prompt "Support software ecc" + config MTD_NAND_ECC_SW_BCH select BCH + depends on MTD_NAND_ECC_SOFT bool prompt "Support software BCH ecc" +config NAND_ECC_HW_SYNDROME + bool + prompt "Support syndrome hardware ecc controllers" + config NAND_ALLOW_ERASE_BAD bool depends on MTD_WRITE diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5db0b5625e..427aa7f0ec 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -5098,6 +5098,9 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip) struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; + if (!IS_ENABLED(CONFIG_MTD_NAND_ECC_SOFT)) + return -ENOSYS; + if (WARN_ON(ecc->mode != NAND_ECC_SOFT)) return -EINVAL; @@ -5619,6 +5622,10 @@ int nand_scan_tail(struct nand_chip *chip) if (!ecc->write_subpage && ecc->hwctl && ecc->calculate) ecc->write_subpage = nand_write_subpage_hwecc; case NAND_ECC_HW_SYNDROME: + if (!IS_ENABLED(CONFIG_NAND_ECC_HW_SYNDROME)) { + ret = -ENOSYS; + goto err_nand_manuf_cleanup; + } if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) && (!ecc->read_page || ecc->read_page == nand_read_page_hwecc || diff --git a/drivers/mtd/nand/nand_denali_dt.c b/drivers/mtd/nand/nand_denali_dt.c index 877c40714a..8deea0292e 100644 --- a/drivers/mtd/nand/nand_denali_dt.c +++ b/drivers/mtd/nand/nand_denali_dt.c @@ -51,12 +51,65 @@ static const struct denali_dt_data denali_socfpga_data = { .ecc_caps = &denali_socfpga_ecc_caps, }; +/* + * Older versions of the kernel driver require the partition nodes + * to be direct subnodes of the controller node. Starting with Kernel + * v5.2 (d8e8fd0ebf8b ("mtd: rawnand: denali: decouple controller and + * NAND chips")) the device node for the Denali controller is seen as a + * NAND controller node which has subnodes for each chip attached to that + * controller. The chip subnodes then hold the partitions. The barebox + * Denali driver also supports chip subnodes like the newer Kernel + * driver. To find the container node for the partitions we first try + * to find the chip subnodes in the Kernel device tree. Only if we + * can't find these we try the controller device node and put the + * partitions there. + * Note that we take the existence of the chip subnodes in the kernel + * device tree as a sign that we put the partitions there. When they + * don't exist we use the controller node. This means you have to make + * sure the chip subnodes exist when you start a Kernel that requires + * these. Beginning with Kernel v5.5 (f34a5072c465 ("mtd: rawnand: denali: + * remove the old unified controller/chip DT support")) the chip subnodes + * are mandatory for the Kernel. + */ +static int denali_partition_fixup(struct mtd_info *mtd, struct device_node *root) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct denali_controller *denali = container_of(chip->controller, + struct denali_controller, + controller); + struct device_node *np, *mtdnp = mtd_get_of_node(mtd); + char *name; + + name = of_get_reproducible_name(mtdnp); + np = of_find_node_by_reproducible_name(root, name); + free(name); + + if (np) { + dev_info(denali->dev, "Fixing up chip node %s\n", + np->full_name); + } else { + name = of_get_reproducible_name(mtdnp->parent); + np = of_find_node_by_reproducible_name(root, name); + free(name); + + if (np) + dev_info(denali->dev, "Fixing up controller node %s\n", + np->full_name); + } + + if (!np) + return -EINVAL; + + return of_fixup_partitions(np, &mtd->cdev); +} + static int denali_dt_chip_init(struct denali_controller *denali, struct device_node *chip_np) { struct denali_chip *dchip; u32 bank; int nsels, i, ret; + struct mtd_info *mtd; nsels = of_property_count_elems_of_size(chip_np, "reg", sizeof(u32)); if (nsels < 0) @@ -66,6 +119,10 @@ static int denali_dt_chip_init(struct denali_controller *denali, dchip->nsels = nsels; + mtd = nand_to_mtd(&dchip->chip); + + mtd->of_fixup = denali_partition_fixup; + for (i = 0; i < nsels; i++) { ret = of_property_read_u32_index(chip_np, "reg", i, &bank); if (ret) diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c index 1d81500bce..db1ca88791 100644 --- a/drivers/mtd/nand/nand_omap_gpmc.c +++ b/drivers/mtd/nand/nand_omap_gpmc.c @@ -1128,8 +1128,11 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo, err = elm_config(BCH16_ECC, minfo->writesize / nand->ecc.size, nand->ecc.size, nand->ecc.bytes); - if (err < 0) + if (err < 0) { + dev_err(oinfo->pdev, "ELM config failed: %s\n", + strerror(-err)); return err; + } nand->ecc.read_page = gpmc_read_page_hwecc_elm; @@ -1319,7 +1322,9 @@ static int gpmc_nand_probe(struct device_d *pdev) omap_gpmc_eccmode_set, NULL, (int *)&oinfo->ecc_mode, ecc_mode_strings, ARRAY_SIZE(ecc_mode_strings), oinfo); - omap_gpmc_eccmode(oinfo, oinfo->ecc_mode); + err = omap_gpmc_eccmode(oinfo, oinfo->ecc_mode); + if (err) + goto out_release_mem; /* We are all set to register with the system now! */ err = add_mtd_nand_device(minfo, "nand"); diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 350b82a6be..bd748ff5b4 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -470,6 +470,9 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) uint32_t rem; int ret; + if (!IS_ENABLED(CONFIG_MTD_WRITE)) + return -ENOSYS; + dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, (long long)instr->len); @@ -928,6 +931,9 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, size_t actual; int ret; + if (!IS_ENABLED(CONFIG_MTD_WRITE)) + return -ENOSYS; + dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE); @@ -1000,6 +1006,9 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, size_t retval; int ret; + if (!IS_ENABLED(CONFIG_MTD_WRITE)) + return -ENOSYS; + dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE); diff --git a/drivers/of/partition.c b/drivers/of/partition.c index 7367073c67..65c24c5426 100644 --- a/drivers/of/partition.c +++ b/drivers/of/partition.c @@ -123,20 +123,16 @@ static void delete_subnodes(struct device_node *np) } } -static int of_partition_fixup(struct device_node *root, void *ctx) +int of_fixup_partitions(struct device_node *np, struct cdev *cdev) { - struct cdev *cdev = ctx, *partcdev; - struct device_node *np, *part, *partnode; - char *name; + struct cdev *partcdev; + struct device_node *part, *partnode; int ret; int n_cells, n_parts = 0; if (of_partition_binding == MTD_OF_BINDING_DONTTOUCH) return 0; - if (!cdev->device_node) - return -EINVAL; - list_for_each_entry(partcdev, &cdev->partitions, partition_entry) { if (partcdev->flags & DEVFS_PARTITION_FROM_TABLE) continue; @@ -151,15 +147,6 @@ static int of_partition_fixup(struct device_node *root, void *ctx) else n_cells = 1; - name = of_get_reproducible_name(cdev->device_node); - np = of_find_node_by_reproducible_name(root, name); - free(name); - if (!np) { - dev_err(cdev->dev, "Cannot find nodepath %s, cannot fixup\n", - cdev->device_node->full_name); - return -EINVAL; - } - partnode = of_get_child_by_name(np, "partitions"); if (partnode) { if (of_partition_binding == MTD_OF_BINDING_LEGACY) { @@ -242,6 +229,24 @@ static int of_partition_fixup(struct device_node *root, void *ctx) return 0; } +static int of_partition_fixup(struct device_node *root, void *ctx) +{ + struct cdev *cdev = ctx; + struct device_node *np; + char *name; + + name = of_get_reproducible_name(cdev->device_node); + np = of_find_node_by_reproducible_name(root, name); + free(name); + if (!np) { + dev_err(cdev->dev, "Cannot find nodepath %s, cannot fixup\n", + cdev->device_node->full_name); + return -EINVAL; + } + + return of_fixup_partitions(np, cdev); +} + int of_partitions_register_fixup(struct cdev *cdev) { return of_register_fixup(of_partition_fixup, cdev); diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index ee37dfd5cb..0d977fea25 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -206,6 +206,8 @@ struct mtd_info { int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); int (*_block_markgood) (struct mtd_info *mtd, loff_t ofs); + int (*of_fixup)(struct mtd_info *mtd, struct device_node *root); + /* ECC status information */ struct mtd_ecc_stats ecc_stats; /* Subpage shift (NAND) */ @@ -248,7 +250,6 @@ struct mtd_info { struct list_head partitions_entry; char *partition_string; - char *of_path; unsigned int of_binding; }; diff --git a/include/of.h b/include/of.h index 6181da8c61..399fb7c5ba 100644 --- a/include/of.h +++ b/include/of.h @@ -277,6 +277,7 @@ extern struct device_d *of_device_enable_and_register_by_alias( struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node); int of_parse_partitions(struct cdev *cdev, struct device_node *node); +int of_fixup_partitions(struct device_node *np, struct cdev *cdev); int of_partitions_register_fixup(struct cdev *cdev); int of_device_is_stdout_path(struct device_d *dev); const char *of_get_model(void); @@ -305,6 +306,11 @@ static inline int of_parse_partitions(struct cdev *cdev, return -EINVAL; } +static inline int of_fixup_partitions(struct device_node *np, struct cdev *cdev) +{ + return -ENOSYS; +} + static inline int of_partitions_register_fixup(struct cdev *cdev) { return -ENOSYS; @@ -405,6 +411,17 @@ static inline struct device_node *of_get_child_by_name( return NULL; } +static inline char *of_get_reproducible_name(struct device_node *node) +{ + return NULL; +} + +static inline struct device_node * +of_find_node_by_reproducible_name(struct device_node *from, const char *name) +{ + return NULL; +} + static inline struct property *of_find_property(const struct device_node *np, const char *name, int *lenp) |