// SPDX-License-Identifier: GPL-2.0 #define pr_fmt(fmt) "[simple-mtd] " fmt #include #include #include #include #include #include #include static int parse_env_part_range(const char *_env, u64 *start, u64 *end) { int ret = 0; char *env, *sep; env = kstrdup(_env, GFP_KERNEL); if (!env) { ret = -ENOMEM; goto out; } sep = strchr(env, ','); if (!sep) { ret = -EINVAL; goto out; } *sep = '\0'; ret = kstrtou64(env, 16, start); if (ret) goto out; ret = kstrtou64(sep + 1, 16, end); if (ret) goto out; out: if (env) kfree(env); return ret; } static int avm_mtd_of_parser(struct mtd_info *mtd, struct mtd_partition **p_mtd_pat, struct mtd_part_parser_data *parse_data) { unsigned long num_parts = 0, i; struct device_node *np, *child; struct mtd_partition *parts; np = parse_data->of_node; if (!np) { pr_err("mtd %s does not have an of node!\n", mtd->name); return 0; } np = of_get_compatible_child(np, "avm,of_mtd"); if (!np) { pr_err("mtd %s does not have avm,of_mtd compatible child!\n", mtd->name); return 0; } for_each_child_of_node (np, child) { num_parts++; } if (num_parts == 0) { pr_warn("mtd %s does not contain of partitions\n", mtd->name); return 0; } parts = kcalloc(num_parts, sizeof(struct mtd_partition), GFP_KERNEL); if (!parts) return -ENOMEM; i = 0; for_each_child_of_node (np, child) { struct mtd_partition *part = parts + i; const char *env_name, *env_value; u64 start, end; if (of_property_read_string(child, "linux,mtd-name", &part->name)) part->name = child->name; if (of_property_read_string(child, "urlader,env", &env_name)) { pr_warn("mtd %s part %s does not have an urlader env, skipping...\n", mtd->name, part->name); continue; } env_value = prom_getenv((char *)env_name); if (!env_value) { pr_warn("mtd %s part %s: env %s not found, skipping.\n", mtd->name, part->name, env_name); continue; } if (parse_env_part_range(env_value, &start, &end)) { pr_warn("mtd %s part %s: could not parse env value, skipping.\n", mtd->name, part->name); continue; } part->offset = start; part->size = end - start; // TODO set types here i++; } *p_mtd_pat = parts; return i; } static struct mtd_part_parser avm_mtd_of = { .name = "avm_of_mtd", .parse_fn = avm_mtd_of_parser, }; static __init int avm_mtd_of_init(void) { register_mtd_parser(&avm_mtd_of); return 0; } subsys_initcall(avm_mtd_of_init);