summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mtd/fsl,vf610-nfc.yaml89
-rw-r--r--Documentation/devicetree/bindings/mtd/vf610-nfc.txt59
-rw-r--r--drivers/mtd/devices/Kconfig2
-rw-r--r--drivers/mtd/mtdchar.c2
-rw-r--r--drivers/mtd/mtdcore.c152
-rw-r--r--drivers/mtd/mtdcore.h2
-rw-r--r--drivers/mtd/mtdpart.c16
-rw-r--r--drivers/mtd/nand/raw/Kconfig2
-rw-r--r--drivers/mtd/spi-nor/macronix.c73
-rw-r--r--include/linux/mtd/partitions.h2
10 files changed, 253 insertions, 146 deletions
diff --git a/Documentation/devicetree/bindings/mtd/fsl,vf610-nfc.yaml b/Documentation/devicetree/bindings/mtd/fsl,vf610-nfc.yaml
new file mode 100644
index 0000000000000..480a5c87859d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/fsl,vf610-nfc.yaml
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/fsl,vf610-nfc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale's NAND flash controller (NFC)
+
+description:
+ This variant of the Freescale NAND flash controller (NFC) can be found on
+ Vybrid (vf610), MPC5125, MCF54418 and Kinetis K70.
+
+maintainers:
+ - Frank Li <Frank.Li@nxp.com>
+
+properties:
+ compatible:
+ enum:
+ - fsl,vf610-nfc
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: nfc
+
+patternProperties:
+ "^nand@[a-f0-9]$":
+ type: object
+ $ref: raw-nand-chip.yaml
+
+ properties:
+ compatible:
+ const: fsl,vf610-nfc-nandcs
+
+ reg:
+ const: 0
+
+ nand-ecc-strength:
+ enum: [24, 32]
+
+ nand-ecc-step-size:
+ const: 2048
+
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+allOf:
+ - $ref: nand-controller.yaml
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/vf610-clock.h>
+
+ nand-controller@400e0000 {
+ compatible = "fsl,vf610-nfc";
+ reg = <0x400e0000 0x4000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_NFC>;
+ clock-names = "nfc";
+ assigned-clocks = <&clks VF610_CLK_NFC>;
+ assigned-clock-rates = <33000000>;
+
+ nand@0 {
+ compatible = "fsl,vf610-nfc-nandcs";
+ reg = <0>;
+ nand-bus-width = <8>;
+ nand-ecc-mode = "hw";
+ nand-ecc-strength = <32>;
+ nand-ecc-step-size = <2048>;
+ nand-on-flash-bbt;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mtd/vf610-nfc.txt b/Documentation/devicetree/bindings/mtd/vf610-nfc.txt
deleted file mode 100644
index 7db5e6e609df6..0000000000000
--- a/Documentation/devicetree/bindings/mtd/vf610-nfc.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-Freescale's NAND flash controller (NFC)
-
-This variant of the Freescale NAND flash controller (NFC) can be found on
-Vybrid (vf610), MPC5125, MCF54418 and Kinetis K70.
-
-Required properties:
-- compatible: Should be set to "fsl,vf610-nfc".
-- reg: address range of the NFC.
-- interrupts: interrupt of the NFC.
-- #address-cells: shall be set to 1. Encode the nand CS.
-- #size-cells : shall be set to 0.
-- assigned-clocks: main clock from the SoC, for Vybrid <&clks VF610_CLK_NFC>;
-- assigned-clock-rates: The NAND bus timing is derived from this clock
- rate and should not exceed maximum timing for any NAND memory chip
- in a board stuffing. Typical NAND memory timings derived from this
- clock are found in the SoC hardware reference manual. Furthermore,
- there might be restrictions on maximum rates when using hardware ECC.
-
-- #address-cells, #size-cells : Must be present if the device has sub-nodes
- representing partitions.
-
-Required children nodes:
-Children nodes represent the available nand chips. Currently the driver can
-only handle one NAND chip.
-
-Required properties:
-- compatible: Should be set to "fsl,vf610-nfc-cs".
-- nand-bus-width: see nand-controller.yaml
-- nand-ecc-mode: see nand-controller.yaml
-
-Required properties for hardware ECC:
-- nand-ecc-strength: supported strengths are 24 and 32 bit (see nand-controller.yaml)
-- nand-ecc-step-size: step size equals page size, currently only 2k pages are
- supported
-- nand-on-flash-bbt: see nand-controller.yaml
-
-Example:
-
- nfc: nand@400e0000 {
- compatible = "fsl,vf610-nfc";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x400e0000 0x4000>;
- interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_NFC>;
- clock-names = "nfc";
- assigned-clocks = <&clks VF610_CLK_NFC>;
- assigned-clock-rates = <33000000>;
-
- nand@0 {
- compatible = "fsl,vf610-nfc-nandcs";
- reg = <0>;
- nand-bus-width = <8>;
- nand-ecc-mode = "hw";
- nand-ecc-strength = <32>;
- nand-ecc-step-size = <2048>;
- nand-on-flash-bbt;
- };
- };
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index ff2f9e55ef28f..aed653ce8fa22 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -98,7 +98,7 @@ config MTD_MCHP48L640
config MTD_SPEAR_SMI
tristate "SPEAR MTD NOR Support through SMI controller"
depends on PLAT_SPEAR || COMPILE_TEST
- default y
+ default PLAT_SPEAR
help
This enable SNOR support on SPEAR platforms using SMI controller
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 8dc4f5c493fcb..391d81ad960c9 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -559,7 +559,7 @@ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
/* Sanitize user input */
p.devname[BLKPG_DEVNAMELTH - 1] = '\0';
- return mtd_add_partition(mtd, p.devname, p.start, p.length);
+ return mtd_add_partition(mtd, p.devname, p.start, p.length, NULL);
case BLKPG_DEL_PARTITION:
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 5ba9a741f5ac3..429d8c16baf04 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -68,7 +68,13 @@ static struct class mtd_class = {
.pm = MTD_CLS_PM_OPS,
};
+static struct class mtd_master_class = {
+ .name = "mtd_master",
+ .pm = MTD_CLS_PM_OPS,
+};
+
static DEFINE_IDR(mtd_idr);
+static DEFINE_IDR(mtd_master_idr);
/* These are exported solely for the purpose of mtd_blkdevs.c. You
should not use them for _anything_ else */
@@ -83,8 +89,9 @@ EXPORT_SYMBOL_GPL(__mtd_next_device);
static LIST_HEAD(mtd_notifiers);
-
+#define MTD_MASTER_DEVS 255
#define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
+static dev_t mtd_master_devt;
/* REVISIT once MTD uses the driver model better, whoever allocates
* the mtd_info will probably want to use the release() hook...
@@ -104,6 +111,17 @@ static void mtd_release(struct device *dev)
device_destroy(&mtd_class, index + 1);
}
+static void mtd_master_release(struct device *dev)
+{
+ struct mtd_info *mtd = dev_get_drvdata(dev);
+
+ idr_remove(&mtd_master_idr, mtd->index);
+ of_node_put(mtd_get_of_node(mtd));
+
+ if (mtd_is_partition(mtd))
+ release_mtd_partition(mtd);
+}
+
static void mtd_device_release(struct kref *kref)
{
struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt);
@@ -367,6 +385,11 @@ static const struct device_type mtd_devtype = {
.release = mtd_release,
};
+static const struct device_type mtd_master_devtype = {
+ .name = "mtd_master",
+ .release = mtd_master_release,
+};
+
static bool mtd_expert_analysis_mode;
#ifdef CONFIG_DEBUG_FS
@@ -634,13 +657,13 @@ exit_parent:
/**
* add_mtd_device - register an MTD device
* @mtd: pointer to new MTD device info structure
+ * @partitioned: create partitioned device
*
* Add a device to the list of MTD devices present in the system, and
* notify each currently active MTD 'user' of its arrival. Returns
* zero on success or non-zero on failure.
*/
-
-int add_mtd_device(struct mtd_info *mtd)
+int add_mtd_device(struct mtd_info *mtd, bool partitioned)
{
struct device_node *np = mtd_get_of_node(mtd);
struct mtd_info *master = mtd_get_master(mtd);
@@ -687,10 +710,17 @@ int add_mtd_device(struct mtd_info *mtd)
ofidx = -1;
if (np)
ofidx = of_alias_get_id(np, "mtd");
- if (ofidx >= 0)
- i = idr_alloc(&mtd_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL);
- else
- i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
+ if (partitioned) {
+ if (ofidx >= 0)
+ i = idr_alloc(&mtd_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL);
+ else
+ i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
+ } else {
+ if (ofidx >= 0)
+ i = idr_alloc(&mtd_master_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL);
+ else
+ i = idr_alloc(&mtd_master_idr, mtd, 0, 0, GFP_KERNEL);
+ }
if (i < 0) {
error = i;
goto fail_locked;
@@ -738,10 +768,18 @@ int add_mtd_device(struct mtd_info *mtd)
/* Caller should have set dev.parent to match the
* physical device, if appropriate.
*/
- mtd->dev.type = &mtd_devtype;
- mtd->dev.class = &mtd_class;
- mtd->dev.devt = MTD_DEVT(i);
- error = dev_set_name(&mtd->dev, "mtd%d", i);
+ if (partitioned) {
+ mtd->dev.type = &mtd_devtype;
+ mtd->dev.class = &mtd_class;
+ mtd->dev.devt = MTD_DEVT(i);
+ dev_set_name(&mtd->dev, "mtd%d", i);
+ error = dev_set_name(&mtd->dev, "mtd%d", i);
+ } else {
+ mtd->dev.type = &mtd_master_devtype;
+ mtd->dev.class = &mtd_master_class;
+ mtd->dev.devt = MKDEV(MAJOR(mtd_master_devt), i);
+ error = dev_set_name(&mtd->dev, "mtd_master%d", i);
+ }
if (error)
goto fail_devname;
dev_set_drvdata(&mtd->dev, mtd);
@@ -749,6 +787,7 @@ int add_mtd_device(struct mtd_info *mtd)
of_node_get(mtd_get_of_node(mtd));
error = device_register(&mtd->dev);
if (error) {
+ pr_err("mtd: %s device_register fail %d\n", mtd->name, error);
put_device(&mtd->dev);
goto fail_added;
}
@@ -760,10 +799,13 @@ int add_mtd_device(struct mtd_info *mtd)
mtd_debugfs_populate(mtd);
- device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL,
- "mtd%dro", i);
+ if (partitioned) {
+ device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL,
+ "mtd%dro", i);
+ }
- pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);
+ pr_debug("mtd: Giving out %spartitioned device %d to %s\n",
+ partitioned ? "" : "un-", i, mtd->name);
/* No need to get a refcount on the module containing
the notifier, since we hold the mtd_table_mutex */
list_for_each_entry(not, &mtd_notifiers, list)
@@ -771,13 +813,16 @@ int add_mtd_device(struct mtd_info *mtd)
mutex_unlock(&mtd_table_mutex);
- if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) {
- if (IS_BUILTIN(CONFIG_MTD)) {
- pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name);
- ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
- } else {
- pr_warn("mtd: can't set mtd%d (%s) as root device - mtd must be builtin\n",
- mtd->index, mtd->name);
+ if (partitioned) {
+ if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) {
+ if (IS_BUILTIN(CONFIG_MTD)) {
+ pr_info("mtd: setting mtd%d (%s) as root device\n",
+ mtd->index, mtd->name);
+ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
+ } else {
+ pr_warn("mtd: can't set mtd%d (%s) as root device - mtd must be builtin\n",
+ mtd->index, mtd->name);
+ }
}
}
@@ -793,7 +838,10 @@ fail_nvmem_add:
fail_added:
of_node_put(mtd_get_of_node(mtd));
fail_devname:
- idr_remove(&mtd_idr, i);
+ if (partitioned)
+ idr_remove(&mtd_idr, i);
+ else
+ idr_remove(&mtd_master_idr, i);
fail_locked:
mutex_unlock(&mtd_table_mutex);
return error;
@@ -811,12 +859,14 @@ fail_locked:
int del_mtd_device(struct mtd_info *mtd)
{
- int ret;
struct mtd_notifier *not;
+ struct idr *idr;
+ int ret;
mutex_lock(&mtd_table_mutex);
- if (idr_find(&mtd_idr, mtd->index) != mtd) {
+ idr = mtd->dev.class == &mtd_class ? &mtd_idr : &mtd_master_idr;
+ if (idr_find(idr, mtd->index) != mtd) {
ret = -ENODEV;
goto out_error;
}
@@ -1056,6 +1106,7 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
const struct mtd_partition *parts,
int nr_parts)
{
+ struct mtd_info *parent;
int ret, err;
mtd_set_dev_defaults(mtd);
@@ -1064,25 +1115,30 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
if (ret)
goto out;
+ ret = add_mtd_device(mtd, false);
+ if (ret)
+ goto out;
+
if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
- ret = add_mtd_device(mtd);
+ ret = mtd_add_partition(mtd, mtd->name, 0, MTDPART_SIZ_FULL, &parent);
if (ret)
goto out;
+
+ } else {
+ parent = mtd;
}
/* Prefer parsed partitions over driver-provided fallback */
- ret = parse_mtd_partitions(mtd, types, parser_data);
+ ret = parse_mtd_partitions(parent, types, parser_data);
if (ret == -EPROBE_DEFER)
goto out;
if (ret > 0)
ret = 0;
else if (nr_parts)
- ret = add_mtd_partitions(mtd, parts, nr_parts);
- else if (!device_is_registered(&mtd->dev))
- ret = add_mtd_device(mtd);
- else
- ret = 0;
+ ret = add_mtd_partitions(parent, parts, nr_parts);
+ else if (!IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
+ ret = mtd_add_partition(parent, mtd->name, 0, MTDPART_SIZ_FULL, NULL);
if (ret)
goto out;
@@ -1102,13 +1158,14 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
register_reboot_notifier(&mtd->reboot_notifier);
}
+ return 0;
out:
- if (ret) {
- nvmem_unregister(mtd->otp_user_nvmem);
- nvmem_unregister(mtd->otp_factory_nvmem);
- }
+ nvmem_unregister(mtd->otp_user_nvmem);
+ nvmem_unregister(mtd->otp_factory_nvmem);
- if (ret && device_is_registered(&mtd->dev)) {
+ del_mtd_partitions(mtd);
+
+ if (device_is_registered(&mtd->dev)) {
err = del_mtd_device(mtd);
if (err)
pr_err("Error when deleting MTD device (%d)\n", err);
@@ -1267,8 +1324,7 @@ int __get_mtd_device(struct mtd_info *mtd)
mtd = mtd->parent;
}
- if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
- kref_get(&master->refcnt);
+ kref_get(&master->refcnt);
return 0;
}
@@ -1362,8 +1418,7 @@ void __put_mtd_device(struct mtd_info *mtd)
mtd = parent;
}
- if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
- kref_put(&master->refcnt, mtd_device_release);
+ kref_put(&master->refcnt, mtd_device_release);
module_put(master->owner);
@@ -2530,6 +2585,16 @@ static int __init init_mtd(void)
if (ret)
goto err_reg;
+ ret = class_register(&mtd_master_class);
+ if (ret)
+ goto err_reg2;
+
+ ret = alloc_chrdev_region(&mtd_master_devt, 0, MTD_MASTER_DEVS, "mtd_master");
+ if (ret < 0) {
+ pr_err("unable to allocate char dev region\n");
+ goto err_chrdev;
+ }
+
mtd_bdi = mtd_bdi_init("mtd");
if (IS_ERR(mtd_bdi)) {
ret = PTR_ERR(mtd_bdi);
@@ -2554,6 +2619,10 @@ out_procfs:
bdi_unregister(mtd_bdi);
bdi_put(mtd_bdi);
err_bdi:
+ unregister_chrdev_region(mtd_master_devt, MTD_MASTER_DEVS);
+err_chrdev:
+ class_unregister(&mtd_master_class);
+err_reg2:
class_unregister(&mtd_class);
err_reg:
pr_err("Error registering mtd class or bdi: %d\n", ret);
@@ -2567,9 +2636,12 @@ static void __exit cleanup_mtd(void)
if (proc_mtd)
remove_proc_entry("mtd", NULL);
class_unregister(&mtd_class);
+ class_unregister(&mtd_master_class);
+ unregister_chrdev_region(mtd_master_devt, MTD_MASTER_DEVS);
bdi_unregister(mtd_bdi);
bdi_put(mtd_bdi);
idr_destroy(&mtd_idr);
+ idr_destroy(&mtd_master_idr);
}
module_init(init_mtd);
diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h
index b014861a06a6f..2258d31c5aa6b 100644
--- a/drivers/mtd/mtdcore.h
+++ b/drivers/mtd/mtdcore.h
@@ -8,7 +8,7 @@ extern struct mutex mtd_table_mutex;
extern struct backing_dev_info *mtd_bdi;
struct mtd_info *__mtd_next_device(int i);
-int __must_check add_mtd_device(struct mtd_info *mtd);
+int __must_check add_mtd_device(struct mtd_info *mtd, bool partitioned);
int del_mtd_device(struct mtd_info *mtd);
int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
int del_mtd_partitions(struct mtd_info *);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 994e8c51e6743..5a3db36d734ef 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -86,8 +86,7 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent,
* parent conditional on that option. Note, this is a way to
* distinguish between the parent and its partitions in sysfs.
*/
- child->dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) || mtd_is_partition(parent) ?
- &parent->dev : parent->dev.parent;
+ child->dev.parent = &parent->dev;
child->dev.of_node = part->of_node;
child->parent = parent;
child->part.offset = part->offset;
@@ -243,7 +242,7 @@ static int mtd_add_partition_attrs(struct mtd_info *new)
}
int mtd_add_partition(struct mtd_info *parent, const char *name,
- long long offset, long long length)
+ long long offset, long long length, struct mtd_info **out)
{
struct mtd_info *master = mtd_get_master(parent);
u64 parent_size = mtd_is_partition(parent) ?
@@ -276,12 +275,15 @@ int mtd_add_partition(struct mtd_info *parent, const char *name,
list_add_tail(&child->part.node, &parent->partitions);
mutex_unlock(&master->master.partitions_lock);
- ret = add_mtd_device(child);
+ ret = add_mtd_device(child, true);
if (ret)
goto err_remove_part;
mtd_add_partition_attrs(child);
+ if (out)
+ *out = child;
+
return 0;
err_remove_part:
@@ -413,7 +415,7 @@ int add_mtd_partitions(struct mtd_info *parent,
list_add_tail(&child->part.node, &parent->partitions);
mutex_unlock(&master->master.partitions_lock);
- ret = add_mtd_device(child);
+ ret = add_mtd_device(child, true);
if (ret) {
mutex_lock(&master->master.partitions_lock);
list_del(&child->part.node);
@@ -590,9 +592,6 @@ static int mtd_part_of_parse(struct mtd_info *master,
int ret, err = 0;
dev = &master->dev;
- /* Use parent device (controller) if the top level MTD is not registered */
- if (!IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) && !mtd_is_partition(master))
- dev = master->dev.parent;
np = mtd_get_of_node(master);
if (mtd_is_partition(master))
@@ -711,6 +710,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
if (ret < 0 && !err)
err = ret;
}
+
return err;
}
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index e966b15d2445d..4b99d9c422c3f 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -34,7 +34,7 @@ config MTD_NAND_DENALI_DT
config MTD_NAND_AMS_DELTA
tristate "Amstrad E3 NAND controller"
depends on MACH_AMS_DELTA || COMPILE_TEST
- default y
+ default MACH_AMS_DELTA
help
Support for NAND flash on Amstrad E3 (Delta).
diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c
index 55644a3cd88c2..e97f5cbd9aad2 100644
--- a/drivers/mtd/spi-nor/macronix.c
+++ b/drivers/mtd/spi-nor/macronix.c
@@ -58,6 +58,31 @@ macronix_qpp4b_post_sfdp_fixups(struct spi_nor *nor)
return 0;
}
+static int
+mx25l3255e_late_init_fixups(struct spi_nor *nor)
+{
+ struct spi_nor_flash_parameter *params = nor->params;
+
+ /*
+ * SFDP of MX25L3255E is JESD216, which does not include the Quad
+ * Enable bit Requirement in BFPT. As a result, during BFPT parsing,
+ * the quad_enable method is not set to spi_nor_sr1_bit6_quad_enable.
+ * Therefore, it is necessary to correct this setting by late_init.
+ */
+ params->quad_enable = spi_nor_sr1_bit6_quad_enable;
+
+ /*
+ * In addition, MX25L3255E also supports 1-4-4 page program in 3-byte
+ * address mode. However, since the 3-byte address 1-4-4 page program
+ * is not defined in SFDP, it needs to be configured in late_init.
+ */
+ params->hwcaps.mask |= SNOR_HWCAPS_PP_1_4_4;
+ spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_1_4_4],
+ SPINOR_OP_PP_1_4_4, SNOR_PROTO_1_4_4);
+
+ return 0;
+}
+
static const struct spi_nor_fixups mx25l25635_fixups = {
.post_bfpt = mx25l25635_post_bfpt_fixups,
.post_sfdp = macronix_qpp4b_post_sfdp_fixups,
@@ -67,6 +92,10 @@ static const struct spi_nor_fixups macronix_qpp4b_fixups = {
.post_sfdp = macronix_qpp4b_post_sfdp_fixups,
};
+static const struct spi_nor_fixups mx25l3255e_fixups = {
+ .late_init = mx25l3255e_late_init_fixups,
+};
+
static const struct flash_info macronix_nor_parts[] = {
{
.id = SNOR_ID(0xc2, 0x20, 0x10),
@@ -88,10 +117,8 @@ static const struct flash_info macronix_nor_parts[] = {
.name = "mx25l8005",
.size = SZ_1M,
}, {
+ /* MX25L1606E */
.id = SNOR_ID(0xc2, 0x20, 0x15),
- .name = "mx25l1606e",
- .size = SZ_2M,
- .no_sfdp_flags = SECT_4K,
}, {
.id = SNOR_ID(0xc2, 0x20, 0x16),
.name = "mx25l3205d",
@@ -103,29 +130,21 @@ static const struct flash_info macronix_nor_parts[] = {
.size = SZ_8M,
.no_sfdp_flags = SECT_4K,
}, {
+ /* MX25L12805D */
.id = SNOR_ID(0xc2, 0x20, 0x18),
- .name = "mx25l12805d",
- .size = SZ_16M,
.flags = SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP,
- .no_sfdp_flags = SECT_4K,
}, {
+ /* MX25L25635E, MX25L25645G */
.id = SNOR_ID(0xc2, 0x20, 0x19),
- .name = "mx25l25635e",
- .size = SZ_32M,
- .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
.fixups = &mx25l25635_fixups
}, {
+ /* MX66L51235F */
.id = SNOR_ID(0xc2, 0x20, 0x1a),
- .name = "mx66l51235f",
- .size = SZ_64M,
- .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
.fixup_flags = SPI_NOR_4B_OPCODES,
.fixups = &macronix_qpp4b_fixups,
}, {
+ /* MX66L1G45G */
.id = SNOR_ID(0xc2, 0x20, 0x1b),
- .name = "mx66l1g45g",
- .size = SZ_128M,
- .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
.fixups = &macronix_qpp4b_fixups,
}, {
/* MX66L2G45G */
@@ -167,29 +186,16 @@ static const struct flash_info macronix_nor_parts[] = {
.size = SZ_16M,
.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
}, {
+ /* MX25U51245G */
.id = SNOR_ID(0xc2, 0x25, 0x3a),
- .name = "mx25u51245g",
- .size = SZ_64M,
- .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
- .fixup_flags = SPI_NOR_4B_OPCODES,
- .fixups = &macronix_qpp4b_fixups,
- }, {
- .id = SNOR_ID(0xc2, 0x25, 0x3a),
- .name = "mx66u51235f",
- .size = SZ_64M,
- .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
- .fixup_flags = SPI_NOR_4B_OPCODES,
.fixups = &macronix_qpp4b_fixups,
}, {
/* MX66U1G45G */
.id = SNOR_ID(0xc2, 0x25, 0x3b),
.fixups = &macronix_qpp4b_fixups,
}, {
+ /* MX66U2G45G */
.id = SNOR_ID(0xc2, 0x25, 0x3c),
- .name = "mx66u2g45g",
- .size = SZ_256M,
- .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
- .fixup_flags = SPI_NOR_4B_OPCODES,
.fixups = &macronix_qpp4b_fixups,
}, {
.id = SNOR_ID(0xc2, 0x26, 0x18),
@@ -215,15 +221,14 @@ static const struct flash_info macronix_nor_parts[] = {
.size = SZ_4M,
.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
}, {
+ /* MX25UW51245G */
.id = SNOR_ID(0xc2, 0x81, 0x3a),
- .name = "mx25uw51245g",
.n_banks = 4,
.flags = SPI_NOR_RWW,
}, {
+ /* MX25L3255E */
.id = SNOR_ID(0xc2, 0x9e, 0x16),
- .name = "mx25l3255e",
- .size = SZ_4M,
- .no_sfdp_flags = SECT_4K,
+ .fixups = &mx25l3255e_fixups,
},
/*
* This spares us of adding new flash entries for flashes that can be
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index b74a539ec5819..5daf80df9e899 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -108,7 +108,7 @@ extern void deregister_mtd_parser(struct mtd_part_parser *parser);
deregister_mtd_parser)
int mtd_add_partition(struct mtd_info *master, const char *name,
- long long offset, long long length);
+ long long offset, long long length, struct mtd_info **part);
int mtd_del_partition(struct mtd_info *master, int partno);
uint64_t mtd_get_device_size(const struct mtd_info *mtd);