From a8a0c55f9d1cd0f4618288b25f63857373015391 Mon Sep 17 00:00:00 2001 From: Tony Dinh Date: Wed, 17 Aug 2022 14:59:44 -0700 Subject: [PATCH 01/16] arm: kirkwood: Add CONFIG_SUPPORT_PASSING_ATAGS Add CONFIG_SUPPORT_PASSING_ATAGS and friends to support legacy image method of booting. Debian and OpenWrt installer use uImage with appended DTB for these Kirkwood boards. Signed-off-by: Tony Dinh Reviewed-by: Stefan Roese --- configs/dockstar_defconfig | 3 +++ configs/dreamplug_defconfig | 3 +++ configs/goflexhome_defconfig | 3 +++ configs/iconnect_defconfig | 3 +++ configs/pogo_e02_defconfig | 3 +++ configs/sheevaplug_defconfig | 3 +++ 6 files changed, 18 insertions(+) diff --git a/configs/dockstar_defconfig b/configs/dockstar_defconfig index d43423c45e..feba398912 100644 --- a/configs/dockstar_defconfig +++ b/configs/dockstar_defconfig @@ -4,6 +4,9 @@ CONFIG_SYS_DCACHE_OFF=y CONFIG_ARCH_CPU_INIT=y CONFIG_SYS_THUMB_BUILD=y CONFIG_ARCH_KIRKWOOD=y +CONFIG_SUPPORT_PASSING_ATAGS=y +CONFIG_CMDLINE_TAG=y +CONFIG_INITRD_TAG=y CONFIG_SYS_KWD_CONFIG="board/Seagate/dockstar/kwbimage.cfg" CONFIG_SYS_TEXT_BASE=0x600000 CONFIG_NR_DRAM_BANKS=2 diff --git a/configs/dreamplug_defconfig b/configs/dreamplug_defconfig index 24090c81aa..650b14620e 100644 --- a/configs/dreamplug_defconfig +++ b/configs/dreamplug_defconfig @@ -3,6 +3,9 @@ CONFIG_SKIP_LOWLEVEL_INIT=y CONFIG_SYS_DCACHE_OFF=y CONFIG_ARCH_CPU_INIT=y CONFIG_ARCH_KIRKWOOD=y +CONFIG_SUPPORT_PASSING_ATAGS=y +CONFIG_CMDLINE_TAG=y +CONFIG_INITRD_TAG=y CONFIG_SYS_KWD_CONFIG="board/Marvell/dreamplug/kwbimage.cfg" CONFIG_SYS_TEXT_BASE=0x600000 CONFIG_NR_DRAM_BANKS=2 diff --git a/configs/goflexhome_defconfig b/configs/goflexhome_defconfig index 0856a31c76..aeb4a7d368 100644 --- a/configs/goflexhome_defconfig +++ b/configs/goflexhome_defconfig @@ -4,6 +4,9 @@ CONFIG_SYS_DCACHE_OFF=y CONFIG_ARCH_CPU_INIT=y CONFIG_SYS_THUMB_BUILD=y CONFIG_ARCH_KIRKWOOD=y +CONFIG_SUPPORT_PASSING_ATAGS=y +CONFIG_CMDLINE_TAG=y +CONFIG_INITRD_TAG=y CONFIG_SYS_KWD_CONFIG="board/Seagate/goflexhome/kwbimage.cfg" CONFIG_SYS_TEXT_BASE=0x600000 CONFIG_NR_DRAM_BANKS=2 diff --git a/configs/iconnect_defconfig b/configs/iconnect_defconfig index 1c66b42de8..c91d58d31a 100644 --- a/configs/iconnect_defconfig +++ b/configs/iconnect_defconfig @@ -4,6 +4,9 @@ CONFIG_SYS_DCACHE_OFF=y CONFIG_ARCH_CPU_INIT=y CONFIG_SYS_THUMB_BUILD=y CONFIG_ARCH_KIRKWOOD=y +CONFIG_SUPPORT_PASSING_ATAGS=y +CONFIG_CMDLINE_TAG=y +CONFIG_INITRD_TAG=y CONFIG_SYS_KWD_CONFIG="board/iomega/iconnect/kwbimage.cfg" CONFIG_SYS_TEXT_BASE=0x600000 CONFIG_NR_DRAM_BANKS=2 diff --git a/configs/pogo_e02_defconfig b/configs/pogo_e02_defconfig index 15b883b6b0..6adb230e29 100644 --- a/configs/pogo_e02_defconfig +++ b/configs/pogo_e02_defconfig @@ -4,6 +4,9 @@ CONFIG_SYS_DCACHE_OFF=y CONFIG_ARCH_CPU_INIT=y CONFIG_SYS_THUMB_BUILD=y CONFIG_ARCH_KIRKWOOD=y +CONFIG_SUPPORT_PASSING_ATAGS=y +CONFIG_CMDLINE_TAG=y +CONFIG_INITRD_TAG=y CONFIG_SYS_KWD_CONFIG="board/cloudengines/pogo_e02/kwbimage.cfg" CONFIG_SYS_TEXT_BASE=0x600000 CONFIG_NR_DRAM_BANKS=2 diff --git a/configs/sheevaplug_defconfig b/configs/sheevaplug_defconfig index edbc2eefa3..6d1e59ef25 100644 --- a/configs/sheevaplug_defconfig +++ b/configs/sheevaplug_defconfig @@ -4,6 +4,9 @@ CONFIG_SYS_DCACHE_OFF=y CONFIG_ARCH_CPU_INIT=y CONFIG_SYS_THUMB_BUILD=y CONFIG_ARCH_KIRKWOOD=y +CONFIG_SUPPORT_PASSING_ATAGS=y +CONFIG_CMDLINE_TAG=y +CONFIG_INITRD_TAG=y CONFIG_SYS_KWD_CONFIG="board/Marvell/sheevaplug/kwbimage.cfg" CONFIG_SYS_TEXT_BASE=0x600000 CONFIG_NR_DRAM_BANKS=2 From ca076d96894fbaa375236da529dc35287413abff Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 19 Aug 2022 09:43:59 +0200 Subject: [PATCH 02/16] tools: kwboot: Change KWBOOT_MSG_RSP_TIMEO_AXP to 10ms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing on the theadorable Armada XP platform has shown, thaz using the current value of 1000ms as response timeout does not result in reliable booting via kwboot. Using 10ms seems to be much better. So let's change this value to this 10ms instead. Signed-off-by: Stefan Roese Acked-by: Pali Rohár --- tools/kwboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/kwboot.c b/tools/kwboot.c index 16bcd4d9a7..da4fe32da2 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -84,7 +84,7 @@ static unsigned char kwboot_msg_debug[] = { #define KWBOOT_MSG_RSP_TIMEO 50 /* ms */ /* Defines known to work on Armada XP */ -#define KWBOOT_MSG_RSP_TIMEO_AXP 1000 /* ms */ +#define KWBOOT_MSG_RSP_TIMEO_AXP 10 /* ms */ /* * Xmodem Transfers From 5a0653493307796e63227d78e40651096c1ca23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 23 Aug 2022 14:52:23 +0200 Subject: [PATCH 03/16] cmd: mvebu/bubt: Check for A38x image data checksum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently for A38x image is checked only header checksum. So check also for image data checksum to prevent flashing broken image. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- cmd/mvebu/bubt.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c index 2136af6416..a97e5ce38a 100644 --- a/cmd/mvebu/bubt.c +++ b/cmd/mvebu/bubt.c @@ -688,9 +688,25 @@ static uint8_t image_checksum8(const void *start, size_t len) return csum; } +static uint32_t image_checksum32(const void *start, size_t len) +{ + u32 csum = 0; + const u32 *p = start; + + while (len) { + csum += *p; + ++p; + len -= sizeof(u32); + } + + return csum; +} + static int check_image_header(void) { u8 checksum; + u32 checksum32, exp_checksum32; + u32 offset, size; const struct a38x_main_hdr_v1 *hdr = (struct a38x_main_hdr_v1 *)get_load_addr(); const size_t image_size = a38x_header_size(hdr); @@ -701,11 +717,39 @@ static int check_image_header(void) checksum = image_checksum8(hdr, image_size); checksum -= hdr->checksum; if (checksum != hdr->checksum) { - printf("Error: Bad A38x image checksum. 0x%x != 0x%x\n", + printf("Error: Bad A38x image header checksum. 0x%x != 0x%x\n", checksum, hdr->checksum); return -ENOEXEC; } + offset = le32_to_cpu(hdr->srcaddr); + size = le32_to_cpu(hdr->blocksize); + + if (hdr->blockid == 0x78) { /* SATA id */ + if (offset < 1) { + printf("Error: Bad A38x image srcaddr.\n"); + return -ENOEXEC; + } + offset -= 1; + offset *= 512; + } + + if (hdr->blockid == 0xAE) /* SDIO id */ + offset *= 512; + + if (offset % 4 != 0 || size < 4 || size % 4 != 0) { + printf("Error: Bad A38x image blocksize.\n"); + return -ENOEXEC; + } + + checksum32 = image_checksum32((u8 *)hdr + offset, size - 4); + exp_checksum32 = *(u32 *)((u8 *)hdr + offset + size - 4); + if (checksum32 != exp_checksum32) { + printf("Error: Bad A38x image data checksum. 0x%08x != 0x%08x\n", + checksum32, exp_checksum32); + return -ENOEXEC; + } + printf("Image checksum...OK!\n"); return 0; } From f7b0bbca2b6257c50d4e087322602593a0f279cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 23 Aug 2022 14:52:24 +0200 Subject: [PATCH 04/16] cmd: mvebu/bubt: Check for A38x/A37xx OTP secure bits and secure boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For obvious reasons BootROMS rejects unsigned images when secure boot is enabled in OTP secure bits. So check for OPT secure bits and do not allow flashing unsigned images when secure boot is enabled. Access to OTP via U-Boot fuse API is currently implemented only for A38x and A37xx SoCs. Additionally Armada 3700 BootROM rejects signed trusted image when secure boot is not enabled in OTP. So add also check for this case. On the other hand Armada 38x BootROM acceps images with secure boot header when secure boot is not enabled in OTP. OTP secure bits may have burned also boot device source. Check it also and reject flashing images to target storage which does not match OTP. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- cmd/mvebu/Kconfig | 1 + cmd/mvebu/bubt.c | 128 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 121 insertions(+), 8 deletions(-) diff --git a/cmd/mvebu/Kconfig b/cmd/mvebu/Kconfig index 120397d6d4..9ec3aa983a 100644 --- a/cmd/mvebu/Kconfig +++ b/cmd/mvebu/Kconfig @@ -5,6 +5,7 @@ config CMD_MVEBU_BUBT bool "bubt" select SHA256 if ARMADA_3700 select SHA512 if ARMADA_3700 + select MVEBU_EFUSE if ARMADA_38X || ARMADA_3700 help bubt - Burn a u-boot image to flash For details about bubt command please see the documentation diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c index a97e5ce38a..7e6e47f40d 100644 --- a/cmd/mvebu/bubt.c +++ b/cmd/mvebu/bubt.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -121,6 +123,17 @@ struct a38x_main_hdr_v1 { u8 checksum; /* 0x1F */ }; +/* + * Header for the optional headers, version 1 (Armada 370/XP/375/38x/39x) + */ +struct a38x_opt_hdr_v1 { + u8 headertype; + u8 headersz_msb; + u16 headersz_lsb; + u8 data[0]; +}; +#define A38X_OPT_HDR_V1_SECURE_TYPE 0x1 + struct a38x_boot_mode { unsigned int id; const char *name; @@ -753,6 +766,38 @@ static int check_image_header(void) printf("Image checksum...OK!\n"); return 0; } + +#if defined(CONFIG_ARMADA_38X) +static int a38x_image_is_secure(const struct a38x_main_hdr_v1 *hdr) +{ + u32 image_size = a38x_header_size(hdr); + struct a38x_opt_hdr_v1 *ohdr; + u32 ohdr_size; + + if (hdr->version != 1) + return 0; + + if (!hdr->ext) + return 0; + + ohdr = (struct a38x_opt_hdr_v1 *)(hdr + 1); + do { + if (ohdr->headertype == A38X_OPT_HDR_V1_SECURE_TYPE) + return 1; + + ohdr_size = (ohdr->headersz_msb << 16) | le16_to_cpu(ohdr->headersz_lsb); + + if (!*((u8 *)ohdr + ohdr_size - 4)) + break; + + ohdr = (struct a38x_opt_hdr_v1 *)((u8 *)ohdr + ohdr_size); + if ((u8 *)ohdr >= (u8 *)hdr + image_size) + break; + } while (1); + + return 0; +} +#endif #else /* Not ARMADA? */ static int check_image_header(void) { @@ -761,20 +806,60 @@ static int check_image_header(void) } #endif +#if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_32BIT) +static u64 fuse_read_u64(u32 bank) +{ + u32 val[2]; + int ret; + + ret = fuse_read(bank, 0, &val[0]); + if (ret < 0) + return -1; + + ret = fuse_read(bank, 1, &val[1]); + if (ret < 0) + return -1; + + return ((u64)val[1] << 32) | val[0]; +} +#endif + +#if defined(CONFIG_ARMADA_3700) +static inline u8 maj3(u8 val) +{ + /* return majority vote of 3 bits */ + return ((val & 0x7) == 3 || (val & 0x7) > 4) ? 1 : 0; +} +#endif + static int bubt_check_boot_mode(const struct bubt_dev *dst) { #if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_32BIT) - int mode; + int mode, secure_mode; #if defined(CONFIG_ARMADA_3700) const struct tim_boot_flash_sign *boot_modes = tim_boot_flash_signs; const struct common_tim_data *hdr = (struct common_tim_data *)get_load_addr(); u32 id = hdr->boot_flash_sign; + int is_secure = hdr->trusted != 0; + u64 otp_secure_bits = fuse_read_u64(1); + int otp_secure_boot = ((maj3(otp_secure_bits >> 0) << 0) | + (maj3(otp_secure_bits >> 4) << 1)) == 2; + unsigned int otp_boot_device = (maj3(otp_secure_bits >> 48) << 0) | + (maj3(otp_secure_bits >> 52) << 1) | + (maj3(otp_secure_bits >> 56) << 2) | + (maj3(otp_secure_bits >> 60) << 3); #elif defined(CONFIG_ARMADA_32BIT) const struct a38x_boot_mode *boot_modes = a38x_boot_modes; const struct a38x_main_hdr_v1 *hdr = (struct a38x_main_hdr_v1 *)get_load_addr(); u32 id = hdr->blockid; +#if defined(CONFIG_ARMADA_38X) + int is_secure = a38x_image_is_secure(hdr); + u64 otp_secure_bits = fuse_read_u64(EFUSE_LINE_SECURE_BOOT); + int otp_secure_boot = otp_secure_bits & 0x1; + unsigned int otp_boot_device = (otp_secure_bits >> 8) & 0x7; +#endif #endif for (mode = 0; boot_modes[mode].name; mode++) { @@ -787,15 +872,42 @@ static int bubt_check_boot_mode(const struct bubt_dev *dst) return -ENOEXEC; } - if (strcmp(boot_modes[mode].name, dst->name) == 0) - return 0; + if (strcmp(boot_modes[mode].name, dst->name) != 0) { + printf("Error: image meant to be booted from \"%s\", not \"%s\"!\n", + boot_modes[mode].name, dst->name); + return -ENOEXEC; + } - printf("Error: image meant to be booted from \"%s\", not \"%s\"!\n", - boot_modes[mode].name, dst->name); - return -ENOEXEC; -#else - return 0; +#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_3700) + if (otp_secure_bits == (u64)-1) { + printf("Error: cannot read OTP secure bits\n"); + return -ENOEXEC; + } else { + if (otp_secure_boot && !is_secure) { + printf("Error: secure boot is enabled in OTP but image does not have secure boot header!\n"); + return -ENOEXEC; + } else if (!otp_secure_boot && is_secure) { +#if defined(CONFIG_ARMADA_3700) + /* + * Armada 3700 BootROM rejects trusted image when secure boot is not enabled. + * Armada 385 BootROM accepts image with secure boot header also when secure boot is not enabled. + */ + printf("Error: secure boot is disabled in OTP but image has secure boot header!\n"); + return -ENOEXEC; #endif + } else if (otp_boot_device && otp_boot_device != id) { + for (secure_mode = 0; boot_modes[secure_mode].name; secure_mode++) { + if (boot_modes[secure_mode].id == otp_boot_device) + break; + } + printf("Error: boot source is set to \"%s\" in OTP but image is for \"%s\"!\n", + boot_modes[secure_mode].name ?: "unknown", dst->name); + return -ENOEXEC; + } + } +#endif +#endif + return 0; } static int bubt_verify(const struct bubt_dev *dst) From 8ac3615e8d73f6be446bc25ae17d4f38f3cbf371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 27 Aug 2022 14:00:51 +0200 Subject: [PATCH 05/16] arm: mvebu: Espressobin: When emmc is not present disable it also in OF_LIVE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- board/Marvell/mvebu_armada-37xx/board.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/board/Marvell/mvebu_armada-37xx/board.c b/board/Marvell/mvebu_armada-37xx/board.c index 3e5e0a0b5c..c6ecc323bb 100644 --- a/board/Marvell/mvebu_armada-37xx/board.c +++ b/board/Marvell/mvebu_armada-37xx/board.c @@ -132,6 +132,8 @@ int board_late_init(void) dev = mmc_dev->dev; device_remove(dev, DM_REMOVE_NORMAL); device_unbind(dev); + if (of_live_active()) + ofnode_set_enabled(dev_ofnode(dev), false); } /* Ensure that 'env default -a' set correct value to $fdtfile */ From 7bb9ea47e1a47e00d4aef86d66293379be0b47b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 27 Aug 2022 20:06:30 +0200 Subject: [PATCH 06/16] board: turris: Initialize serial# env MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store serial number from atsha cryptochip into the serial# env variable. U-Boot automatically puts content of this variable into the root device tree property serial-number when booting Linux kernel. Refactor turris atsha code and from turris_atsha_otp_get_serial_number() function returns directly string suitable for printing or storing into device tree. Because during different boot stages is env storage read-only, it is not possible to always store serial number into env storage. So introduce a new function turris_atsha_otp_init_serial_number() which is called at later stage and which ensures that serial number is correctly stored into env. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- board/CZ.NIC/turris_atsha_otp.c | 33 +++++++++++++++++++++--- board/CZ.NIC/turris_atsha_otp.h | 3 ++- board/CZ.NIC/turris_omnia/turris_omnia.c | 11 +++----- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/board/CZ.NIC/turris_atsha_otp.c b/board/CZ.NIC/turris_atsha_otp.c index aa4e29b156..a29fe36231 100644 --- a/board/CZ.NIC/turris_atsha_otp.c +++ b/board/CZ.NIC/turris_atsha_otp.c @@ -93,30 +93,57 @@ int turris_atsha_otp_init_mac_addresses(int first_idx) return 0; } -int turris_atsha_otp_get_serial_number(u32 *version_num, u32 *serial_num) +int turris_atsha_otp_init_serial_number(void) +{ + char serial[17]; + int ret; + + ret = turris_atsha_otp_get_serial_number(serial); + if (ret) + return ret; + + if (!env_get("serial#")) + return -1; + + return 0; +} + +int turris_atsha_otp_get_serial_number(char serial[17]) { struct udevice *dev = get_atsha204a_dev(); + u32 version_num, serial_num; + const char *serial_env; int ret; if (!dev) return -1; + serial_env = env_get("serial#"); + if (serial_env && strlen(serial_env) == 16) { + memcpy(serial, serial_env, 17); + return 0; + } + ret = atsha204a_wakeup(dev); if (ret) return ret; ret = atsha204a_read(dev, ATSHA204A_ZONE_OTP, false, TURRIS_ATSHA_OTP_VERSION, - (u8 *)version_num); + (u8 *)&version_num); if (ret) return ret; ret = atsha204a_read(dev, ATSHA204A_ZONE_OTP, false, TURRIS_ATSHA_OTP_SERIAL, - (u8 *)serial_num); + (u8 *)&serial_num); if (ret) return ret; atsha204a_sleep(dev); + + sprintf(serial, "%08X%08X", be32_to_cpu(version_num), be32_to_cpu(serial_num)); + env_set("serial#", serial); + return 0; } diff --git a/board/CZ.NIC/turris_atsha_otp.h b/board/CZ.NIC/turris_atsha_otp.h index bd4308fdc3..2cfe20bbc3 100644 --- a/board/CZ.NIC/turris_atsha_otp.h +++ b/board/CZ.NIC/turris_atsha_otp.h @@ -4,6 +4,7 @@ #define TURRIS_ATSHA_OTP_H int turris_atsha_otp_init_mac_addresses(int first_idx); -int turris_atsha_otp_get_serial_number(u32 *version_num, u32 *serial_num); +int turris_atsha_otp_init_serial_number(void); +int turris_atsha_otp_get_serial_number(char serial[17]); #endif diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c index ab5061ef58..cf8a602670 100644 --- a/board/CZ.NIC/turris_omnia/turris_omnia.c +++ b/board/CZ.NIC/turris_omnia/turris_omnia.c @@ -963,19 +963,15 @@ int board_late_init(void) int show_board_info(void) { - u32 version_num, serial_num; + char serial[17]; int err; - err = turris_atsha_otp_get_serial_number(&version_num, &serial_num); + err = turris_atsha_otp_get_serial_number(serial); printf("Model: Turris Omnia\n"); printf(" MCU type: %s\n", omnia_get_mcu_type()); printf(" MCU version: %s\n", omnia_get_mcu_version()); printf(" RAM size: %i MiB\n", omnia_get_ram_size_gb() * 1024); - if (err) - printf(" Serial Number: unknown\n"); - else - printf(" Serial Number: %08X%08X\n", be32_to_cpu(version_num), - be32_to_cpu(serial_num)); + printf(" Serial Number: %s\n", !err ? serial : "unknown"); return 0; } @@ -983,6 +979,7 @@ int show_board_info(void) int misc_init_r(void) { turris_atsha_otp_init_mac_addresses(1); + turris_atsha_otp_init_serial_number(); return 0; } From 109dde049740fe17a461471d7ff54a64fc58aab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 27 Aug 2022 20:49:20 +0200 Subject: [PATCH 07/16] arm: mvebu: turris_{omnia, mox}: Reset bootdelay env for rescue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When rescue mode was activated reset also bootdelay env variable to its default value. This will ensure that reset button works and starts rescue mode also in the case when user changed bootdelay env variable to -1 (which has meaning to not start autoboot). Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- board/CZ.NIC/turris_mox/turris_mox.c | 5 +++-- board/CZ.NIC/turris_omnia/turris_omnia.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/board/CZ.NIC/turris_mox/turris_mox.c b/board/CZ.NIC/turris_mox/turris_mox.c index 3dbd68e523..5e1cf328ec 100644 --- a/board/CZ.NIC/turris_mox/turris_mox.c +++ b/board/CZ.NIC/turris_mox/turris_mox.c @@ -440,8 +440,9 @@ static void handle_reset_button(void) env_set_default_vars(1, (char * const *)vars, 0); if (read_reset_button()) { - const char * const vars[2] = { + const char * const vars[3] = { "bootcmd", + "bootdelay", "distro_bootcmd", }; @@ -449,7 +450,7 @@ static void handle_reset_button(void) * Set the above envs to their default values, in case the user * managed to break them. */ - env_set_default_vars(2, (char * const *)vars, 0); + env_set_default_vars(3, (char * const *)vars, 0); /* Ensure bootcmd_rescue is used by distroboot */ env_set("boot_targets", "rescue"); diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c index cf8a602670..a7f96e5b77 100644 --- a/board/CZ.NIC/turris_omnia/turris_omnia.c +++ b/board/CZ.NIC/turris_omnia/turris_omnia.c @@ -549,8 +549,9 @@ static void handle_reset_button(void) env_set_ulong("omnia_reset", reset_status); if (reset_status) { - const char * const vars[2] = { + const char * const vars[3] = { "bootcmd", + "bootdelay", "distro_bootcmd", }; @@ -558,7 +559,7 @@ static void handle_reset_button(void) * Set the above envs to their default values, in case the user * managed to break them. */ - env_set_default_vars(2, (char * const *)vars, 0); + env_set_default_vars(3, (char * const *)vars, 0); /* Ensure bootcmd_rescue is used by distroboot */ env_set("boot_targets", "rescue"); From 64c422b14fbe22d0424c53c043f3e5c6183f05ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 29 Aug 2022 15:44:48 +0200 Subject: [PATCH 08/16] arm: mvebu: turris_mox: Add support for distroboot $fdt_addr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit $fdt_addr is mandatory for systems which provides DTB in HW (e.g. ROM) and wishes to pass that DTB to Linux. Turris Mox contains DTB binary in SPI NOR memory at "dtb" partition which starts at offset 0x7f0000 and is 0x10000 bytes long. Armada 3700 CPU does not allow mapping SPI NOR memory into physical address space like on other architectures and therefore set $fdt_addr variable to memory range in RAM and loads this DTB binary from SPI NOR in misc_init_r() function. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- board/CZ.NIC/turris_mox/turris_mox.c | 48 ++++++++++++++++++++++++++++ include/configs/turris_mox.h | 1 + 2 files changed, 49 insertions(+) diff --git a/board/CZ.NIC/turris_mox/turris_mox.c b/board/CZ.NIC/turris_mox/turris_mox.c index 5e1cf328ec..ff1c4cb170 100644 --- a/board/CZ.NIC/turris_mox/turris_mox.c +++ b/board/CZ.NIC/turris_mox/turris_mox.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "mox_sp.h" @@ -339,6 +340,51 @@ static int get_reset_gpio(struct gpio_desc *reset_gpio) return 0; } +/* Load default system DTB binary to $fdr_addr */ +static void load_spi_dtb(void) +{ + const char *const env_name[1] = { "fdt_addr" }; + unsigned long size, offset; + struct udevice *spi_dev; + struct spi_flash *flash; + const char *addr_str; + unsigned long addr; + void *buf; + + addr_str = env_get(env_name[0]); + if (!addr_str) { + env_set_default_vars(1, (char * const *)env_name, 0); + addr_str = env_get(env_name[0]); + } + + if (!addr_str) + return; + + addr = hextoul(addr_str, NULL); + if (!addr) + return; + + spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, &spi_dev); + flash = dev_get_uclass_priv(spi_dev); + if (!flash) + return; + + /* + * SPI NOR "dtb" partition offset & size hardcoded for now because the + * mtd subsystem does not offer finding the partition yet and we do not + * want to reimplement OF partition parser here. + */ + offset = 0x7f0000; + size = 0x10000; + + buf = map_physmem(addr, size, MAP_WRBACK); + if (!buf) + return; + + spi_flash_read(flash, offset, size, buf); + unmap_physmem(buf, size); +} + int misc_init_r(void) { u8 mac[2][6]; @@ -358,6 +404,8 @@ int misc_init_r(void) eth_env_set_enetaddr_by_index("eth", i, mac[i]); } + load_spi_dtb(); + return 0; } diff --git a/include/configs/turris_mox.h b/include/configs/turris_mox.h index b8ff705ac9..f549f9f7ad 100644 --- a/include/configs/turris_mox.h +++ b/include/configs/turris_mox.h @@ -36,6 +36,7 @@ "bootm 0x5800000" #define CONFIG_EXTRA_ENV_SETTINGS \ + "fdt_addr=0x4c00000\0" \ "scriptaddr=0x4d00000\0" \ "pxefile_addr_r=0x4e00000\0" \ "fdt_addr_r=0x4f00000\0" \ From 634aa8e586c6cd3c4b8a068586af6f0f86d35572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 8 Sep 2022 16:59:36 +0200 Subject: [PATCH 09/16] tools: termios_linux.h: Fix compilation on non-glibc systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TCGETS2 is defined in header file asm/ioctls.h provided by linux kernel. On glib systems it is automatically included by some other glibc include header file and therefore TCGETS2 is present in termios_linux.h when linux kernel provides it. On non-glibc systems (e.g. musl) asm/ioctls.h is not automatically included which results in the strange error that BOTHER is supported, TCGETS2 not defined and struct termios does not provide c_ispeed member. tools/kwboot.c: In function 'kwboot_tty_change_baudrate': tools/kwboot.c:662:6: error: 'struct termios' has no member named 'c_ospeed' 662 | tio.c_ospeed = tio.c_ispeed = baudrate; | ^ Fix this issue by explicitly including asm/ioctls.h file which provides TCGETS2 macro (if supported on selected architecture) to not depending on glibc auto-include behavior and because termios_linux.h requires it. With this change it is possible compile kwboot with musl libc. Reported-by: Michal Vasilek Signed-off-by: Pali Rohár --- tools/termios_linux.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/termios_linux.h b/tools/termios_linux.h index 45f5c1233c..0806a91180 100644 --- a/tools/termios_linux.h +++ b/tools/termios_linux.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #if defined(BOTHER) && defined(TCGETS2) From cadda05a763ac5c1b844e6e9b78579ca62103cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 9 Sep 2022 14:18:48 +0200 Subject: [PATCH 10/16] arm: mvebu: turris_omnia: Allow to use second serial port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turris Omnia has two serial ports. Both are already specified in device tree file. But U-Boot by default does not allow to use more than one serial port unless CONFIG_SERIAL_PROBE_ALL is not enabled. After enabling CONFIG_SERIAL_PROBE_ALL, U-Boot see also second serial port (but is inactive by default): => coninfo List of available devices: serial@12000 00000007 IO stdin stdout stderr serial@12100 00000007 IO To allow simultaneously to use more input / output devices it is needed to enable CONFIG_CONSOLE_MUX option. With CONFIG_CONSOLE_MUX it is possible to call: => setenv stdout 'serial@12000,serial@12100' And U-Boot output is then visible on both serial ports. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- configs/turris_omnia_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/turris_omnia_defconfig b/configs/turris_omnia_defconfig index bce14cc69d..ba635feb44 100644 --- a/configs/turris_omnia_defconfig +++ b/configs/turris_omnia_defconfig @@ -33,6 +33,7 @@ CONFIG_FIT_VERBOSE=y CONFIG_OF_BOARD_SETUP=y CONFIG_BOOTDELAY=3 CONFIG_USE_PREBOOT=y +CONFIG_CONSOLE_MUX=y CONFIG_SYS_CONSOLE_INFO_QUIET=y # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_DISPLAY_BOARDINFO_LATE=y @@ -103,6 +104,7 @@ CONFIG_PINCTRL_ARMADA_38X=y CONFIG_DM_RTC=y CONFIG_RTC_ARMADA38X=y CONFIG_SCSI=y +CONFIG_SERIAL_PROBE_ALL=y CONFIG_SPL_DEBUG_UART_BASE=0xd0012000 CONFIG_DEBUG_UART_SHIFT=2 CONFIG_SYS_NS16550=y From b120519d7655a9fb134f1c71148c1f0b96b1192e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 9 Sep 2022 14:41:28 +0200 Subject: [PATCH 11/16] arm: mvebu: Mark constant data with const keyword MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- arch/arm/mach-kirkwood/cpu.c | 2 +- arch/arm/mach-kirkwood/include/mach/cpu.h | 2 +- arch/arm/mach-mvebu/cpu.c | 2 +- arch/arm/mach-mvebu/include/mach/cpu.h | 2 +- arch/arm/mach-mvebu/mbus.c | 2 +- arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c | 2 +- arch/arm/mach-mvebu/system-controller.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-kirkwood/cpu.c b/arch/arm/mach-kirkwood/cpu.c index 80f893ab36..df3e8f1178 100644 --- a/arch/arm/mach-kirkwood/cpu.c +++ b/arch/arm/mach-kirkwood/cpu.c @@ -52,7 +52,7 @@ unsigned int kw_winctrl_calcsize(unsigned int sizeval) return (0x0000ffff & j); } -static struct mbus_win windows[] = { +static const struct mbus_win windows[] = { /* Window 0: PCIE MEM address space */ { KW_DEFADR_PCI_MEM, KW_DEFADR_PCI_MEM_SIZE, KWCPU_TARGET_PCIE, KWCPU_ATTR_PCIE_MEM }, diff --git a/arch/arm/mach-kirkwood/include/mach/cpu.h b/arch/arm/mach-kirkwood/include/mach/cpu.h index d8639c6035..9eec786fe8 100644 --- a/arch/arm/mach-kirkwood/include/mach/cpu.h +++ b/arch/arm/mach-kirkwood/include/mach/cpu.h @@ -150,7 +150,7 @@ struct kwgpio_registers { unsigned int mvebu_sdram_bar(enum memory_bank bank); unsigned int mvebu_sdram_bs(enum memory_bank bank); void mvebu_sdram_size_adjust(enum memory_bank bank); -int mvebu_mbus_probe(struct mbus_win windows[], int count); +int mvebu_mbus_probe(const struct mbus_win windows[], int count); void mvebu_config_gpio(unsigned int gpp0_oe_val, unsigned int gpp1_oe_val, unsigned int gpp0_oe, unsigned int gpp1_oe); int kw_config_mpp(unsigned int mpp0_7, unsigned int mpp8_15, diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 1457af1d6a..5626b9197b 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -20,7 +20,7 @@ #define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) #define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3)) -static struct mbus_win windows[] = { +static const struct mbus_win windows[] = { /* SPI */ { MBUS_SPI_BASE, MBUS_SPI_SIZE, CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPIFLASH }, diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h index d9fa1f32aa..b127fce865 100644 --- a/arch/arm/mach-mvebu/include/mach/cpu.h +++ b/arch/arm/mach-mvebu/include/mach/cpu.h @@ -128,7 +128,7 @@ struct sar_freq_modes { unsigned int mvebu_sdram_bar(enum memory_bank bank); unsigned int mvebu_sdram_bs(enum memory_bank bank); void mvebu_sdram_size_adjust(enum memory_bank bank); -int mvebu_mbus_probe(struct mbus_win windows[], int count); +int mvebu_mbus_probe(const struct mbus_win windows[], int count); u32 mvebu_get_nand_clock(void); void __noreturn return_to_bootrom(void); diff --git a/arch/arm/mach-mvebu/mbus.c b/arch/arm/mach-mvebu/mbus.c index 7092f6cc10..959ca8e926 100644 --- a/arch/arm/mach-mvebu/mbus.c +++ b/arch/arm/mach-mvebu/mbus.c @@ -469,7 +469,7 @@ int mbus_dt_setup_win(u32 base, u32 size, u8 target, u8 attr) return 0; } -int mvebu_mbus_probe(struct mbus_win windows[], int count) +int mvebu_mbus_probe(const struct mbus_win windows[], int count) { int win; int ret; diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c index 2e467b546d..943ae01942 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c +++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c @@ -105,7 +105,7 @@ struct serdes_unit_data { u8 serdes_unit_num; }; -static struct serdes_unit_data serdes_type_to_unit_info[] = { +static const struct serdes_unit_data serdes_type_to_unit_info[] = { {PEX_UNIT_ID, 0,}, {PEX_UNIT_ID, 1,}, {PEX_UNIT_ID, 2,}, diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c index ea858b269e..e90aff0c33 100644 --- a/arch/arm/mach-mvebu/system-controller.c +++ b/arch/arm/mach-mvebu/system-controller.c @@ -86,7 +86,7 @@ static const struct udevice_id mvebu_reset_of_match[] = { { }, }; -static struct reset_ops mvebu_reset_ops = { +static const struct reset_ops mvebu_reset_ops = { .of_xlate = mvebu_reset_of_xlate, .request = mvebu_reset_request, .rfree = mvebu_reset_free, From 117ef65502ccb5a5d1ee02595e94be9205b760aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 8 Sep 2022 16:06:50 +0200 Subject: [PATCH 12/16] arm: mvebu: Fix function enable_caches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 3308933d2fe9 ("arm: mvebu: Avoid reading MVEBU_REG_PCIE_DEVID register too many times") broke support for caches on all Armada SoCs. Before that commit there was code: if (mvebu_soc_family() != MVEBU_SOC_A375) { dcache_enable(); } And after that commit there is code: if (IS_ENABLED(CONFIG_ARMADA_375)) { dcache_enable(); } Comment above this code says that d-cache should be disabled on Armada 375. But new code inverted logic and broke Armada 375 and slowed down all other Armada SoCs (including A38x). Fix this issue by changing logic to: if (!IS_ENABLED(CONFIG_ARMADA_375)) { dcache_enable(); } Which matches behavior prior that commit. Fixes: 3308933d2fe9 ("arm: mvebu: Avoid reading MVEBU_REG_PCIE_DEVID register too many times") Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 5626b9197b..7b722ca812 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -663,7 +663,7 @@ void enable_caches(void) * ethernet driver (mvpp2). So lets keep the d-cache disabled * until this is solved. */ - if (IS_ENABLED(CONFIG_ARMADA_375)) { + if (!IS_ENABLED(CONFIG_ARMADA_375)) { /* Enable D-cache. I-cache is already enabled in start.S */ dcache_enable(); } From 2a0d9ae414b4b2b38f6ada2d7a7134d7f31cff41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 8 Sep 2022 16:06:51 +0200 Subject: [PATCH 13/16] arm: mvebu: Guard non-AXP code by checking for AXP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit c86d53fd88df ("arm: mvebu: Don't disable cache at startup on Armada XP at all") introduced branch for non-AXP code which was guarded by A38X condition. Fix this issue by checking for AXP platform, not by A38X. Fixes: c86d53fd88df ("arm: mvebu: Don't disable cache at startup on Armada XP at all") Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 7b722ca812..949bf21c9b 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -448,7 +448,7 @@ int arch_cpu_init(void) struct pl310_regs *const pl310 = (struct pl310_regs *)CONFIG_SYS_PL310_BASE; - if (IS_ENABLED(CONFIG_ARMADA_38X)) { + if (!IS_ENABLED(CONFIG_ARMADA_XP)) { /* * To fully release / unlock this area from cache, we need * to flush all caches and disable the L2 cache. From a7199f4493fed97baee5a50b273369b055f5abca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 8 Sep 2022 16:06:52 +0200 Subject: [PATCH 14/16] arm: mvebu: lowlevel.S: Use CR_M from asm/system.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace magic constant 1 when disabling MMU by macro CR_M from include header file asm/system.h. Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/lowlevel.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-mvebu/lowlevel.S b/arch/arm/mach-mvebu/lowlevel.S index 2491310eb0..b460382c6b 100644 --- a/arch/arm/mach-mvebu/lowlevel.S +++ b/arch/arm/mach-mvebu/lowlevel.S @@ -2,6 +2,7 @@ #include #include +#include ENTRY(arch_very_early_init) #ifdef CONFIG_ARMADA_38X @@ -12,7 +13,7 @@ ENTRY(arch_very_early_init) * still locked to cache. */ mrc p15, 0, r0, c1, c0, 0 - bic r0, #1 + bic r0, #CR_M mcr p15, 0, r0, c1, c0, 0 #endif From 4f2333ba886aa8df655016091cafc695c750775a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 8 Sep 2022 16:06:53 +0200 Subject: [PATCH 15/16] arm: mvebu: Enable L2 cache also on Armada 38x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some unknown reason when L2 cache is disabled on Armada 385 then loadb, loadx and loady commands do not work with higher baudrates than 115200 (they just abort transfer) and lzmadec command with lzma image of size 0x7000000 (maybe even smaller, we tested this one) is doing decompression for more than 2 minutes. After enabling L2 cache decompression takes only 30s and loadb, loadx and loady are stable and working fine. git bisect identified problematic commit 3308933d2fe9 ("arm: mvebu: Avoid reading MVEBU_REG_PCIE_DEVID register too many times"). Before this commit above issues were not present. But investigation showed that above issue was possible to reproduce also by reverting that commit and forcing compiler to do inline optimization of mvebu_soc_family() function. Which seems that the root of this issue is in caches and position of instruction of segments. So currently it is unknown what is or was broken, but code movement, code inlining or other compiler optimization triggered it. Commit 3e5ce7ceeb94 ("arm: mvebu: Enable L2 cache on Armada XP") mentioned that enabling L2 cache on Armada XP improved performance and that Armada 38x has L2 disabled (which is default state) and if needed it has to be enabled in separate patch. As enabling L2 cache also improve performance on Armada 38x, enable it. Note that Aurora cache in no outer mode is available only on Armada XP, hence it is not touched for Armada 38x code. Fixes: 3308933d2fe9 ("arm: mvebu: Avoid reading MVEBU_REG_PCIE_DEVID register too many times") Reported-by: Marek Behún Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/cpu.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 949bf21c9b..77e403ba73 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -671,12 +671,20 @@ void enable_caches(void) void v7_outer_cache_enable(void) { - if (IS_ENABLED(CONFIG_ARMADA_XP)) { - struct pl310_regs *const pl310 = - (struct pl310_regs *)CONFIG_SYS_PL310_BASE; - u32 u; + struct pl310_regs *const pl310 = + (struct pl310_regs *)CONFIG_SYS_PL310_BASE; - /* The L2 cache is already disabled at this point */ + /* The L2 cache is already disabled at this point */ + + /* + * For now L2 cache will be enabled only for Armada XP and Armada 38x. + * It can be enabled also for other SoCs after testing that it works fine. + */ + if (!IS_ENABLED(CONFIG_ARMADA_XP) && !IS_ENABLED(CONFIG_ARMADA_38X)) + return; + + if (IS_ENABLED(CONFIG_ARMADA_XP)) { + u32 u; /* * For Aurora cache in no outer mode, enable via the CP15 @@ -687,10 +695,10 @@ void v7_outer_cache_enable(void) asm volatile("mcr p15, 1, %0, c15, c2, 0" : : "r" (u)); isb(); - - /* Enable the L2 cache */ - setbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN); } + + /* Enable the L2 cache */ + setbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN); } void v7_outer_cache_disable(void) From 5818198e6a184963c6afc82178b23a64435ace6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 8 Sep 2022 16:06:54 +0200 Subject: [PATCH 16/16] arm: mvebu: Fix moving internal registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 5bb2c550b11e ("arm: mvebu: Move internal registers in arch_very_early_init() function") moved code from file cpu.c to lowlevel.c, which moves Marvell internal registers from address INTREG_BASE_ADDR_REG to SOC_REGS_PHY_BASE. But the steps describing how to do it correctly were documented only in older U-Boot versions and commit cefd764222ee ("arm: mvebu: Fix internal register config on A38x") probably unintentionally removed important details about MMU from code comments around. Commit 5bb2c550b11e ("arm: mvebu: Move internal registers in arch_very_early_init() function") implemented code movement according to (now incomplete) comments which resulted in semi-broken code. The result is that I-cache is currently disabled for all Armada 38x boards and maybe there are some other (unreported / undetected) issues. Reimplement it correctly. First flush all caches, then disable MMU and L2 cache and then move Marvell internal registers. There is no need to explicitly disable I-cache. After this change lzmadec command with lzma image of 0x7000000 bytes is doing decompression just 5 seconds. Before this change it was 30 seconds. To make lowlevel.S code more readable, extend asm/pl310.h header file to be compatible with assembler and use macros from this file. Fixes: 5bb2c550b11e ("arm: mvebu: Move internal registers in arch_very_early_init() function") Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/include/asm/pl310.h | 9 +++++++-- arch/arm/mach-mvebu/cpu.c | 13 ------------- arch/arm/mach-mvebu/lowlevel.S | 27 +++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/arch/arm/include/asm/pl310.h b/arch/arm/include/asm/pl310.h index f69e9e45f8..9d4cd68ee4 100644 --- a/arch/arm/include/asm/pl310.h +++ b/arch/arm/include/asm/pl310.h @@ -7,13 +7,12 @@ #ifndef _PL310_H_ #define _PL310_H_ -#include - /* Register bit fields */ #define PL310_AUX_CTRL_ASSOCIATIVITY_MASK (1 << 16) #define L2X0_DYNAMIC_CLK_GATING_EN (1 << 1) #define L2X0_STNDBY_MODE_EN (1 << 0) #define L2X0_CTRL_EN 1 +#define L2X0_CTRL_OFF 0x100 #define L310_SHARED_ATT_OVERRIDE_ENABLE (1 << 22) #define L310_AUX_CTRL_DATA_PREFETCH_MASK (1 << 28) @@ -27,6 +26,10 @@ #define L2X0_CACHE_ID_RTL_MASK 0x3f #define L2X0_CACHE_ID_RTL_R3P2 0x8 +#ifndef __ASSEMBLY__ + +#include + struct pl310_regs { u32 pl310_cache_id; u32 pl310_cache_type; @@ -87,3 +90,5 @@ void pl310_inval_range(u32 start, u32 end); void pl310_clean_inval_range(u32 start, u32 end); #endif + +#endif diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 77e403ba73..1f8cdf8744 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -445,19 +445,6 @@ static void setup_usb_phys(void) */ int arch_cpu_init(void) { - struct pl310_regs *const pl310 = - (struct pl310_regs *)CONFIG_SYS_PL310_BASE; - - if (!IS_ENABLED(CONFIG_ARMADA_XP)) { - /* - * To fully release / unlock this area from cache, we need - * to flush all caches and disable the L2 cache. - */ - icache_disable(); - dcache_disable(); - clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN); - } - /* * We need to call mvebu_mbus_probe() before calling * update_sdram_window_sizes() as it disables all previously diff --git a/arch/arm/mach-mvebu/lowlevel.S b/arch/arm/mach-mvebu/lowlevel.S index b460382c6b..60c2072c35 100644 --- a/arch/arm/mach-mvebu/lowlevel.S +++ b/arch/arm/mach-mvebu/lowlevel.S @@ -3,6 +3,7 @@ #include #include #include +#include ENTRY(arch_very_early_init) #ifdef CONFIG_ARMADA_38X @@ -11,10 +12,36 @@ ENTRY(arch_very_early_init) * register address on Armada 38x. Without this the SDRAM * located at >= 0x4000.0000 is also not accessible, as its * still locked to cache. + * + * So to fully release / unlock this area from cache, we need + * to first flush all caches, then disable the MMU and + * disable the L2 cache. */ + + /* Invalidate L1 I/D */ + mov r0, #0 @ set up for MCR + mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs + mcr p15, 0, r0, c7, c5, 0 @ invalidate icache + mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array + mcr p15, 0, r0, c7, c10, 4 @ DSB + mcr p15, 0, r0, c7, c5, 4 @ ISB + + /* Disable MMU */ mrc p15, 0, r0, c1, c0, 0 bic r0, #CR_M mcr p15, 0, r0, c1, c0, 0 + + /* + * Disable L2 cache + * + * NOTE: Internal registers are still at address INTREG_BASE_ADDR_REG + * but CONFIG_SYS_PL310_BASE is already calculated from base + * address SOC_REGS_PHY_BASE. + */ + ldr r1, =(CONFIG_SYS_PL310_BASE - SOC_REGS_PHY_BASE + INTREG_BASE_ADDR_REG) + ldr r0, [r1, #L2X0_CTRL_OFF] + bic r0, #L2X0_CTRL_EN + str r0, [r1, #L2X0_CTRL_OFF] #endif /* Move internal registers from INTREG_BASE_ADDR_REG to SOC_REGS_PHY_BASE */