122 lines
3.0 KiB
C
122 lines
3.0 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "aml_part: " fmt
|
|
|
|
#include <common.h>
|
|
#include <errno.h>
|
|
#include <linux/err.h>
|
|
#include <linux/compat.h>
|
|
#include <linux/mtd/mtd.h>
|
|
#include <linux/mtd/partitions.h>
|
|
#include <linux/mtd/spinand.h>
|
|
#include <amlogic/aml_mtd.h>
|
|
#include <amlogic/storage.h>
|
|
#include <amlogic/aml_rsv.h>
|
|
|
|
static void mtd_get_logic_part_info(struct mtd_info *mtd,
|
|
struct mtd_partition *part)
|
|
{
|
|
loff_t offset = part->offset, end = part->offset + part->size;
|
|
loff_t append_size = 0;
|
|
|
|
#ifdef CONFIG_NOT_SKIP_BAD_BLOCK
|
|
return;
|
|
#endif
|
|
|
|
do {
|
|
if (mtd->_block_isbad(mtd, offset) == NAND_FACTORY_BAD) {
|
|
pr_err("%s %d found bad block in 0x%llx\n",
|
|
__func__, __LINE__, offset);
|
|
end += mtd->erasesize;
|
|
append_size += mtd->erasesize;
|
|
}
|
|
offset += mtd->erasesize;
|
|
} while (offset < end && offset < mtd->size);
|
|
part->size += append_size;
|
|
}
|
|
|
|
static inline void set_part_info(struct mtd_partition *part,
|
|
const char *name, uint64_t offset, uint64_t size)
|
|
{
|
|
part->name = name;
|
|
part->offset = offset;
|
|
part->size = size;
|
|
}
|
|
|
|
uint64_t mtd_get_normal_part_offset(struct mtd_info *mtd)
|
|
{
|
|
if (mtd->type == MTD_NORFLASH)
|
|
return mtd_spinor_get_bootpart_size();
|
|
else
|
|
return meson_rsv_part_get_tpl_start(mtd) + meson_rsv_part_get_tpl_size(mtd);
|
|
}
|
|
|
|
int mtd_register_partitions(struct mtd_info *mtd,
|
|
const struct mtd_partition *parts,
|
|
int nbparts, bool nand)
|
|
{
|
|
struct mtd_partition *new_part, *p, *normal, bl2_part[1] = { 0 };
|
|
u64 normal_offset;
|
|
int i, n = nbparts, ret;
|
|
|
|
if (!nbparts && nand) {
|
|
set_part_info(&bl2_part[0], BOOT_BL2, 0,
|
|
meson_rsv_part_get_bl2_part_size(mtd));
|
|
return add_mtd_partitions(mtd, &bl2_part[0], 1);
|
|
}
|
|
|
|
/* Maybe need extra two more parts <bl2 and tpl> */
|
|
new_part = kcalloc(n + 2, sizeof(*new_part), GFP_KERNEL);
|
|
if (!new_part)
|
|
return -ENOMEM;
|
|
|
|
p = new_part;
|
|
if (mtd->type == MTD_NORFLASH) {
|
|
set_part_info(p++, BOOT_LOADER, 0,
|
|
mtd_spinor_get_bootpart_size());
|
|
} else {
|
|
/* simplify that bootloader only has BL2 + TPL */
|
|
if (!nand)
|
|
set_part_info(p++, BOOT_BL2, 0,
|
|
meson_rsv_part_get_bl2_part_size(mtd));
|
|
|
|
set_part_info(p++, BOOT_TPL,
|
|
meson_rsv_part_get_tpl_start(mtd),
|
|
meson_rsv_part_get_tpl_size(mtd));
|
|
}
|
|
|
|
normal = p;
|
|
|
|
/* filter out these partitions with wrong size ZERO */
|
|
for (i = 0; i < nbparts; i++) {
|
|
if (!parts[i].size && !parts[i].offset)
|
|
continue;
|
|
*p++ = parts[i];
|
|
}
|
|
|
|
normal_offset = mtd_get_normal_part_offset(mtd);
|
|
nbparts = p - new_part;
|
|
n = p - normal;
|
|
for (i = 0, p = normal; i < n; i++, p++) {
|
|
if ((normal_offset + p->size) > mtd->size) {
|
|
pr_err("over flash size!\n");
|
|
kfree(new_part);
|
|
return -1;
|
|
}
|
|
p->offset = normal_offset;
|
|
if (mtd->type != MTD_NORFLASH)
|
|
mtd_get_logic_part_info(mtd, p);
|
|
if (i == (n - 1))
|
|
p->size = mtd->size - normal_offset;
|
|
normal_offset += p->size;
|
|
}
|
|
|
|
ret = add_mtd_partitions(mtd, new_part, nbparts);
|
|
kfree(new_part);
|
|
|
|
return ret;
|
|
}
|