blob: e30a5acf569200e89e237e464936732288f98c80 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) ASR Microelectronics 2023
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/mtd/mtd.h>
#include <linux/slab.h>
#include <linux/mtd/partitions.h>
#include "../mtdsplit/mtdsplit.h"
#define ASR_SDTIM_PARTS 1
#define ASR_TIMH_OFFSET 0x4
#define ASR_SDTIM_OFFSET 0x38
#define ASR_IMGID_OFFSET 0x98
#define ASR_TIMH_MAGIC 0x54494D48 // TIMH
#define ASR_SDTIM_MAGIC 0x5354494D // STIM
static int check_asr_fs_with_sdtim(struct mtd_info *master,
const struct mtd_partition *part)
{
void *buf;
size_t retlen;
int err;
u32 magic_tim, magic_sdtim;
#ifdef CONFIG_ASR_SDTIM
/*
* For filesystem partition with sdtim header, force to create
* "-sdtim" and "-mount" to make sure A/B fs mount succeed even
* one of sdtim header and fs area destroied, by adding property
* "sdtim-fs" to correspond partition node.
*/
if (of_get_property(part->of_node, "sdtim-fs", NULL))
return ASR_SDTIM_PARTS;
#endif
buf = kzalloc(master->writesize, GFP_KERNEL);
if (!buf)
return -ENOMEM;
err = mtd_read(master, part->offset, master->writesize, &retlen, buf);
if (err && err != -EUCLEAN)
goto free_buf;
if (retlen != master->writesize) {
err = -EIO;
goto free_buf;
}
magic_tim = *((u32 *)(buf + ASR_TIMH_OFFSET));
magic_sdtim = *((u32 *)(buf + ASR_SDTIM_OFFSET));
if (magic_tim != ASR_TIMH_MAGIC || magic_sdtim != ASR_SDTIM_MAGIC) {
err = 0;
goto free_buf;
}
if (part->size <= master->erasesize) {
err = 0;
goto free_buf;
}
/* check if this part may exist filesystem, read from next block */
err = mtd_check_rootfs_magic(master, part->offset + master->erasesize, NULL);
if (err) {
err = 0;
goto free_buf;
}
kfree(buf);
return ASR_SDTIM_PARTS;
free_buf:
kfree(buf);
return err;
}
int asr_sdtim_partitions_post_parse(struct mtd_info *mtd,
struct mtd_partition **pparts, int nr_parts)
{
struct mtd_partition *parts = *pparts;
struct mtd_partition *nparts;
int new_nr = 0;
int i;
nparts = kcalloc(nr_parts * 2 + 1, sizeof(*parts), GFP_KERNEL);
if (!nparts)
return -ENOMEM;
for (i = 0; i < nr_parts; i++) {
#ifdef CONFIG_AB_SYSTEM
/* add "-sdtim" and "-mount" for sdtim img with filesystem */
if (check_asr_fs_with_sdtim(mtd, parts + i) > 0) {
/* add -sdtim partition */
nparts[new_nr].name = kstrdup(parts[i].name, GFP_KERNEL);
strcat((char *)nparts[new_nr].name, "-sdtim");
nparts[new_nr].offset = parts[i].offset;
nparts[new_nr].size = mtd->erasesize;
nparts[new_nr].mask_flags = parts[i].mask_flags;
nparts[new_nr].types = parts[i].types;
nparts[new_nr].of_node = parts[i].of_node;
new_nr++;
/* add -mount partition */
nparts[new_nr].name = kmemdup(parts[i].name, 128, GFP_KERNEL);
strcat((char *)nparts[new_nr].name, "-mount");
nparts[new_nr].offset = parts[i].offset + mtd->erasesize;
nparts[new_nr].size = parts[i].size - mtd->erasesize;
nparts[new_nr].mask_flags = parts[i].mask_flags;
nparts[new_nr].types = parts[i].types;
nparts[new_nr].of_node = parts[i].of_node;
new_nr++;
}
/* copy original partition */
nparts[new_nr].name = kstrdup(parts[i].name, GFP_KERNEL);
nparts[new_nr].offset = parts[i].offset;
nparts[new_nr].size = parts[i].size;
nparts[new_nr].mask_flags = parts[i].mask_flags;
nparts[new_nr].types = parts[i].types;
nparts[new_nr].of_node = parts[i].of_node;
new_nr++;
#else
if (check_asr_fs_with_sdtim(mtd, parts + i) > 0) {
/* add -sdtim partition */
nparts[new_nr].name = kstrdup(parts[i].name, GFP_KERNEL);
strcat((char *)nparts[new_nr].name, "-sdtim");
nparts[new_nr].offset = parts[i].offset;
nparts[new_nr].size = mtd->erasesize;
nparts[new_nr].mask_flags = parts[i].mask_flags;
nparts[new_nr].types = parts[i].types;
nparts[new_nr].of_node = parts[i].of_node;
new_nr++;
nparts[new_nr].name = kstrdup(parts[i].name, GFP_KERNEL);
nparts[new_nr].offset = parts[i].offset + mtd->erasesize;
nparts[new_nr].size = parts[i].size - mtd->erasesize;
nparts[new_nr].mask_flags = parts[i].mask_flags;
nparts[new_nr].types = parts[i].types;
nparts[new_nr].of_node = parts[i].of_node;
new_nr++;
} else {
/* copy original partition */
nparts[new_nr].name = kstrdup(parts[i].name, GFP_KERNEL);
nparts[new_nr].offset = parts[i].offset;
nparts[new_nr].size = parts[i].size;
nparts[new_nr].mask_flags = parts[i].mask_flags;
nparts[new_nr].types = parts[i].types;
nparts[new_nr].of_node = parts[i].of_node;
new_nr++;
}
#endif
}
kfree(parts);
*pparts = nparts;
return new_nr;
}