| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| */ |
| |
| #include <common.h> |
| #include <dm.h> |
| #include <errno.h> |
| #include <malloc.h> |
| #include <spi.h> |
| #include <spi_flash.h> |
| #include <linux/mtd/partitions.h> |
| #include <linux/types.h> |
| #include <linux/sizes.h> |
| #include <malloc.h> |
| #include <linux/errno.h> |
| #include <mtd.h> |
| #include <amlogic/aml_mtd.h> |
| #include <amlogic/storage.h> |
| #include <amlogic/cpu_id.h> |
| |
| /* Hard code, all partitions are aligned in block size, fast erasing */ |
| #define SPINOR_ALIGNED_SIZE (64 * 1024) |
| extern struct storage_startup_parameter g_ssp; |
| |
| /* do not use default value, rewrite this function in the board file */ |
| uint64_t __weak spiflash_bootloader_size(void) |
| { |
| return SZ_2M; |
| } |
| |
| uint32_t __weak spiflash_rsv_block_num(void) |
| { |
| return 0; |
| } |
| |
| extern boot_area_entry_t general_boot_part_entry[MAX_BOOT_AREA_ENTRIES]; |
| /* The size of the partition must be block aligned */ |
| static int _spinor_add_partitions(struct mtd_info *mtd, |
| const struct mtd_partition *parts, |
| int nbparts) |
| { |
| int part_num = 0, i = 0; |
| struct mtd_partition *temp, *parts_nm; |
| loff_t off; |
| |
| if (store_get_device_bootloader_mode() == DISCRETE_BOOTLOADER) |
| /* spinor add discrete mode for advanced */ |
| part_num = nbparts + 5; |
| else |
| part_num = nbparts + 1; |
| |
| temp = kzalloc(sizeof(*temp) * part_num, GFP_KERNEL); |
| memset(temp, 0, sizeof(*temp) * part_num); |
| if (store_get_device_bootloader_mode() == DISCRETE_BOOTLOADER) { |
| temp[BOOT_AREA_BB1ST].name = BOOT_LOADER; |
| temp[BOOT_AREA_BB1ST].offset = general_boot_part_entry[BOOT_AREA_BB1ST].offset; |
| temp[BOOT_AREA_BB1ST].size = general_boot_part_entry[BOOT_AREA_BB1ST].size * g_ssp.boot_bakups; |
| if (temp[BOOT_AREA_BB1ST].size % SPINOR_ALIGNED_SIZE) |
| WARN_ON(1); |
| |
| temp[BOOT_AREA_BL2E].name = BOOT_BL2E; |
| temp[BOOT_AREA_BL2E].offset = general_boot_part_entry[BOOT_AREA_BL2E].offset; |
| temp[BOOT_AREA_BL2E].size = general_boot_part_entry[BOOT_AREA_BL2E].size * g_ssp.boot_bakups; |
| if (temp[0].size % SPINOR_ALIGNED_SIZE) |
| WARN_ON(1); |
| |
| temp[BOOT_AREA_BL2X].name = BOOT_BL2X; |
| temp[BOOT_AREA_BL2X].offset = general_boot_part_entry[BOOT_AREA_BL2X].offset; |
| temp[BOOT_AREA_BL2X].size = general_boot_part_entry[BOOT_AREA_BL2X].size * g_ssp.boot_bakups; |
| if (temp[0].size % SPINOR_ALIGNED_SIZE) |
| WARN_ON(1); |
| |
| temp[BOOT_AREA_DDRFIP].name = BOOT_DDRFIP; |
| temp[BOOT_AREA_DDRFIP].offset = general_boot_part_entry[BOOT_AREA_DDRFIP].offset; |
| temp[BOOT_AREA_DDRFIP].size = general_boot_part_entry[BOOT_AREA_DDRFIP].size * g_ssp.boot_bakups; |
| if (temp[0].size % SPINOR_ALIGNED_SIZE) |
| WARN_ON(1); |
| |
| temp[BOOT_AREA_DEVFIP].name = BOOT_DEVFIP; |
| temp[BOOT_AREA_DEVFIP].offset = general_boot_part_entry[BOOT_AREA_DEVFIP].offset; |
| temp[BOOT_AREA_DEVFIP].size = general_boot_part_entry[BOOT_AREA_DEVFIP].size * |
| CONFIG_NOR_TPL_COPY_NUM; |
| if (temp[0].size % SPINOR_ALIGNED_SIZE) |
| WARN_ON(1); |
| |
| off = temp[BOOT_AREA_DEVFIP].offset + temp[BOOT_AREA_DEVFIP].size; |
| parts_nm = &temp[5]; |
| } else { |
| temp[0].name = BOOT_LOADER; |
| temp[0].offset = 0; |
| temp[0].size = spiflash_bootloader_size(); |
| if (temp[0].size % SPINOR_ALIGNED_SIZE) |
| WARN_ON(1); |
| /* rsv size is aligned with blocksize(64K) */ |
| off = temp[0].size + spiflash_rsv_block_num() * SPINOR_ALIGNED_SIZE; |
| parts_nm = &temp[1]; |
| } |
| for (i = 0; i < nbparts; i++) { |
| if (!parts[i].name) { |
| pr_err("name can't be null! "); |
| pr_err("please check your %d th partition name!\n", |
| i + 1); |
| return 1; |
| } |
| if ((off + parts[i].size) > mtd->size) { |
| pr_err("%s %d over nand size!\n", |
| __func__, __LINE__); |
| return 1; |
| } |
| parts_nm[i].name = parts[i].name; |
| parts_nm[i].offset = off; |
| if (parts[i].size % SPINOR_ALIGNED_SIZE) { |
| pr_err("%s %d \"%s\" size auto align to block size\n", |
| __func__, __LINE__, parts[i].name); |
| parts_nm[i].size += parts[i].size % SPINOR_ALIGNED_SIZE; |
| } |
| /* it's ok "+=" here because size has been set to 0 */ |
| parts_nm[i].size += parts[i].size; |
| off += parts_nm[i].size; |
| if (i == (nbparts - 1)) |
| parts_nm[i].size = mtd->size - off; |
| } |
| |
| return add_mtd_partitions(mtd, temp, part_num); |
| } |
| |
| extern struct mtd_partition *get_spiflash_partition_table(int *partitions); |
| int spinor_add_partitions(struct mtd_info *mtd) |
| { |
| struct mtd_partition *spiflash_partitions; |
| int partition_count; |
| |
| spiflash_partitions = get_spiflash_partition_table(&partition_count); |
| |
| return _spinor_add_partitions(mtd, spiflash_partitions, |
| partition_count); |
| } |
| |
| int spinor_del_partitions(struct mtd_info *mtd) |
| { |
| return del_mtd_partitions(mtd); |
| } |