aboutsummaryrefslogtreecommitdiff
path: root/pkgs/patches-linux-5.15/401-v5.20-mtd-parsers-add-support-for-Sercomm-partitions.patch
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/patches-linux-5.15/401-v5.20-mtd-parsers-add-support-for-Sercomm-partitions.patch')
-rw-r--r--pkgs/patches-linux-5.15/401-v5.20-mtd-parsers-add-support-for-Sercomm-partitions.patch302
1 files changed, 302 insertions, 0 deletions
diff --git a/pkgs/patches-linux-5.15/401-v5.20-mtd-parsers-add-support-for-Sercomm-partitions.patch b/pkgs/patches-linux-5.15/401-v5.20-mtd-parsers-add-support-for-Sercomm-partitions.patch
new file mode 100644
index 0000000..113a96a
--- /dev/null
+++ b/pkgs/patches-linux-5.15/401-v5.20-mtd-parsers-add-support-for-Sercomm-partitions.patch
@@ -0,0 +1,302 @@
+From 9b78ef0c7997052e9eaa0f7a4513d546fa17358c Mon Sep 17 00:00:00 2001
+From: Mikhail Zhilkin <csharper2005@gmail.com>
+Date: Sun, 29 May 2022 11:07:14 +0000
+Subject: [PATCH] mtd: parsers: add support for Sercomm partitions
+
+This adds an MTD partition parser for the Sercomm partition table that
+is used in some Beeline, Netgear and Sercomm routers.
+
+The Sercomm partition map table contains real partition offsets, which
+may differ from device to device depending on the number and location of
+bad blocks on NAND.
+
+Original patch (proposed by NOGUCHI Hiroshi):
+Link: https://github.com/openwrt/openwrt/pull/1318#issuecomment-420607394
+
+Signed-off-by: NOGUCHI Hiroshi <drvlabo@gmail.com>
+Signed-off-by: Mikhail Zhilkin <csharper2005@gmail.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20220529110714.189732-1-csharper2005@gmail.com
+---
+ drivers/mtd/parsers/Kconfig | 9 ++
+ drivers/mtd/parsers/Makefile | 1 +
+ drivers/mtd/parsers/scpart.c | 248 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 258 insertions(+)
+ create mode 100644 drivers/mtd/parsers/scpart.c
+
+--- a/drivers/mtd/parsers/Kconfig
++++ b/drivers/mtd/parsers/Kconfig
+@@ -186,3 +186,12 @@ config MTD_QCOMSMEM_PARTS
+ help
+ This provides support for parsing partitions from Shared Memory (SMEM)
+ for NAND and SPI flash on Qualcomm platforms.
++
++config MTD_SERCOMM_PARTS
++ tristate "Sercomm partition table parser"
++ depends on MTD && RALINK
++ help
++ This provides partitions table parser for devices with Sercomm
++ partition map. This partition table contains real partition
++ offsets, which may differ from device to device depending on the
++ number and location of bad blocks on NAND.
+--- a/drivers/mtd/parsers/Makefile
++++ b/drivers/mtd/parsers/Makefile
+@@ -10,6 +10,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)
+ obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
+ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
+ obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
++obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o
+ obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
+ obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
+ obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o
+--- /dev/null
++++ b/drivers/mtd/parsers/scpart.c
+@@ -0,0 +1,248 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * drivers/mtd/scpart.c: Sercomm Partition Parser
++ *
++ * Copyright (C) 2018 NOGUCHI Hiroshi
++ * Copyright (C) 2022 Mikhail Zhilkin
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/module.h>
++
++#define MOD_NAME "scpart"
++
++#ifdef pr_fmt
++#undef pr_fmt
++#endif
++
++#define pr_fmt(fmt) MOD_NAME ": " fmt
++
++#define ID_ALREADY_FOUND 0xffffffffUL
++
++#define MAP_OFFS_IN_BLK 0x800
++#define MAP_MIRROR_NUM 2
++
++static const char sc_part_magic[] = {
++ 'S', 'C', 'F', 'L', 'M', 'A', 'P', 'O', 'K', '\0',
++};
++#define PART_MAGIC_LEN sizeof(sc_part_magic)
++
++/* assumes that all fields are set by CPU native endian */
++struct sc_part_desc {
++ uint32_t part_id;
++ uint32_t part_offs;
++ uint32_t part_bytes;
++};
++
++static uint32_t scpart_desc_is_valid(struct sc_part_desc *pdesc)
++{
++ return ((pdesc->part_id != 0xffffffffUL) &&
++ (pdesc->part_offs != 0xffffffffUL) &&
++ (pdesc->part_bytes != 0xffffffffUL));
++}
++
++static int scpart_scan_partmap(struct mtd_info *master, loff_t partmap_offs,
++ struct sc_part_desc **ppdesc)
++{
++ int cnt = 0;
++ int res = 0;
++ int res2;
++ loff_t offs;
++ size_t retlen;
++ struct sc_part_desc *pdesc = NULL;
++ struct sc_part_desc *tmpdesc;
++ uint8_t *buf;
++
++ buf = kzalloc(master->erasesize, GFP_KERNEL);
++ if (!buf) {
++ res = -ENOMEM;
++ goto out;
++ }
++
++ res2 = mtd_read(master, partmap_offs, master->erasesize, &retlen, buf);
++ if (res2 || retlen != master->erasesize) {
++ res = -EIO;
++ goto free;
++ }
++
++ for (offs = MAP_OFFS_IN_BLK;
++ offs < master->erasesize - sizeof(*tmpdesc);
++ offs += sizeof(*tmpdesc)) {
++ tmpdesc = (struct sc_part_desc *)&buf[offs];
++ if (!scpart_desc_is_valid(tmpdesc))
++ break;
++ cnt++;
++ }
++
++ if (cnt > 0) {
++ int bytes = cnt * sizeof(*pdesc);
++
++ pdesc = kcalloc(cnt, sizeof(*pdesc), GFP_KERNEL);
++ if (!pdesc) {
++ res = -ENOMEM;
++ goto free;
++ }
++ memcpy(pdesc, &(buf[MAP_OFFS_IN_BLK]), bytes);
++
++ *ppdesc = pdesc;
++ res = cnt;
++ }
++
++free:
++ kfree(buf);
++
++out:
++ return res;
++}
++
++static int scpart_find_partmap(struct mtd_info *master,
++ struct sc_part_desc **ppdesc)
++{
++ int magic_found = 0;
++ int res = 0;
++ int res2;
++ loff_t offs = 0;
++ size_t retlen;
++ uint8_t rdbuf[PART_MAGIC_LEN];
++
++ while ((magic_found < MAP_MIRROR_NUM) &&
++ (offs < master->size) &&
++ !mtd_block_isbad(master, offs)) {
++ res2 = mtd_read(master, offs, PART_MAGIC_LEN, &retlen, rdbuf);
++ if (res2 || retlen != PART_MAGIC_LEN) {
++ res = -EIO;
++ goto out;
++ }
++ if (!memcmp(rdbuf, sc_part_magic, PART_MAGIC_LEN)) {
++ pr_debug("Signature found at 0x%llx\n", offs);
++ magic_found++;
++ res = scpart_scan_partmap(master, offs, ppdesc);
++ if (res > 0)
++ goto out;
++ }
++ offs += master->erasesize;
++ }
++
++out:
++ if (res > 0)
++ pr_info("Valid 'SC PART MAP' (%d partitions) found at 0x%llx\n", res, offs);
++ else
++ pr_info("No valid 'SC PART MAP' was found\n");
++
++ return res;
++}
++
++static int scpart_parse(struct mtd_info *master,
++ const struct mtd_partition **pparts,
++ struct mtd_part_parser_data *data)
++{
++ const char *partname;
++ int n;
++ int nr_scparts;
++ int nr_parts = 0;
++ int res = 0;
++ struct sc_part_desc *scpart_map = NULL;
++ struct mtd_partition *parts = NULL;
++ struct device_node *mtd_node;
++ struct device_node *ofpart_node;
++ struct device_node *pp;
++
++ mtd_node = mtd_get_of_node(master);
++ if (!mtd_node) {
++ res = -ENOENT;
++ goto out;
++ }
++
++ ofpart_node = of_get_child_by_name(mtd_node, "partitions");
++ if (!ofpart_node) {
++ pr_info("%s: 'partitions' subnode not found on %pOF.\n",
++ master->name, mtd_node);
++ res = -ENOENT;
++ goto out;
++ }
++
++ nr_scparts = scpart_find_partmap(master, &scpart_map);
++ if (nr_scparts <= 0) {
++ pr_info("No any partitions was found in 'SC PART MAP'.\n");
++ res = -ENOENT;
++ goto free;
++ }
++
++ parts = kcalloc(of_get_child_count(ofpart_node), sizeof(*parts),
++ GFP_KERNEL);
++ if (!parts) {
++ res = -ENOMEM;
++ goto free;
++ }
++
++ for_each_child_of_node(ofpart_node, pp) {
++ u32 scpart_id;
++
++ if (of_property_read_u32(pp, "sercomm,scpart-id", &scpart_id))
++ continue;
++
++ for (n = 0 ; n < nr_scparts ; n++)
++ if ((scpart_map[n].part_id != ID_ALREADY_FOUND) &&
++ (scpart_id == scpart_map[n].part_id))
++ break;
++ if (n >= nr_scparts)
++ /* not match */
++ continue;
++
++ /* add the partition found in OF into MTD partition array */
++ parts[nr_parts].offset = scpart_map[n].part_offs;
++ parts[nr_parts].size = scpart_map[n].part_bytes;
++ parts[nr_parts].of_node = pp;
++
++ if (!of_property_read_string(pp, "label", &partname))
++ parts[nr_parts].name = partname;
++ if (of_property_read_bool(pp, "read-only"))
++ parts[nr_parts].mask_flags |= MTD_WRITEABLE;
++ if (of_property_read_bool(pp, "lock"))
++ parts[nr_parts].mask_flags |= MTD_POWERUP_LOCK;
++
++ /* mark as 'done' */
++ scpart_map[n].part_id = ID_ALREADY_FOUND;
++
++ nr_parts++;
++ }
++
++ if (nr_parts > 0) {
++ *pparts = parts;
++ res = nr_parts;
++ } else
++ pr_info("No partition in OF matches partition ID with 'SC PART MAP'.\n");
++
++ of_node_put(pp);
++
++free:
++ kfree(scpart_map);
++ if (res <= 0)
++ kfree(parts);
++
++out:
++ return res;
++}
++
++static const struct of_device_id scpart_parser_of_match_table[] = {
++ { .compatible = "sercomm,sc-partitions" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, scpart_parser_of_match_table);
++
++static struct mtd_part_parser scpart_parser = {
++ .parse_fn = scpart_parse,
++ .name = "scpart",
++ .of_match_table = scpart_parser_of_match_table,
++};
++module_mtd_part_parser(scpart_parser);
++
++/* mtd parsers will request the module by parser name */
++MODULE_ALIAS("scpart");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("NOGUCHI Hiroshi <drvlabo@gmail.com>");
++MODULE_AUTHOR("Mikhail Zhilkin <csharper2005@gmail.com>");
++MODULE_DESCRIPTION("Sercomm partition parser");