From de24bc7e0e3528f3d3c4731ab053a3e8d621ab7a Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 28 Oct 2020 15:09:59 +0100 Subject: [PATCH 1/5] mips: start.S: Add Octeon boot header compatibility Octeon has a specific boot header, when booted via SPI NOR, NAND or MMC. Here the only 2 instructions are allowed in the first few bytes of the image. And these instructions need to be one branch and a nop. This patch adds the necessary nop after the nop, to that the common MIPS image is compatible with this Octeon header. The tool to patch the Octeon boot header into the image will be send in a follow-up patch. Signed-off-by: Stefan Roese Cc: Aaron Williams Cc: Chandrakala Chavva Cc: Daniel Schwierzeck Reviewed-by: Daniel Schwierzeck --- arch/mips/cpu/start.S | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index d0c412236dd..335aafa6a8d 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -74,9 +74,14 @@ .endm ENTRY(_start) - /* U-Boot entry point */ + /* + * U-Boot entry point. + * Do not add instructions to the branch delay slot! Some SoC's + * like Octeon might patch the final U-Boot binary at this location + * with additional boot headers. + */ b reset - mtc0 zero, CP0_COUNT # clear cp0 count for most accurate boot timing + nop #if defined(CONFIG_MIPS_INSERT_BOOT_CONFIG) /* @@ -123,6 +128,7 @@ ENTRY(_start) #endif reset: + mtc0 zero, CP0_COUNT # clear cp0 count for most accurate boot timing #if __mips_isa_rev >= 6 mfc0 t0, CP0_CONFIG, 5 and t0, t0, MIPS_CONF5_VP From 8a138257dd4d6b7de27de9645a868dd56e6018f1 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 28 Oct 2020 15:10:00 +0100 Subject: [PATCH 2/5] mips: octeon: Fix Octeon DDR driver to use the correct struct Don't use "platdata_auto_alloc_size" but "priv_auto_alloc_size" instead to auto allocate the private data struct, which is referenced via dev_get_priv() in this driver. This fixes an ugly bug detected while trying to boot via SPI NOR. Signed-off-by: Stefan Roese Cc: Aaron Williams Cc: Chandrakala Chavva Cc: Daniel Schwierzeck --- drivers/ram/octeon/octeon_ddr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ram/octeon/octeon_ddr.c b/drivers/ram/octeon/octeon_ddr.c index 757436b9d37..aaff9c36879 100644 --- a/drivers/ram/octeon/octeon_ddr.c +++ b/drivers/ram/octeon/octeon_ddr.c @@ -2724,5 +2724,5 @@ U_BOOT_DRIVER(octeon_ddr) = { .of_match = octeon_ids, .ops = &octeon_ops, .probe = octeon_ddr_probe, - .platdata_auto_alloc_size = sizeof(struct ddr_priv), + .priv_auto_alloc_size = sizeof(struct ddr_priv), }; From 8bab2c893c33b0245c51a71e91effe3547a73524 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 28 Oct 2020 15:10:01 +0100 Subject: [PATCH 3/5] mips: octeon: Report full DDR size in dram_init() to gd->ram_size With this patch, gd->ram_size now holds to full RAM size detected by the DDR init code. It introduces the get_effective_memsize() function to report the maximum usable RAM size in U-Boot to the system instead. Signed-off-by: Stefan Roese Cc: Aaron Williams Cc: Chandrakala Chavva Cc: Daniel Schwierzeck Reviewed-by: Daniel Schwierzeck --- arch/mips/mach-octeon/dram.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/mach-octeon/dram.c b/arch/mips/mach-octeon/dram.c index 6dc08e19da4..4679260f17a 100644 --- a/arch/mips/mach-octeon/dram.c +++ b/arch/mips/mach-octeon/dram.c @@ -33,7 +33,7 @@ int dram_init(void) return ret; } - gd->ram_size = min_t(size_t, ram.size, UBOOT_RAM_SIZE_MAX); + gd->ram_size = ram.size; debug("SDRAM base=%lx, size=%lx\n", (unsigned long)ram.base, (unsigned long)ram.size); } else { @@ -72,6 +72,11 @@ void board_add_ram_info(int use_default) } } +phys_size_t get_effective_memsize(void) +{ + return UBOOT_RAM_SIZE_MAX; +} + ulong board_get_usable_ram_top(ulong total_size) { if (IS_ENABLED(CONFIG_RAM_OCTEON)) { From b7eac19a3d91fae05250688ed4047c1a5d68dd42 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 28 Oct 2020 15:10:02 +0100 Subject: [PATCH 4/5] mips: octeon: bootoctlinux: Use gd->ram_size instead of ram_get_info() Using ram_get_info() is complicated and does not work after relocation. Now that gd->ram_size holds the full RAM size, let's use it instead and remove the ram_get_size logic completely. Signed-off-by: Stefan Roese Cc: Aaron Williams Cc: Chandrakala Chavva Cc: Daniel Schwierzeck Reviewed-by: Daniel Schwierzeck --- arch/mips/mach-octeon/bootoctlinux.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/arch/mips/mach-octeon/bootoctlinux.c b/arch/mips/mach-octeon/bootoctlinux.c index 75d7e83bd71..26136902f34 100644 --- a/arch/mips/mach-octeon/bootoctlinux.c +++ b/arch/mips/mach-octeon/bootoctlinux.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -370,8 +369,6 @@ int do_bootoctlinux(struct cmd_tbl *cmdtp, int flag, int argc, struct cvmx_coremask avail_coremask; int first_core; int core; - struct ram_info ram; - struct udevice *dev; const u64 *nmi_code; int num_dwords; u8 node_mask = 0x01; @@ -470,19 +467,6 @@ int do_bootoctlinux(struct cmd_tbl *cmdtp, int flag, int argc, */ cvmx_coremask_or(&coremask_to_run, &coremask_to_run, &core_mask); - /* Get RAM size */ - ret = uclass_get_device(UCLASS_RAM, 0, &dev); - if (ret) { - debug("DRAM init failed: %d\n", ret); - return ret; - } - - ret = ram_get_info(dev, &ram); - if (ret) { - debug("Cannot get DRAM size: %d\n", ret); - return ret; - } - /* * Load kernel ELF image, or try binary if ELF is not detected. * This way the much smaller vmlinux.bin can also be started but @@ -498,7 +482,7 @@ int do_bootoctlinux(struct cmd_tbl *cmdtp, int flag, int argc, /* Init bootmem list for Linux kernel booting */ if (!cvmx_bootmem_phy_mem_list_init( - ram.size, OCTEON_RESERVED_LOW_MEM_SIZE, + gd->ram_size, OCTEON_RESERVED_LOW_MEM_SIZE, (void *)CKSEG0ADDR(BOOTLOADER_BOOTMEM_DESC_SPACE))) { printf("FATAL: Error initializing free memory list\n"); return 0; @@ -517,7 +501,8 @@ int do_bootoctlinux(struct cmd_tbl *cmdtp, int flag, int argc, if (core == first_core) cvmx_bootinfo_array[core].flags |= BOOT_FLAG_INIT_CORE; - cvmx_bootinfo_array[core].dram_size = ram.size / (1024 * 1024); + cvmx_bootinfo_array[core].dram_size = gd->ram_size / + (1024 * 1024); cvmx_bootinfo_array[core].dclock_hz = gd->mem_clk * 1000000; cvmx_bootinfo_array[core].eclock_hz = gd->cpu_clk; From 540a2bcec1389a3a31c23b5275e73186be6102b2 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 30 Nov 2020 13:14:23 +0100 Subject: [PATCH 5/5] mips: octeon: tools: Add update_octeon_header tool Add a tool to update or insert an Octeon specific header into the U-Boot image. This is needed e.g. for booting via SPI NOR, eMMC and NAND. While working on this, move enum cvmx_board_types_enum and cvmx_board_type_to_string() to cvmx-bootloader.h and remove the unreferenced (unsupported) board definition. Signed-off-by: Stefan Roese Cc: Aaron Williams Cc: Chandrakala Chavva Cc: Daniel Schwierzeck Reviewed-by: Daniel Schwierzeck --- .../mach-octeon/include/mach/cvmx-bootinfo.h | 222 --------- .../include/mach/cvmx-bootloader.h | 172 +++++++ tools/.gitignore | 1 + tools/Makefile | 3 + tools/update_octeon_header.c | 456 ++++++++++++++++++ 5 files changed, 632 insertions(+), 222 deletions(-) create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-bootloader.h create mode 100644 tools/update_octeon_header.c diff --git a/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h b/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h index 337987178f4..97438ff787a 100644 --- a/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h +++ b/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h @@ -125,226 +125,4 @@ struct cvmx_bootinfo { #endif /* (CVMX_BOOTINFO_MAJ_VER == 1) */ -/* Type defines for board and chip types */ -enum cvmx_board_types_enum { - CVMX_BOARD_TYPE_NULL = 0, - CVMX_BOARD_TYPE_SIM = 1, - CVMX_BOARD_TYPE_EBT3000 = 2, - CVMX_BOARD_TYPE_KODAMA = 3, - CVMX_BOARD_TYPE_NIAGARA = 4, - CVMX_BOARD_TYPE_NAC38 = 5, /* formerly NAO38 */ - CVMX_BOARD_TYPE_THUNDER = 6, - CVMX_BOARD_TYPE_TRANTOR = 7, - CVMX_BOARD_TYPE_EBH3000 = 8, - CVMX_BOARD_TYPE_EBH3100 = 9, - CVMX_BOARD_TYPE_HIKARI = 10, - CVMX_BOARD_TYPE_CN3010_EVB_HS5 = 11, - CVMX_BOARD_TYPE_CN3005_EVB_HS5 = 12, - CVMX_BOARD_TYPE_KBP = 13, - /* Deprecated, CVMX_BOARD_TYPE_CN3010_EVB_HS5 supports the CN3020 */ - CVMX_BOARD_TYPE_CN3020_EVB_HS5 = 14, - CVMX_BOARD_TYPE_EBT5800 = 15, - CVMX_BOARD_TYPE_NICPRO2 = 16, - CVMX_BOARD_TYPE_EBH5600 = 17, - CVMX_BOARD_TYPE_EBH5601 = 18, - CVMX_BOARD_TYPE_EBH5200 = 19, - CVMX_BOARD_TYPE_BBGW_REF = 20, - CVMX_BOARD_TYPE_NIC_XLE_4G = 21, - CVMX_BOARD_TYPE_EBT5600 = 22, - CVMX_BOARD_TYPE_EBH5201 = 23, - CVMX_BOARD_TYPE_EBT5200 = 24, - CVMX_BOARD_TYPE_CB5600 = 25, - CVMX_BOARD_TYPE_CB5601 = 26, - CVMX_BOARD_TYPE_CB5200 = 27, - /* Special 'generic' board type, supports many boards */ - CVMX_BOARD_TYPE_GENERIC = 28, - CVMX_BOARD_TYPE_EBH5610 = 29, - CVMX_BOARD_TYPE_LANAI2_A = 30, - CVMX_BOARD_TYPE_LANAI2_U = 31, - CVMX_BOARD_TYPE_EBB5600 = 32, - CVMX_BOARD_TYPE_EBB6300 = 33, - CVMX_BOARD_TYPE_NIC_XLE_10G = 34, - CVMX_BOARD_TYPE_LANAI2_G = 35, - CVMX_BOARD_TYPE_EBT5810 = 36, - CVMX_BOARD_TYPE_NIC10E = 37, - CVMX_BOARD_TYPE_EP6300C = 38, - CVMX_BOARD_TYPE_EBB6800 = 39, - CVMX_BOARD_TYPE_NIC4E = 40, - CVMX_BOARD_TYPE_NIC2E = 41, - CVMX_BOARD_TYPE_EBB6600 = 42, - CVMX_BOARD_TYPE_REDWING = 43, - CVMX_BOARD_TYPE_NIC68_4 = 44, - CVMX_BOARD_TYPE_NIC10E_66 = 45, - CVMX_BOARD_TYPE_MAX, - - /* - * The range from CVMX_BOARD_TYPE_MAX to - * CVMX_BOARD_TYPE_CUST_DEFINED_MIN is reserved for future - * SDK use. - */ - - /* - * Set aside a range for customer boards. These numbers are managed - * by Cavium. - */ - CVMX_BOARD_TYPE_CUST_DEFINED_MIN = 10000, - CVMX_BOARD_TYPE_CUST_WSX16 = 10001, - CVMX_BOARD_TYPE_CUST_NS0216 = 10002, - CVMX_BOARD_TYPE_CUST_NB5 = 10003, - CVMX_BOARD_TYPE_CUST_WMR500 = 10004, - CVMX_BOARD_TYPE_CUST_ITB101 = 10005, - CVMX_BOARD_TYPE_CUST_NTE102 = 10006, - CVMX_BOARD_TYPE_CUST_AGS103 = 10007, - CVMX_BOARD_TYPE_CUST_GST104 = 10008, - CVMX_BOARD_TYPE_CUST_GCT105 = 10009, - CVMX_BOARD_TYPE_CUST_AGS106 = 10010, - CVMX_BOARD_TYPE_CUST_SGM107 = 10011, - CVMX_BOARD_TYPE_CUST_GCT108 = 10012, - CVMX_BOARD_TYPE_CUST_AGS109 = 10013, - CVMX_BOARD_TYPE_CUST_GCT110 = 10014, - CVMX_BOARD_TYPE_CUST_L2_AIR_SENDER = 10015, - CVMX_BOARD_TYPE_CUST_L2_AIR_RECEIVER = 10016, - CVMX_BOARD_TYPE_CUST_L2_ACCTON2_TX = 10017, - CVMX_BOARD_TYPE_CUST_L2_ACCTON2_RX = 10018, - CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_TX = 10019, - CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_RX = 10020, - CVMX_BOARD_TYPE_CUST_L2_ZINWELL = 10021, - CVMX_BOARD_TYPE_CUST_DEFINED_MAX = 20000, - - /* - * Set aside a range for customer private use. The SDK won't - * use any numbers in this range. - */ - CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, - CVMX_BOARD_TYPE_UBNT_E100 = 20002, - CVMX_BOARD_TYPE_CUST_DSR1000N = 20006, - CVMX_BOARD_TYPE_KONTRON_S1901 = 21901, - CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, - - /* The remaining range is reserved for future use. */ -}; - -enum cvmx_chip_types_enum { - CVMX_CHIP_TYPE_NULL = 0, - CVMX_CHIP_SIM_TYPE_DEPRECATED = 1, - CVMX_CHIP_TYPE_OCTEON_SAMPLE = 2, - CVMX_CHIP_TYPE_MAX, -}; - -/* - * Compatibility alias for NAC38 name change, planned to be removed - * from SDK 1.7 - */ -#define CVMX_BOARD_TYPE_NAO38 CVMX_BOARD_TYPE_NAC38 - -/* Functions to return string based on type */ -#define ENUM_BRD_TYPE_CASE(x) \ - case x: \ - return(#x + 16) /* Skip CVMX_BOARD_TYPE_ */ - -static inline const char *cvmx_board_type_to_string(enum - cvmx_board_types_enum type) -{ - switch (type) { - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NULL); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_SIM); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT3000); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KODAMA); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIAGARA); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NAC38); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_THUNDER); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_TRANTOR); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH3000); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH3100); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_HIKARI); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3010_EVB_HS5); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3005_EVB_HS5); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KBP); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3020_EVB_HS5); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5800); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NICPRO2); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5600); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5601); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5200); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_BBGW_REF); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC_XLE_4G); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5600); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5201); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5200); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5600); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5601); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5200); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_GENERIC); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5610); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_A); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_U); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB5600); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6300); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC_XLE_10G); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_G); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5810); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EP6300C); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6800); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC4E); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC2E); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6600); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_REDWING); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC68_4); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E_66); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_MAX); - - /* Customer boards listed here */ - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MIN); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_WSX16); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NS0216); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NB5); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_WMR500); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_ITB101); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NTE102); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS103); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GST104); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT105); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS106); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_SGM107); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT108); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS109); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT110); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_AIR_SENDER); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_AIR_RECEIVER); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ACCTON2_TX); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ACCTON2_RX); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_TX); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_RX); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ZINWELL); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MAX); - - /* Customer private range */ - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DSR1000N); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KONTRON_S1901); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX); - } - - return NULL; -} - -#define ENUM_CHIP_TYPE_CASE(x) \ - case x: \ - return(#x + 15) /* Skip CVMX_CHIP_TYPE */ - -static inline const char *cvmx_chip_type_to_string(enum - cvmx_chip_types_enum type) -{ - switch (type) { - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_NULL); - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_SIM_TYPE_DEPRECATED); - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_OCTEON_SAMPLE); - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_MAX); - } - - return "Unsupported Chip"; -} - #endif /* __CVMX_BOOTINFO_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-bootloader.h b/arch/mips/mach-octeon/include/mach/cvmx-bootloader.h new file mode 100644 index 00000000000..9abe0214523 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-bootloader.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +/* + * Bootloader definitions that are shared with other programs + */ + +#ifndef __CVMX_BOOTLOADER__ +#define __CVMX_BOOTLOADER__ + +/* + * The bootloader_header_t structure defines the header that is present + * at the start of binary u-boot images. This header is used to locate + * the bootloader image in NAND, and also to allow verification of images + * for normal NOR booting. This structure is placed at the beginning of a + * bootloader binary image, and remains in the executable code. + */ +#define BOOTLOADER_HEADER_MAGIC 0x424f4f54 /* "BOOT" in ASCII */ + +#define BOOTLOADER_HEADER_COMMENT_LEN 64 +#define BOOTLOADER_HEADER_VERSION_LEN 64 +/* limited by the space to the next exception handler */ +#define BOOTLOADER_HEADER_MAX_SIZE 0x200 + +#define BOOTLOADER_HEADER_CURRENT_MAJOR_REV 1 +#define BOOTLOADER_HEADER_CURRENT_MINOR_REV 2 +/* + * Revision history + * 1.1 Initial released revision. (SDK 1.9) + * 1.2 TLB based relocatable image (SDK 2.0) + */ + +#ifndef __ASSEMBLY__ +struct bootloader_header { + uint32_t jump_instr; /* + * Jump to executable code following the + * header. This allows this header to be + * (and remain) part of the executable image) + */ + uint32_t nop_instr; /* Must be 0x0 */ + uint32_t magic; /* Magic number to identify header */ + uint32_t hcrc; /* CRC of all of header excluding this field */ + + uint16_t hlen; /* Length of header in bytes */ + uint16_t maj_rev; /* Major revision */ + uint16_t min_rev; /* Minor revision */ + uint16_t board_type; /* Board type that the image is for */ + + uint32_t dlen; /* Length of data (following header) in bytes */ + uint32_t dcrc; /* CRC of data */ + uint64_t address; /* Mips virtual address */ + uint32_t flags; + uint16_t image_type; /* Defined in bootloader_image_t enum */ + uint16_t resv0; /* pad */ + + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint32_t reserved4; + + /* Optional, for descriptive purposes */ + char comment_string[BOOTLOADER_HEADER_COMMENT_LEN]; + /* Optional, for descriptive purposes */ + char version_string[BOOTLOADER_HEADER_VERSION_LEN]; +} __packed; + +/* Defines for flag field */ +#define BL_HEADER_FLAG_FAILSAFE 1 + +enum bootloader_image { + BL_HEADER_IMAGE_UNKNOWN = 0x0, + BL_HEADER_IMAGE_STAGE2, /* Binary bootloader stage2 image */ + BL_HEADER_IMAGE_STAGE3, /* Binary bootloader stage3 image */ + BL_HEADER_IMAGE_NOR, /* Binary bootloader for NOR boot */ + BL_HEADER_IMAGE_PCIBOOT, /* Binary bootloader for PCI boot */ + BL_HEADER_IMAGE_UBOOT_ENV, /* Environment for u-boot */ + /* Bootloader before U-Boot (stage 1/1.5) */ + BL_HEADER_IMAGE_PRE_UBOOT, + BL_HEADER_IMAGE_STAGE1, /* NOR stage 1 bootloader */ + BL_HEADER_IMAGE_MAX, + /* Range for customer private use. Will not be used by Cavium Inc. */ + BL_HEADER_IMAGE_CUST_RESERVED_MIN = 0x1000, + BL_HEADER_IMAGE_CUST_RESERVED_MAX = 0x1fff +}; + +#endif /* __ASSEMBLY__ */ + +/* + * Maximum address searched for NAND boot images and environments. + * This is used by stage1 and stage2. + */ +#define MAX_NAND_SEARCH_ADDR 0x800000 + +/* Maximum address to look for start of normal bootloader */ +#define MAX_NOR_SEARCH_ADDR 0x400000 + +/* + * Defines for RAM based environment set by the host or the previous + * bootloader in a chain boot configuration. + */ + +#define U_BOOT_RAM_ENV_ADDR 0x1000 +#define U_BOOT_RAM_ENV_SIZE 0x1000 +#define U_BOOT_RAM_ENV_CRC_SIZE 0x4 +#define U_BOOT_RAM_ENV_ADDR_2 (U_BOOT_RAM_ENV_ADDR + U_BOOT_RAM_ENV_SIZE) +/* Address of environment in L2 cache if booted from cache */ +#define U_BOOT_CACHE_ENV_ADDR 0x000ff000 +/* Size of environment in L2 cache */ +#define U_BOOT_CACHE_ENV_SIZE 0x1000 + +/* Board numbers and names */ + +/* Type defines for board and chip types */ +enum cvmx_board_types_enum { + CVMX_BOARD_TYPE_NULL = 0, + CVMX_BOARD_TYPE_SIM = 1, + /* Special 'generic' board type, supports many boards */ + CVMX_BOARD_TYPE_GENERIC = 28, + CVMX_BOARD_TYPE_EBB7304 = 76, + CVMX_BOARD_TYPE_MAX, + /* NOTE: 256-257 are being used by a customer. */ + + /* + * The range from CVMX_BOARD_TYPE_MAX to + * CVMX_BOARD_TYPE_CUST_DEFINED_MIN is reserved + * for future SDK use. + */ + + /* + * Set aside a range for customer boards. These numbers are managed + * by Cavium. + */ + CVMX_BOARD_TYPE_CUST_DEFINED_MIN = 10000, + CVMX_BOARD_TYPE_CUST_DEFINED_MAX = 20000, + + /* + * Set aside a range for customer private use. The SDK won't + * use any numbers in this range. + */ + CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, + CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, +}; + +/* Functions to return string based on type */ +/* Skip CVMX_BOARD_TYPE_ */ +#define ENUM_BRD_TYPE_CASE(x) case x: return(#x + 16) + +static inline const char +*cvmx_board_type_to_string(enum cvmx_board_types_enum type) +{ + switch (type) { + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NULL); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_SIM); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_GENERIC); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB7304); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_MAX); + + /* Customer boards listed here */ + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MIN); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MAX); + + /* Customer private range */ + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX); + } + + return "Unsupported Board"; +} + +#endif /* __CVMX_BOOTLOADER__ */ diff --git a/tools/.gitignore b/tools/.gitignore index 82bdce27829..a021ea95cd6 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -32,5 +32,6 @@ /spl_size_limit /sunxi-spl-image-builder /ubsha1 +/update_octeon_header /version.h /xway-swap-bytes diff --git a/tools/Makefile b/tools/Makefile index 51123fd9298..253a6b97065 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -206,6 +206,9 @@ hostprogs-y += proftool hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela hostprogs-$(CONFIG_RISCV) += prelink-riscv +hostprogs-$(CONFIG_ARCH_OCTEON) += update_octeon_header +update_octeon_header-objs := update_octeon_header.o lib/crc32.o + hostprogs-y += fdtgrep fdtgrep-objs += $(LIBFDT_OBJS) common/fdt_region.o fdtgrep.o diff --git a/tools/update_octeon_header.c b/tools/update_octeon_header.c new file mode 100644 index 00000000000..8054ceec855 --- /dev/null +++ b/tools/update_octeon_header.c @@ -0,0 +1,456 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mkimage.h" + +#include "../arch/mips/mach-octeon/include/mach/cvmx-bootloader.h" + +#define BUF_SIZE (16 * 1024) +#define NAME_LEN 100 + +/* word offset */ +#define WOFFSETOF(type, elem) (offsetof(type, elem) / 4) + +static int stage2_flag; +static int stage_1_5_flag; +static int stage_1_flag; + +/* Getoptions variables must be global */ +static int failsafe_flag; +static int pciboot_flag; +static int env_flag; + +static const struct option long_options[] = { + /* These options set a flag. */ + {"failsafe", no_argument, &failsafe_flag, 1}, + {"pciboot", no_argument, &pciboot_flag, 1}, + {"nandstage2", no_argument, &stage2_flag, 1}, + {"spistage2", no_argument, &stage2_flag, 1}, + {"norstage2", no_argument, &stage2_flag, 1}, + {"stage2", no_argument, &stage2_flag, 1}, + {"stage1.5", no_argument, &stage_1_5_flag, 1}, + {"stage1", no_argument, &stage_1_flag, 1}, + {"environment", no_argument, &env_flag, 1}, + /* + * These options don't set a flag. + * We distinguish them by their indices. + */ + {"board", required_argument, 0, 0}, + {"text_base", required_argument, 0, 0}, + {0, 0, 0, 0} +}; + +static int lookup_board_type(char *board_name) +{ + int i; + int board_type = 0; + char *substr = NULL; + + /* Detect stage 2 bootloader boards */ + if (strcasestr(board_name, "_stage2")) { + printf("Stage 2 bootloader detected from substring %s in name %s\n", + "_stage2", board_name); + stage2_flag = 1; + } else { + printf("Stage 2 bootloader NOT detected from name \"%s\"\n", + board_name); + } + + if (strcasestr(board_name, "_stage1")) { + printf("Stage 1 bootloader detected from substring %s in name %s\n", + "_stage1", board_name); + stage_1_flag = 1; + } + + /* Generic is a special case since there are numerous sub-types */ + if (!strncasecmp("generic", board_name, strlen("generic"))) + return CVMX_BOARD_TYPE_GENERIC; + + /* + * If we're an eMMC stage 2 bootloader, cut off the _emmc_stage2 + * part of the name. + */ + substr = strcasestr(board_name, "_emmc_stage2"); + if (substr && (substr[strlen("_emmc_stage2")] == '\0')) { + /*return CVMX_BOARD_TYPE_GENERIC;*/ + + printf(" Converting board name %s to ", board_name); + *substr = '\0'; + printf("%s\n", board_name); + } + + /* + * If we're a NAND stage 2 bootloader, cut off the _nand_stage2 + * part of the name. + */ + substr = strcasestr(board_name, "_nand_stage2"); + if (substr && (substr[strlen("_nand_stage2")] == '\0')) { + /*return CVMX_BOARD_TYPE_GENERIC;*/ + + printf(" Converting board name %s to ", board_name); + *substr = '\0'; + printf("%s\n", board_name); + } + + /* + * If we're a SPI stage 2 bootloader, cut off the _spi_stage2 + * part of the name. + */ + substr = strcasestr(board_name, "_spi_stage2"); + if (substr && (substr[strlen("_spi_stage2")] == '\0')) { + printf(" Converting board name %s to ", board_name); + *substr = '\0'; + printf("%s\n", board_name); + } + + for (i = CVMX_BOARD_TYPE_NULL; i < CVMX_BOARD_TYPE_MAX; i++) + if (!strcasecmp(cvmx_board_type_to_string(i), board_name)) + board_type = i; + + for (i = CVMX_BOARD_TYPE_CUST_DEFINED_MIN; + i < CVMX_BOARD_TYPE_CUST_DEFINED_MAX; i++) + if (!strncasecmp(cvmx_board_type_to_string(i), board_name, + strlen(cvmx_board_type_to_string(i)))) + board_type = i; + + for (i = CVMX_BOARD_TYPE_CUST_PRIVATE_MIN; + i < CVMX_BOARD_TYPE_CUST_PRIVATE_MAX; i++) + if (!strncasecmp(cvmx_board_type_to_string(i), board_name, + strlen(cvmx_board_type_to_string(i)))) + board_type = i; + + return board_type; +} + +static void usage(void) +{ + printf("Usage: update_octeon_header [--failsafe] [--text_base=0xXXXXX]\n"); +} + +int main(int argc, char *argv[]) +{ + int fd; + uint8_t buf[BUF_SIZE]; + uint32_t data_crc = 0; + int len; + int data_len = 0; + struct bootloader_header header; + char filename[NAME_LEN]; + int i; + int option_index = 0; /* getopt_long stores the option index here. */ + char board_name[NAME_LEN] = { 0 }; + char tmp_board_name[NAME_LEN] = { 0 }; + int c; + int board_type = 0; + unsigned long long address = 0; + ssize_t ret; + const char *type_str = NULL; + int hdr_size = sizeof(struct bootloader_header); + + /* + * Compile time check, if the size of the bootloader_header structure + * has changed. + */ + compiletime_assert(sizeof(struct bootloader_header) == 192, + "Octeon bootloader header size changed (!= 192)!"); + + /* Bail out, if argument count is incorrect */ + if (argc < 3) { + usage(); + return -1; + } + + debug("header size is: %d bytes\n", hdr_size); + + /* Parse command line options using getopt_long */ + while (1) { + c = getopt_long(argc, argv, "h", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) + break; + + switch (c) { + /* All long options handled in case 0 */ + case 0: + /* If this option set a flag, do nothing else now. */ + if (long_options[option_index].flag != 0) + break; + debug("option(l) %s", long_options[option_index].name); + + if (!optarg) { + usage(); + return -1; + } + debug(" with arg %s\n", optarg); + + if (!strcmp(long_options[option_index].name, "board")) { + if (strlen(optarg) >= NAME_LEN) { + printf("strncpy() issue detected!"); + exit(-1); + } + strncpy(board_name, optarg, NAME_LEN); + + printf("Using user supplied board name: %s\n", + board_name); + } else if (!strcmp(long_options[option_index].name, + "text_base")) { + address = strtoull(optarg, NULL, 0); + printf("Address of image is: 0x%llx\n", + (unsigned long long)address); + if (!(address & 0xFFFFFFFFULL << 32)) { + if (address & 1 << 31) { + address |= 0xFFFFFFFFULL << 32; + printf("Converting address to 64 bit compatibility space: 0x%llx\n", + address); + } + } + } + break; + + case 'h': + case '?': + /* getopt_long already printed an error message. */ + usage(); + return -1; + + default: + abort(); + } + } + + if (optind < argc) { + /* + * We only support one argument - an optional bootloader + * file name + */ + if (argc - optind > 2) { + fprintf(stderr, "non-option ARGV-elements: "); + while (optind < argc) + fprintf(stderr, "%s ", argv[optind++]); + fprintf(stderr, "\n"); + + usage(); + return -1; + } + } + + if (strlen(argv[optind]) >= NAME_LEN) { + fprintf(stderr, "strncpy() issue detected!"); + exit(-1); + } + strncpy(filename, argv[optind], NAME_LEN); + + if (board_name[0] == '\0') { + if (strlen(argv[optind + 1]) >= NAME_LEN) { + fprintf(stderr, "strncpy() issue detected!"); + exit(-1); + } + strncpy(board_name, argv[optind + 1], NAME_LEN); + } + + if (strlen(board_name) >= NAME_LEN) { + fprintf(stderr, "strncpy() issue detected!"); + exit(-1); + } + strncpy(tmp_board_name, board_name, NAME_LEN); + + fd = open(filename, O_RDWR); + if (fd < 0) { + fprintf(stderr, "Unable to open file: %s\n", filename); + exit(-1); + } + + if (failsafe_flag) + printf("Setting failsafe flag\n"); + + if (strlen(board_name)) { + int offset = 0; + + printf("Supplied board name of: %s\n", board_name); + + if (strstr(board_name, "failsafe")) { + failsafe_flag = 1; + printf("Setting failsafe flag based on board name\n"); + } + /* Skip leading octeon_ if present. */ + if (!strncmp(board_name, "octeon_", 7)) + offset = 7; + + /* + * Check to see if 'failsafe' is in the name. If so, set the + * failsafe flag. Also, ignore extra trailing characters on + * passed parameter when comparing against board names. + * We actually use the configuration name from u-boot, so it + * may have some other variant names. Variants other than + * failsafe _must_ be passed to this program explicitly + */ + + board_type = lookup_board_type(board_name + offset); + if (!board_type) { + /* Retry with 'cust_' prefix to catch boards that are + * in the customer section (such as nb5) + */ + sprintf(tmp_board_name, "cust_%s", board_name + offset); + board_type = lookup_board_type(tmp_board_name); + } + + /* reset to original value */ + strncpy(tmp_board_name, board_name, NAME_LEN); + if (!board_type) { + /* + * Retry with 'cust_private_' prefix to catch boards + * that are in the customer private section + */ + sprintf(tmp_board_name, "cust_private_%s", + board_name + offset); + board_type = lookup_board_type(tmp_board_name); + } + + if (!board_type) { + fprintf(stderr, + "ERROR: unable to determine board type\n"); + exit(-1); + } + printf("Board type is: %d: %s\n", board_type, + cvmx_board_type_to_string(board_type)); + } else { + fprintf(stderr, "Board name must be specified!\n"); + exit(-1); + } + + /* + * Check to see if there is either an existing header, or that there + * are zero valued bytes where we want to put the header + */ + len = read(fd, buf, BUF_SIZE); + if (len > 0) { + /* + * Copy the header, as the first word (jump instruction, needs + * to remain the same. + */ + memcpy(&header, buf, hdr_size); + /* + * Check to see if we have zero bytes (excluding first 4, which + * are the jump instruction) + */ + for (i = 1; i < hdr_size / 4; i++) { + if (((uint32_t *)buf)[i]) { + fprintf(stderr, + "ERROR: non-zero word found %x in location %d required for header, aborting\n", + ((uint32_t *)buf)[i], i); + exit(-1); + } + } + printf("Zero bytes found in header location, adding header.\n"); + + } else { + fprintf(stderr, "Unable to read from file %s\n", filename); + exit(-1); + } + + /* Read data bytes and generate CRC */ + lseek(fd, hdr_size, SEEK_SET); + + while ((len = read(fd, buf, BUF_SIZE)) > 0) { + data_crc = crc32(data_crc, buf, len); + data_len += len; + } + printf("CRC of data: 0x%x, length: %d\n", data_crc, data_len); + + /* Now create the new header */ + header.magic = htonl(BOOTLOADER_HEADER_MAGIC); + header.maj_rev = htons(BOOTLOADER_HEADER_CURRENT_MAJOR_REV); + header.min_rev = htons(BOOTLOADER_HEADER_CURRENT_MINOR_REV); + header.dlen = htonl(data_len); + header.dcrc = htonl(data_crc); + header.board_type = htons(board_type); + header.address = address; + if (failsafe_flag) + header.flags |= htonl(BL_HEADER_FLAG_FAILSAFE); + + printf("Stage 2 flag is %sset\n", stage2_flag ? "" : "not "); + printf("Stage 1 flag is %sset\n", stage_1_flag ? "" : "not "); + if (pciboot_flag) + header.image_type = htons(BL_HEADER_IMAGE_PCIBOOT); + else if (stage2_flag) + header.image_type = htons(BL_HEADER_IMAGE_STAGE2); + else if (stage_1_flag) + header.image_type = htons(BL_HEADER_IMAGE_STAGE1); + else if (env_flag) + header.image_type = htons(BL_HEADER_IMAGE_UBOOT_ENV); + else if (stage_1_5_flag || stage_1_flag) + header.image_type = htons(BL_HEADER_IMAGE_PRE_UBOOT); + else + header.image_type = htons(BL_HEADER_IMAGE_NOR); + + switch (ntohs(header.image_type)) { + case BL_HEADER_IMAGE_UNKNOWN: + type_str = "Unknown"; + break; + case BL_HEADER_IMAGE_STAGE1: + type_str = "Stage 1"; + break; + case BL_HEADER_IMAGE_STAGE2: + type_str = "Stage 2"; + break; + case BL_HEADER_IMAGE_PRE_UBOOT: + type_str = "Pre-U-Boot"; + break; + case BL_HEADER_IMAGE_STAGE3: + type_str = "Stage 3"; + break; + case BL_HEADER_IMAGE_NOR: + type_str = "NOR"; + break; + case BL_HEADER_IMAGE_PCIBOOT: + type_str = "PCI Boot"; + break; + case BL_HEADER_IMAGE_UBOOT_ENV: + type_str = "U-Boot Environment"; + break; + default: + if (ntohs(header.image_type) >= BL_HEADER_IMAGE_CUST_RESERVED_MIN && + ntohs(header.image_type) <= BL_HEADER_IMAGE_CUST_RESERVED_MAX) + type_str = "Customer Reserved"; + else + type_str = "Unsupported"; + } + printf("Header image type: %s\n", type_str); + header.hlen = htons(hdr_size); + + /* Now compute header CRC over all of the header excluding the CRC */ + header.hcrc = crc32(0, (void *)&header, 12); + header.hcrc = htonl(crc32(header.hcrc, ((void *)&(header)) + 16, + hdr_size - 16)); + + /* Seek to beginning of file */ + lseek(fd, 0, SEEK_SET); + + /* Write header to file */ + ret = write(fd, &header, hdr_size); + if (ret < 0) + perror("write"); + + close(fd); + + printf("Header CRC: 0x%x\n", ntohl(header.hcrc)); + return 0; +}