[Feature] add GA346 baseline version
Change-Id: Ic62933698569507dcf98240cdf5d9931ae34348f
diff --git a/src/kernel/linux/v4.19/drivers/mtd/pmtpart.c b/src/kernel/linux/v4.19/drivers/mtd/pmtpart.c
new file mode 100644
index 0000000..a2cfd8b
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/mtd/pmtpart.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Guochun Mao <guochun.mao@mediatek.com>
+ * Xiaolei Li <xiaolei.li@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/div64.h>
+
+#define MAX_PARTITION_COUNT 128
+#define MAX_PARTITION_NAME_LEN 64
+#define PT_SIG 0x50547633 //"PTv3"
+#define MPT_SIG 0x4D505433 //"MPT3"
+#define PT_SIG_SIZE 8
+
+#define is_valid_mpt(buf) ((*(uint32_t *)(buf)) == MPT_SIG)
+#define is_valid_pt(buf) ((*(uint32_t *)(buf)) == PT_SIG)
+#define is_valid_pt_v1(buf) ((*(uint32_t *)(buf)) == PT_SIG_V1)
+
+typedef struct
+{
+ unsigned char name[MAX_PARTITION_NAME_LEN]; /* partition name */
+ unsigned long long size; /* partition size */
+ unsigned long long part_id; /* partition region */ //will be used as download type on L branch. xiaolei
+ unsigned long long offset; /* partition start */
+ unsigned long long mask_flags; /* partition flags */
+} pt_resident;
+
+static void pmt_add_part(struct mtd_partition *part, char *name,
+ u64 offset, uint32_t mask_flags, uint64_t size)
+{
+ part->name = kstrdup_const(name, GFP_KERNEL);
+ part->offset = offset;
+ part->mask_flags = mask_flags;
+ part->size = size;
+}
+
+static int pmt_parse(struct mtd_info *master,
+ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+{
+ struct mtd_partition *parts;
+ int err, i;
+ u_char *buf;
+ u32 pmt_size = sizeof(pt_resident) * MAX_PARTITION_COUNT;
+ u8 pmt[PT_SIG_SIZE] = {0};
+ pt_resident *pt;
+ size_t bytes_read = 0;
+ loff_t pmt_start_addr = (loff_t)master->size - 6 * (loff_t)master->erasesize;
+ u8 max_partition_count = 0;
+
+ dev_dbg(&master->dev, "PMT: enter pmt parser...\n");
+
+ buf = kzalloc(pmt_size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ pt = (pt_resident *)buf;
+ err = mtd_read(master, pmt_start_addr, sizeof(pmt), &bytes_read, pmt);
+ if (err < 0)
+ goto freebuf;
+
+ /* look for the PMT tag */
+ if (is_valid_mpt(pmt) == 0 && is_valid_pt(pmt) == 0) {
+ dev_err(&master->dev, "PMT: not find sig in 1st PMT block, try 2nd one\n");
+ pmt_start_addr += master->erasesize;
+ err = mtd_read(master, pmt_start_addr, sizeof(pmt), &bytes_read, pmt);
+ if (err < 0)
+ goto freebuf;
+ if (is_valid_mpt(pmt) == 0 && is_valid_pt(pmt) == 0) {
+ dev_err(&master->dev, "PMT: not find sig in 2st PMT block, give up\n");
+ goto freebuf;
+ }
+ }
+
+ err = mtd_read(master, pmt_start_addr + PT_SIG_SIZE, pmt_size, &bytes_read, buf);
+ if (err < 0)
+ goto freebuf;
+
+ for (i = 0 ; i < MAX_PARTITION_COUNT ; i++) {
+ if (strlen(pt[i].name) == 0)
+ break;
+ }
+ max_partition_count = i;
+ dev_dbg(&master->dev, "pmt there are <%d> parititons.\n",
+ max_partition_count);
+
+ parts = kcalloc(max_partition_count,
+ sizeof(struct mtd_partition), GFP_KERNEL);
+ if (parts == NULL)
+ goto freebuf;
+
+ for (i = 0 ; i < max_partition_count ; i++) {
+ pmt_add_part(&parts[i], pt[i].name,
+ pt[i].offset, 0, pt[i].size);
+
+ }
+
+parsedone:
+ *pparts = parts;
+ kfree(buf);
+ return max_partition_count;
+
+freebuf:
+ kfree(buf);
+ return 0;
+};
+
+static struct mtd_part_parser pmt_parser = {
+ .owner = THIS_MODULE,
+ .parse_fn = pmt_parse,
+ .name = "pmtpart",
+};
+
+static int __init pmtpart_init(void)
+{
+ return register_mtd_parser(&pmt_parser);
+}
+
+static void __exit pmtpart_exit(void)
+{
+ deregister_mtd_parser(&pmt_parser);
+}
+
+module_init(pmtpart_init);
+module_exit(pmtpart_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMT partitioning for flash memories");