aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kconfig11
-rw-r--r--Makefile4
-rw-r--r--README3
-rw-r--r--arch/arm/dts/Makefile5
-rw-r--r--arch/arm/dts/at91sam9g25-gardena-smart-gateway-u-boot.dtsi5
-rw-r--r--arch/arm/dts/at91sam9g25-gardena-smart-gateway.dts120
-rw-r--r--arch/arm/dts/at91sam9x5.dtsi2
-rw-r--r--arch/arm/mach-at91/Kconfig8
-rw-r--r--arch/arm/mach-at91/arm926ejs/Makefile2
-rw-r--r--arch/arm/mach-at91/arm926ejs/u-boot-spl.lds2
-rw-r--r--arch/arm/mach-at91/armv7/sama5d2_devices.c2
-rw-r--r--arch/arm/mach-at91/clock.c48
-rw-r--r--arch/arm/mach-at91/include/mach/at91_wdt.h10
-rw-r--r--arch/arm/mach-at91/include/mach/sama5d2.h5
-rw-r--r--arch/arm/mach-at91/spl_at91.c10
-rw-r--r--arch/riscv/Kconfig46
-rw-r--r--arch/riscv/cpu/ax25/Kconfig7
-rw-r--r--arch/riscv/cpu/cpu.c9
-rw-r--r--arch/riscv/cpu/start.S167
-rw-r--r--arch/riscv/dts/Makefile2
-rw-r--r--arch/riscv/dts/ae350_32.dts81
-rw-r--r--arch/riscv/dts/ae350_64.dts81
-rw-r--r--arch/riscv/include/asm/csr.h1
-rw-r--r--arch/riscv/include/asm/global_data.h12
-rw-r--r--arch/riscv/include/asm/sbi.h94
-rw-r--r--arch/riscv/include/asm/smp.h53
-rw-r--r--arch/riscv/include/asm/syscon.h4
-rw-r--r--arch/riscv/lib/Makefile4
-rw-r--r--arch/riscv/lib/andes_plic.c113
-rw-r--r--arch/riscv/lib/andes_plmt.c53
-rw-r--r--arch/riscv/lib/asm-offsets.c1
-rw-r--r--arch/riscv/lib/bootm.c13
-rw-r--r--arch/riscv/lib/sbi_ipi.c25
-rw-r--r--arch/riscv/lib/smp.c118
-rw-r--r--board/AndesTech/ax25-ae350/Kconfig1
-rw-r--r--board/emulation/qemu-riscv/Kconfig1
-rw-r--r--board/gardena/smart-gateway-at91sam/Kconfig12
-rw-r--r--board/gardena/smart-gateway-at91sam/MAINTAINERS7
-rw-r--r--board/gardena/smart-gateway-at91sam/Makefile7
-rw-r--r--board/gardena/smart-gateway-at91sam/board.c59
-rw-r--r--board/gardena/smart-gateway-at91sam/spl.c135
-rw-r--r--board/ronetix/pm9g45/pm9g45.c10
-rw-r--r--board/sifive/fu540/Kconfig1
-rw-r--r--cmd/fs.c14
-rw-r--r--configs/ae350_rv32_defconfig1
-rw-r--r--configs/ae350_rv64_defconfig1
-rw-r--r--configs/gardena-smart-gateway-at91sam_defconfig83
-rw-r--r--configs/pm9g45_defconfig44
-rw-r--r--configs/smartweb_defconfig1
-rw-r--r--configs/taurus_defconfig1
-rw-r--r--drivers/mtd/ubi/debug.h10
-rw-r--r--drivers/net/macb.c8
-rw-r--r--drivers/pinctrl/pinctrl-at91.c84
-rw-r--r--drivers/serial/Kconfig9
-rw-r--r--drivers/serial/atmel_usart.c12
-rw-r--r--drivers/watchdog/Kconfig4
-rw-r--r--drivers/watchdog/at91sam9_wdt.c32
-rw-r--r--env/ext4.c2
-rw-r--r--fs/ext4/ext4_common.c76
-rw-r--r--fs/ext4/ext4_common.h2
-rw-r--r--fs/ext4/ext4_journal.c22
-rw-r--r--fs/ext4/ext4_write.c66
-rw-r--r--fs/ext4/ext4fs.c51
-rw-r--r--fs/fat/fat.c47
-rw-r--r--fs/fs.c44
-rw-r--r--fs/ubifs/debug.h4
-rw-r--r--include/configs/corvus.h3
-rw-r--r--include/configs/gardena-smart-gateway-at91sam.h88
-rw-r--r--include/configs/pm9g45.h173
-rw-r--r--include/configs/smartweb.h4
-rw-r--r--include/configs/taurus.h3
-rw-r--r--include/dt-bindings/pinctrl/at91.h4
-rw-r--r--include/efi_api.h4
-rw-r--r--include/efi_loader.h14
-rw-r--r--include/ext4fs.h17
-rw-r--r--include/fs.h2
-rw-r--r--include/watchdog.h10
-rw-r--r--lib/efi_loader/efi_bootmgr.c51
-rw-r--r--lib/efi_loader/efi_boottime.c328
-rw-r--r--lib/efi_loader/efi_console.c17
-rw-r--r--lib/efi_loader/efi_file.c108
-rw-r--r--lib/efi_loader/efi_image_loader.c24
-rw-r--r--lib/efi_loader/efi_memory.c80
-rw-r--r--lib/efi_loader/efi_setup.c27
-rw-r--r--lib/efi_loader/efi_variable.c10
-rw-r--r--lib/efi_selftest/efi_selftest_miniapp_exit.c58
-rw-r--r--scripts/Makefile.spl6
-rw-r--r--test/py/tests/test_efi_selftest.py2
-rw-r--r--test/py/tests/test_fs/conftest.py77
-rw-r--r--test/py/tests/test_fs/fstest_defs.py3
-rw-r--r--test/py/tests/test_fs/fstest_helpers.py13
-rw-r--r--test/py/tests/test_fs/test_basic.py4
-rw-r--r--test/py/tests/test_fs/test_ext.py10
-rw-r--r--test/py/tests/test_fs/test_mkdir.py8
-rw-r--r--test/py/tests/test_fs/test_symlink.py130
-rw-r--r--test/py/tests/test_fs/test_unlink.py14
-rw-r--r--test/py/tests/test_mmc_rd.py133
97 files changed, 2892 insertions, 505 deletions
diff --git a/Kconfig b/Kconfig
index 305b265..7a5491b 100644
--- a/Kconfig
+++ b/Kconfig
@@ -224,6 +224,16 @@ config BUILD_ROM
which are not shipped in the U-Boot source tree.
Please, see doc/README.x86 for details.
+config SPL_IMAGE
+ string "SPL image used in the combined SPL+U-Boot image"
+ default "spl/boot.bin" if ARCH_AT91 && SPL_NAND_SUPPORT
+ default "spl/u-boot-spl.bin"
+ help
+ Select the SPL build target that shall be generated by the SPL
+ build process (default spl/u-boot-spl.bin). This image will be
+ used to generate a combined image with SPL and main U-Boot
+ proper as one single image.
+
config BUILD_TARGET
string "Build target special images"
default "u-boot-with-spl.sfp" if TARGET_SOCFPGA_ARRIA10
@@ -232,6 +242,7 @@ config BUILD_TARGET
default "u-boot-elf.srec" if RCAR_GEN3
default "u-boot.itb" if SPL_LOAD_FIT && ARCH_SUNXI
default "u-boot.kwb" if KIRKWOOD
+ default "u-boot-with-spl.bin" if ARCH_AT91 && SPL_NAND_SUPPORT
help
Some SoCs need special image types (e.g. U-Boot binary
with a special header) as build targets. By defining
diff --git a/Makefile b/Makefile
index 4e4a33d..9709e76 100644
--- a/Makefile
+++ b/Makefile
@@ -1246,9 +1246,11 @@ else
SPL_PAYLOAD := u-boot.bin
endif
+SPL_IMAGE := $(CONFIG_SPL_IMAGE:"%"=%)
+
OBJCOPYFLAGS_u-boot-with-spl.bin = -I binary -O binary \
--pad-to=$(CONFIG_SPL_PAD_TO)
-u-boot-with-spl.bin: spl/u-boot-spl.bin $(SPL_PAYLOAD) FORCE
+u-boot-with-spl.bin: $(SPL_IMAGE) $(SPL_PAYLOAD) FORCE
$(call if_changed,pad_cat)
ifeq ($(CONFIG_ARCH_LPC32XX)$(CONFIG_SPL),yy)
diff --git a/README b/README
index c9a20db..a514f48 100644
--- a/README
+++ b/README
@@ -767,9 +767,6 @@ The following options need to be configured:
SoC, then define this variable and provide board
specific code for the "hw_watchdog_reset" function.
- CONFIG_AT91_HW_WDT_TIMEOUT
- specify the timeout in seconds. default 2 seconds.
-
- Real-Time Clock:
When CONFIG_CMD_DATE is selected, the type of the RTC
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 8a4efee..86a01c2 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -599,6 +599,8 @@ dtb-$(CONFIG_TARGET_AT91SAM9260EK) += \
dtb-$(CONFIG_TARGET_AT91SAM9M10G45EK) += at91sam9m10g45ek.dtb
+dtb-$(CONFIG_TARGET_PM9G45) += at91sam9m10g45ek.dtb
+
dtb-$(CONFIG_TARGET_AT91SAM9X5EK) += \
at91sam9g15ek.dtb \
at91sam9g25ek.dtb \
@@ -608,6 +610,9 @@ dtb-$(CONFIG_TARGET_AT91SAM9X5EK) += \
dtb-$(CONFIG_TARGET_AT91SAM9N12EK) += at91sam9n12ek.dtb
+dtb-$(CONFIG_TARGET_GARDENA_SMART_GATEWAY_AT91SAM) += \
+ at91sam9g25-gardena-smart-gateway.dtb
+
dtb-$(CONFIG_TARGET_ETHERNUT5) += ethernut5.dtb
dtb-$(CONFIG_TARGET_USB_A9263) += usb_a9263.dtb
diff --git a/arch/arm/dts/at91sam9g25-gardena-smart-gateway-u-boot.dtsi b/arch/arm/dts/at91sam9g25-gardena-smart-gateway-u-boot.dtsi
new file mode 100644
index 0000000..732dee6
--- /dev/null
+++ b/arch/arm/dts/at91sam9g25-gardena-smart-gateway-u-boot.dtsi
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+&dbgu {
+ u-boot,dm-pre-reloc;
+};
diff --git a/arch/arm/dts/at91sam9g25-gardena-smart-gateway.dts b/arch/arm/dts/at91sam9g25-gardena-smart-gateway.dts
new file mode 100644
index 0000000..e2f8d80
--- /dev/null
+++ b/arch/arm/dts/at91sam9g25-gardena-smart-gateway.dts
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Device Tree file for the GARDENA smart Gateway (AT91SAM)
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ */
+
+/dts-v1/;
+
+#include "at91sam9g25.dtsi"
+
+/ {
+ model = "GARDENA smart Gateway (AT91SAM)";
+ compatible = "gardena,smart-gateway-at91sam", "atmel,at91sam9";
+
+ aliases {
+ serial0 = &dbgu;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ reg = <0x20000000 0x8000000>;
+ };
+
+ clocks {
+ slow_xtal {
+ clock-frequency = <32768>;
+ };
+
+ main_xtal {
+ clock-frequency = <12000000>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ power_blue {
+ label = "smartgw:power:blue";
+ gpios = <&pioC 21 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ power_green {
+ label = "smartgw:power:green";
+ gpios = <&pioC 20 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ };
+
+ power_red {
+ label = "smartgw:power:red";
+ gpios = <&pioC 19 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ radio_blue {
+ label = "smartgw:radio:blue";
+ gpios = <&pioC 18 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ radio_green {
+ label = "smartgw:radio:green";
+ gpios = <&pioC 17 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ radio_red {
+ label = "smartgw:radio:red";
+ gpios = <&pioC 16 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ internet_blue {
+ label = "smartgw:internet:blue";
+ gpios = <&pioC 15 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ internet_green {
+ label = "smartgw:internet:green";
+ gpios = <&pioC 14 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ internet_red {
+ label = "smartgw:internet:red";
+ gpios = <&pioC 13 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ };
+};
+
+&dbgu {
+ status = "okay";
+};
+
+&macb0 {
+ phy-mode = "rmii";
+ status = "okay";
+};
+
+&nand0 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "hw";
+ atmel,has-pmecc; /* Enable PMECC */
+ atmel,pmecc-cap = <2>;
+ atmel,pmecc-sector-size = <512>;
+ nand-on-flash-bbt;
+ status = "okay";
+};
+
+&watchdog {
+ status = "okay";
+ timeout-sec = <16>;
+};
diff --git a/arch/arm/dts/at91sam9x5.dtsi b/arch/arm/dts/at91sam9x5.dtsi
index ea319cc..bd4abe0 100644
--- a/arch/arm/dts/at91sam9x5.dtsi
+++ b/arch/arm/dts/at91sam9x5.dtsi
@@ -1180,7 +1180,7 @@
};
};
- watchdog@fffffe40 {
+ watchdog: watchdog@fffffe40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffe40 0x10>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index a6329dc..a089e94 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -147,6 +147,13 @@ config TARGET_AT91SAM9X5EK
select BOARD_LATE_INIT
select SUPPORT_SPL
+config TARGET_GARDENA_SMART_GATEWAY_AT91SAM
+ bool "GARDENA smart Gateway (AT91SAM)"
+ select AT91SAM9X5
+ select BOARD_EARLY_INIT_F
+ select BOARD_LATE_INIT
+ select SUPPORT_SPL
+
config TARGET_SAMA5D2_PTC_EK
bool "SAMA5D2 PTC EK board"
select BOARD_EARLY_INIT_F
@@ -283,6 +290,7 @@ source "board/bluewater/snapper9260/Kconfig"
source "board/calao/usb_a9263/Kconfig"
source "board/egnite/ethernut5/Kconfig"
source "board/esd/meesc/Kconfig"
+source "board/gardena/smart-gateway-at91sam/Kconfig"
source "board/l+g/vinco/Kconfig"
source "board/mini-box/picosam9g45/Kconfig"
source "board/ronetix/pm9261/Kconfig"
diff --git a/arch/arm/mach-at91/arm926ejs/Makefile b/arch/arm/mach-at91/arm926ejs/Makefile
index 0639d7e..6b0b289 100644
--- a/arch/arm/mach-at91/arm926ejs/Makefile
+++ b/arch/arm/mach-at91/arm926ejs/Makefile
@@ -24,8 +24,10 @@ obj-y += timer.o
endif
ifndef CONFIG_SKIP_LOWLEVEL_INIT
+ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
obj-y += lowlevel_init.o
endif
+endif
ifdef CONFIG_$(SPL_)SYS_THUMB_BUILD
ifndef CONFIG_HAS_THUMB2
diff --git a/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds b/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds
index f18b17d..3955bea 100644
--- a/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds
+++ b/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds
@@ -39,6 +39,8 @@ SECTIONS
*(.__end)
} >.sram
+ _image_binary_end = .;
+
.bss :
{
. = ALIGN(4);
diff --git a/arch/arm/mach-at91/armv7/sama5d2_devices.c b/arch/arm/mach-at91/armv7/sama5d2_devices.c
index 6432f66..59a0c44 100644
--- a/arch/arm/mach-at91/armv7/sama5d2_devices.c
+++ b/arch/arm/mach-at91/armv7/sama5d2_devices.c
@@ -9,7 +9,7 @@
#include <asm/arch/clk.h>
#include <asm/arch/sama5d2.h>
-int cpu_is_sama5d2(void)
+int _cpu_is_sama5d2(void)
{
unsigned int chip_id = get_chip_id();
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index 64cbc3d..1d3df2c 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -5,12 +5,17 @@
*/
#include <common.h>
+#include <dm.h>
+#include <wdt.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_wdt.h>
#define EN_UPLL_TIMEOUT 500
+static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
+
void at91_periph_clk_enable(int id)
{
struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
@@ -118,3 +123,46 @@ void at91_pllicpr_init(u32 icpr)
writel(icpr, &pmc->pllicpr);
}
+
+/* Called by macro WATCHDOG_RESET */
+void watchdog_reset(void)
+{
+ static ulong next_reset;
+ ulong now;
+
+ if (!watchdog_dev)
+ return;
+
+ now = get_timer(0);
+
+ /* Do not reset the watchdog too often */
+ if (now > next_reset) {
+ next_reset = now + 1000; /* reset every 1000ms */
+ wdt_reset(watchdog_dev);
+ }
+}
+
+int arch_early_init_r(void)
+{
+ struct at91_wdt_priv *priv;
+
+ /* Init watchdog */
+ if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
+ debug("Watchdog: Not found by seq!\n");
+ if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
+ puts("Watchdog: Not found!\n");
+ return 0;
+ }
+ }
+
+ priv = dev_get_priv(watchdog_dev);
+ if (!priv) {
+ printf("Watchdog: priv not available!\n");
+ return 0;
+ }
+
+ wdt_start(watchdog_dev, priv->timeout * 1000, 0);
+ printf("Watchdog: Started\n");
+
+ return 0;
+}
diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h b/arch/arm/mach-at91/include/mach/at91_wdt.h
index cd22723..a8fc73b 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -25,6 +25,12 @@ typedef struct at91_wdt {
u32 sr;
} at91_wdt_t;
+struct at91_wdt_priv {
+ void __iomem *regs;
+ u32 regval;
+ u32 timeout;
+};
+
#endif
/* Watchdog Control Register */
@@ -43,4 +49,8 @@ typedef struct at91_wdt {
#define AT91_WDT_MR_WDDBGHLT 0x10000000
#define AT91_WDT_MR_WDIDLEHLT 0x20000000
+/* Hardware timeout in seconds */
+#define WDT_MAX_TIMEOUT 16
+#define WDT_DEFAULT_TIMEOUT 2
+
#endif
diff --git a/arch/arm/mach-at91/include/mach/sama5d2.h b/arch/arm/mach-at91/include/mach/sama5d2.h
index 37806cb..c7d9bb5 100644
--- a/arch/arm/mach-at91/include/mach/sama5d2.h
+++ b/arch/arm/mach-at91/include/mach/sama5d2.h
@@ -222,6 +222,9 @@
#define ARCH_EXID_SAMA5D27C_D1G 0x00000033
#define ARCH_EXID_SAMA5D28C_D1G 0x00000013
+/* Checked if defined in ethernet driver macb */
+#define cpu_is_sama5d2 _cpu_is_sama5d2
+
/* PIT Timer(PIT_PIIR) */
#define CONFIG_SYS_TIMER_COUNTER 0xf804803c
@@ -231,7 +234,7 @@
#ifndef __ASSEMBLY__
unsigned int get_chip_id(void);
unsigned int get_extension_chip_id(void);
-int cpu_is_sama5d2(void);
+int _cpu_is_sama5d2(void);
unsigned int has_lcdc(void);
char *get_cpu_name(void);
#endif
diff --git a/arch/arm/mach-at91/spl_at91.c b/arch/arm/mach-at91/spl_at91.c
index 23ebaa9..1065f09 100644
--- a/arch/arm/mach-at91/spl_at91.c
+++ b/arch/arm/mach-at91/spl_at91.c
@@ -75,6 +75,16 @@ void __weak spl_board_init(void)
void board_init_f(ulong dummy)
{
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ int ret;
+
+ ret = spl_early_init();
+ if (ret) {
+ debug("spl_early_init() failed: %d\n", ret);
+ hang();
+ }
+#endif
+
lowlevel_clock_init();
#if !defined(CONFIG_WDT_AT91)
at91_disable_wdt();
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 36512a8..ae8ff7b 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -109,6 +109,24 @@ config SIFIVE_CLINT
The SiFive CLINT block holds memory-mapped control and status registers
associated with software and timer interrupts.
+config ANDES_PLIC
+ bool
+ depends on RISCV_MMODE
+ select REGMAP
+ select SYSCON
+ help
+ The Andes PLIC block holds memory-mapped claim and pending registers
+ associated with software interrupt.
+
+config ANDES_PLMT
+ bool
+ depends on RISCV_MMODE
+ select REGMAP
+ select SYSCON
+ help
+ The Andes PLMT block holds memory-mapped mtime register
+ associated with timer tick.
+
config RISCV_RDTIME
bool
default y if RISCV_SMODE
@@ -120,4 +138,32 @@ config RISCV_RDTIME
config SYS_MALLOC_F_LEN
default 0x1000
+config SMP
+ bool "Symmetric Multi-Processing"
+ help
+ This enables support for systems with more than one CPU. If
+ you say N here, U-Boot will run on single and multiprocessor
+ machines, but will use only one CPU of a multiprocessor
+ machine. If you say Y here, U-Boot will run on many, but not
+ all, single processor machines.
+
+config NR_CPUS
+ int "Maximum number of CPUs (2-32)"
+ range 2 32
+ depends on SMP
+ default 8
+ help
+ On multiprocessor machines, U-Boot sets up a stack for each CPU.
+ Stack memory is pre-allocated. U-Boot must therefore know the
+ maximum number of CPUs that may be present.
+
+config SBI_IPI
+ bool
+ default y if RISCV_SMODE
+ depends on SMP
+
+config STACK_SIZE_SHIFT
+ int
+ default 13
+
endmenu
diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig
index e9dbca2..6b4b92e 100644
--- a/arch/riscv/cpu/ax25/Kconfig
+++ b/arch/riscv/cpu/ax25/Kconfig
@@ -1,5 +1,11 @@
config RISCV_NDS
bool
+ select ARCH_EARLY_INIT_R
+ imply CPU
+ imply CPU_RISCV
+ imply RISCV_TIMER
+ imply ANDES_PLIC if RISCV_MMODE
+ imply ANDES_PLMT if RISCV_MMODE
help
Run U-Boot on AndeStar V5 platforms and use some specific features
which are provided by Andes Technology AndeStar V5 families.
@@ -8,6 +14,7 @@ if RISCV_NDS
config RISCV_NDS_CACHE
bool "AndeStar V5 families specific cache support"
+ depends on RISCV_MMODE
help
Provide Andes Technology AndeStar V5 families specific cache support.
diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index e662140..c32de8a 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -12,10 +12,17 @@
#include <dm/uclass-internal.h>
/*
- * prior_stage_fdt_address must be stored in the data section since it is used
+ * The variables here must be stored in the data section since they are used
* before the bss section is available.
*/
phys_addr_t prior_stage_fdt_address __attribute__((section(".data")));
+u32 hart_lottery __attribute__((section(".data"))) = 0;
+
+/*
+ * The main hart running U-Boot has acquired available_harts_lock until it has
+ * finished initialization of global data.
+ */
+u32 available_harts_lock = 1;
static inline bool supports_extension(char ext)
{
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 81ea52b..a4433fb 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -13,6 +13,7 @@
#include <config.h>
#include <common.h>
#include <elf.h>
+#include <asm/csr.h>
#include <asm/encoding.h>
#include <generated/asm-offsets.h>
@@ -32,11 +33,19 @@
#define SYM_SIZE 0x18
#endif
+.section .data
+secondary_harts_relocation_error:
+ .ascii "Relocation of secondary harts has failed, error %d\n"
+
.section .text
.globl _start
_start:
+#ifdef CONFIG_RISCV_MMODE
+ csrr a0, mhartid
+#endif
+
/* save hart id and dtb pointer */
- mv s0, a0
+ mv tp, a0
mv s1, a1
la t0, trap_entry
@@ -45,9 +54,22 @@ _start:
/* mask all interrupts */
csrw MODE_PREFIX(ie), zero
- /* Enable cache */
- jal icache_enable
- jal dcache_enable
+#ifdef CONFIG_SMP
+ /* check if hart is within range */
+ /* tp: hart id */
+ li t0, CONFIG_NR_CPUS
+ bge tp, t0, hart_out_of_bounds_loop
+#endif
+
+#ifdef CONFIG_SMP
+ /* set xSIE bit to receive IPIs */
+#ifdef CONFIG_RISCV_MMODE
+ li t0, MIE_MSIE
+#else
+ li t0, SIE_SSIE
+#endif
+ csrs MODE_PREFIX(ie), t0
+#endif
/*
* Set stackpointer in internal/ex RAM to call board_init_f
@@ -57,14 +79,33 @@ call_board_init_f:
li t1, CONFIG_SYS_INIT_SP_ADDR
and sp, t1, t0 /* force 16 byte alignment */
-#ifdef CONFIG_DEBUG_UART
- jal debug_uart_init
-#endif
-
call_board_init_f_0:
mv a0, sp
jal board_init_f_alloc_reserve
+
+ /*
+ * Set global data pointer here for all harts, uninitialized at this
+ * point.
+ */
+ mv gp, a0
+
+ /* setup stack */
+#ifdef CONFIG_SMP
+ /* tp: hart id */
+ slli t0, tp, CONFIG_STACK_SIZE_SHIFT
+ sub sp, a0, t0
+#else
mv sp, a0
+#endif
+
+ /*
+ * Pick hart to initialize global data and run U-Boot. The other harts
+ * wait for initialization to complete.
+ */
+ la t0, hart_lottery
+ li s2, 1
+ amoswap.w s2, t1, 0(t0)
+ bnez s2, wait_for_gd_init
la t0, prior_stage_fdt_address
SREG s1, 0(t0)
@@ -72,7 +113,42 @@ call_board_init_f_0:
jal board_init_f_init_reserve
/* save the boot hart id to global_data */
- SREG s0, GD_BOOT_HART(gp)
+ SREG tp, GD_BOOT_HART(gp)
+
+ la t0, available_harts_lock
+ fence rw, w
+ amoswap.w zero, zero, 0(t0)
+
+wait_for_gd_init:
+ la t0, available_harts_lock
+ li t1, 1
+1: amoswap.w t1, t1, 0(t0)
+ fence r, rw
+ bnez t1, 1b
+
+ /* register available harts in the available_harts mask */
+ li t1, 1
+ sll t1, t1, tp
+ LREG t2, GD_AVAILABLE_HARTS(gp)
+ or t2, t2, t1
+ SREG t2, GD_AVAILABLE_HARTS(gp)
+
+ fence rw, w
+ amoswap.w zero, zero, 0(t0)
+
+ /*
+ * Continue on hart lottery winner, others branch to
+ * secondary_hart_loop.
+ */
+ bnez s2, secondary_hart_loop
+
+ /* Enable cache */
+ jal icache_enable
+ jal dcache_enable
+
+#ifdef CONFIG_DEBUG_UART
+ jal debug_uart_init
+#endif
mv a0, zero /* a0 <-- boot_flags = 0 */
la t5, board_init_f
@@ -95,7 +171,14 @@ relocate_code:
*Set up the stack
*/
stack_setup:
+#ifdef CONFIG_SMP
+ /* tp: hart id */
+ slli t0, tp, CONFIG_STACK_SIZE_SHIFT
+ sub sp, s2, t0
+#else
mv sp, s2
+#endif
+
la t0, _start
sub t6, s4, t0 /* t6 <- relocation offset */
beq t0, s4, clear_bss /* skip relocation */
@@ -175,13 +258,37 @@ clear_bss:
add t0, t0, t6 /* t0 <- rel __bss_start in RAM */
la t1, __bss_end /* t1 <- rel __bss_end in FLASH */
add t1, t1, t6 /* t1 <- rel __bss_end in RAM */
- beq t0, t1, call_board_init_r
+ beq t0, t1, relocate_secondary_harts
clbss_l:
SREG zero, 0(t0) /* clear loop... */
addi t0, t0, REGBYTES
bne t0, t1, clbss_l
+relocate_secondary_harts:
+#ifdef CONFIG_SMP
+ /* send relocation IPI */
+ la t0, secondary_hart_relocate
+ add a0, t0, t6
+
+ /* store relocation offset */
+ mv s5, t6
+
+ mv a1, s2
+ mv a2, s3
+ jal smp_call_function
+
+ /* hang if relocation of secondary harts has failed */
+ beqz a0, 1f
+ mv a1, a0
+ la a0, secondary_harts_relocation_error
+ jal printf
+ jal hang
+
+ /* restore relocation offset */
+1: mv t6, s5
+#endif
+
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
@@ -202,3 +309,43 @@ call_board_init_r:
* jump to it ...
*/
jr t4 /* jump to board_init_r() */
+
+#ifdef CONFIG_SMP
+hart_out_of_bounds_loop:
+ /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */
+ wfi
+ j hart_out_of_bounds_loop
+#endif
+
+#ifdef CONFIG_SMP
+/* SMP relocation entry */
+secondary_hart_relocate:
+ /* a1: new sp */
+ /* a2: new gd */
+ /* tp: hart id */
+
+ /* setup stack */
+ slli t0, tp, CONFIG_STACK_SIZE_SHIFT
+ sub sp, a1, t0
+
+ /* update global data pointer */
+ mv gp, a2
+#endif
+
+secondary_hart_loop:
+ wfi
+
+#ifdef CONFIG_SMP
+ csrr t0, MODE_PREFIX(ip)
+#ifdef CONFIG_RISCV_MMODE
+ andi t0, t0, MIE_MSIE
+#else
+ andi t0, t0, SIE_SSIE
+#endif
+ beqz t0, secondary_hart_loop
+
+ mv a0, tp
+ jal handle_ipi
+#endif
+
+ j secondary_hart_loop
diff --git a/arch/riscv/dts/Makefile b/arch/riscv/dts/Makefile
index b400def..f9cd606 100644
--- a/arch/riscv/dts/Makefile
+++ b/arch/riscv/dts/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
+dtb-$(CONFIG_TARGET_AX25_AE350) += ae350_32.dtb ae350_64.dtb
+
targets += $(dtb-y)
DTC_FLAGS += -R 4 -p 0x1000
diff --git a/arch/riscv/dts/ae350_32.dts b/arch/riscv/dts/ae350_32.dts
index 0679827..2ec01a5 100644
--- a/arch/riscv/dts/ae350_32.dts
+++ b/arch/riscv/dts/ae350_32.dts
@@ -26,16 +26,49 @@
status = "okay";
compatible = "riscv";
riscv,isa = "rv32imafdc";
+ riscv,priv-major = <1>;
+ riscv,priv-minor = <10>;
mmu-type = "riscv,sv32";
clock-frequency = <60000000>;
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <32>;
d-cache-size = <0x8000>;
d-cache-line-size = <32>;
+ next-level-cache = <&L2>;
CPU0_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ reg = <1>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,isa = "rv32imafdc";
+ riscv,priv-major = <1>;
+ riscv,priv-minor = <10>;
+ mmu-type = "riscv,sv32";
+ clock-frequency = <60000000>;
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <32>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <32>;
+ next-level-cache = <&L2>;
+ CPU1_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ };
+ };
+
+ L2: l2-cache@e0500000 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-size = <0x40000>;
+ reg = <0x0 0xe0500000 0x0 0x40000>;
+ };
};
memory@0 {
@@ -46,32 +79,32 @@
soc {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "andestech,riscv-ae350-soc";
+ compatible = "simple-bus";
ranges;
- plic0: interrupt-controller@e4000000 {
- compatible = "riscv,plic0";
- #address-cells = <1>;
- #interrupt-cells = <1>;
- interrupt-controller;
- reg = <0xe4000000 0x2000000>;
- riscv,ndev=<71>;
- interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9>;
- };
+ plic0: interrupt-controller@e4000000 {
+ compatible = "riscv,plic0";
+ #address-cells = <1>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ reg = <0xe4000000 0x2000000>;
+ riscv,ndev=<71>;
+ interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9 &CPU1_intc 11 &CPU1_intc 9>;
+ };
- plic1: interrupt-controller@e6400000 {
- compatible = "riscv,plic1";
- #address-cells = <1>;
- #interrupt-cells = <1>;
- interrupt-controller;
- reg = <0xe6400000 0x400000>;
- riscv,ndev=<1>;
- interrupts-extended = <&CPU0_intc 3>;
- };
+ plic1: interrupt-controller@e6400000 {
+ compatible = "riscv,plic1";
+ #address-cells = <1>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ reg = <0xe6400000 0x400000>;
+ riscv,ndev=<2>;
+ interrupts-extended = <&CPU0_intc 3 &CPU1_intc 3>;
+ };
- plmt0@e6000000 {
- compatible = "riscv,plmt0";
- interrupts-extended = <&CPU0_intc 7>;
+ plmt0@e6000000 {
+ compatible = "riscv,plmt0";
+ interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7>;
reg = <0xe6000000 0x100000>;
};
};
@@ -146,6 +179,10 @@
interrupt-parent = <&plic0>;
};
+ pmu {
+ compatible = "riscv,base-pmu";
+ };
+
virtio_mmio@fe007000 {
interrupts = <0x17 0x4>;
interrupt-parent = <0x2>;
diff --git a/arch/riscv/dts/ae350_64.dts b/arch/riscv/dts/ae350_64.dts
index e48c298..cde5cde 100644
--- a/arch/riscv/dts/ae350_64.dts
+++ b/arch/riscv/dts/ae350_64.dts
@@ -26,16 +26,49 @@
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
+ riscv,priv-major = <1>;
+ riscv,priv-minor = <10>;
mmu-type = "riscv,sv39";
clock-frequency = <60000000>;
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <32>;
d-cache-size = <0x8000>;
d-cache-line-size = <32>;
+ next-level-cache = <&L2>;
CPU0_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ reg = <1>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,isa = "rv64imafdc";
+ riscv,priv-major = <1>;
+ riscv,priv-minor = <10>;
+ mmu-type = "riscv,sv39";
+ clock-frequency = <60000000>;
+ i-cache-size = <0x8000>;
+ i-cache-line-size = <32>;
+ d-cache-size = <0x8000>;
+ d-cache-line-size = <32>;
+ next-level-cache = <&L2>;
+ CPU1_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ };
+ };
+
+ L2: l2-cache@e0500000 {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-size = <0x40000>;
+ reg = <0x0 0xe0500000 0x0 0x40000>;
+ };
};
memory@0 {
@@ -46,32 +79,32 @@
soc {
#address-cells = <2>;
#size-cells = <2>;
- compatible = "andestech,riscv-ae350-soc";
+ compatible = "simple-bus";
ranges;
- plic0: interrupt-controller@e4000000 {
- compatible = "riscv,plic0";
- #address-cells = <2>;
- #interrupt-cells = <2>;
- interrupt-controller;
- reg = <0x0 0xe4000000 0x0 0x2000000>;
- riscv,ndev=<71>;
- interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9>;
- };
+ plic0: interrupt-controller@e4000000 {
+ compatible = "riscv,plic0";
+ #address-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0x0 0xe4000000 0x0 0x2000000>;
+ riscv,ndev=<71>;
+ interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9 &CPU1_intc 11 &CPU1_intc 9>;
+ };
- plic1: interrupt-controller@e6400000 {
- compatible = "riscv,plic1";
- #address-cells = <2>;
- #interrupt-cells = <2>;
- interrupt-controller;
- reg = <0x0 0xe6400000 0x0 0x400000>;
- riscv,ndev=<1>;
- interrupts-extended = <&CPU0_intc 3>;
- };
+ plic1: interrupt-controller@e6400000 {
+ compatible = "riscv,plic1";
+ #address-cells = <2>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0x0 0xe6400000 0x0 0x400000>;
+ riscv,ndev=<2>;
+ interrupts-extended = <&CPU0_intc 3 &CPU1_intc 3>;
+ };
- plmt0@e6000000 {
- compatible = "riscv,plmt0";
- interrupts-extended = <&CPU0_intc 7>;
+ plmt0@e6000000 {
+ compatible = "riscv,plmt0";
+ interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7>;
reg = <0x0 0xe6000000 0x0 0x100000>;
};
};
@@ -146,6 +179,10 @@
interrupt-parent = <&plic0>;
};
+ pmu {
+ compatible = "riscv,base-pmu";
+ };
+
virtio_mmio@fe007000 {
interrupts = <0x17 0x4>;
interrupt-parent = <0x2>;
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 86136f5..644e6ba 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -46,6 +46,7 @@
#endif
/* Interrupt Enable and Interrupt Pending flags */
+#define MIE_MSIE _AC(0x00000008, UL) /* Software Interrupt Enable */
#define SIE_SSIE _AC(0x00000002, UL) /* Software Interrupt Enable */
#define SIE_STIE _AC(0x00000020, UL) /* Timer Interrupt Enable */
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h
index a3a342c..dffcd45 100644
--- a/arch/riscv/include/asm/global_data.h
+++ b/arch/riscv/include/asm/global_data.h
@@ -10,12 +10,24 @@
#ifndef __ASM_GBL_DATA_H
#define __ASM_GBL_DATA_H
+#include <asm/smp.h>
+
/* Architecture-specific global data */
struct arch_global_data {
long boot_hart; /* boot hart id */
#ifdef CONFIG_SIFIVE_CLINT
void __iomem *clint; /* clint base address */
#endif
+#ifdef CONFIG_ANDES_PLIC
+ void __iomem *plic; /* plic base address */
+#endif
+#ifdef CONFIG_ANDES_PLMT
+ void __iomem *plmt; /* plmt base address */
+#endif
+#ifdef CONFIG_SMP
+ struct ipi_data ipi[CONFIG_NR_CPUS];
+#endif
+ ulong available_harts;
};
#include <asm-generic/global_data.h>
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
new file mode 100644
index 0000000..ced57de
--- /dev/null
+++ b/arch/riscv/include/asm/sbi.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2015 Regents of the University of California
+ *
+ * Taken from Linux arch/riscv/include/asm/sbi.h
+ */
+
+#ifndef _ASM_RISCV_SBI_H
+#define _ASM_RISCV_SBI_H
+
+#include <linux/types.h>
+
+#define SBI_SET_TIMER 0
+#define SBI_CONSOLE_PUTCHAR 1
+#define SBI_CONSOLE_GETCHAR 2
+#define SBI_CLEAR_IPI 3
+#define SBI_SEND_IPI 4
+#define SBI_REMOTE_FENCE_I 5
+#define SBI_REMOTE_SFENCE_VMA 6
+#define SBI_REMOTE_SFENCE_VMA_ASID 7
+#define SBI_SHUTDOWN 8
+
+#define SBI_CALL(which, arg0, arg1, arg2) ({ \
+ register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); \
+ register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); \
+ register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); \
+ register uintptr_t a7 asm ("a7") = (uintptr_t)(which); \
+ asm volatile ("ecall" \
+ : "+r" (a0) \
+ : "r" (a1), "r" (a2), "r" (a7) \
+ : "memory"); \
+ a0; \
+})
+
+/* Lazy implementations until SBI is finalized */
+#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0)
+#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0)
+#define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0)
+
+static inline void sbi_console_putchar(int ch)
+{
+ SBI_CALL_1(SBI_CONSOLE_PUTCHAR, ch);
+}
+
+static inline int sbi_console_getchar(void)
+{
+ return SBI_CALL_0(SBI_CONSOLE_GETCHAR);
+}
+
+static inline void sbi_set_timer(uint64_t stime_value)
+{
+#if __riscv_xlen == 32
+ SBI_CALL_2(SBI_SET_TIMER, stime_value, stime_value >> 32);
+#else
+ SBI_CALL_1(SBI_SET_TIMER, stime_value);
+#endif
+}
+
+static inline void sbi_shutdown(void)
+{
+ SBI_CALL_0(SBI_SHUTDOWN);
+}
+
+static inline void sbi_clear_ipi(void)
+{
+ SBI_CALL_0(SBI_CLEAR_IPI);
+}
+
+static inline void sbi_send_ipi(const unsigned long *hart_mask)
+{
+ SBI_CALL_1(SBI_SEND_IPI, hart_mask);
+}
+
+static inline void sbi_remote_fence_i(const unsigned long *hart_mask)
+{
+ SBI_CALL_1(SBI_REMOTE_FENCE_I, hart_mask);
+}
+
+static inline void sbi_remote_sfence_vma(const unsigned long *hart_mask,
+ unsigned long start,
+ unsigned long size)
+{
+ SBI_CALL_1(SBI_REMOTE_SFENCE_VMA, hart_mask);
+}
+
+static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
+ unsigned long start,
+ unsigned long size,
+ unsigned long asid)
+{
+ SBI_CALL_1(SBI_REMOTE_SFENCE_VMA_ASID, hart_mask);
+}
+
+#endif
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
new file mode 100644
index 0000000..bc863fd
--- /dev/null
+++ b/arch/riscv/include/asm/smp.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Fraunhofer AISEC,
+ * Lukas Auer <lukas.auer@aisec.fraunhofer.de>
+ */
+
+#ifndef _ASM_RISCV_SMP_H
+#define _ASM_RISCV_SMP_H
+
+/**
+ * struct ipi_data - Inter-processor interrupt (IPI) data structure
+ *
+ * IPIs are used for SMP support to communicate to other harts what function to
+ * call. Functions are in the form
+ * void (*addr)(ulong hart, ulong arg0, ulong arg1).
+ *
+ * The function address and the two arguments, arg0 and arg1, are stored in the
+ * IPI data structure. The hart ID is inserted by the hart handling the IPI and
+ * calling the function.
+ *
+ * @addr: Address of function
+ * @arg0: First argument of function
+ * @arg1: Second argument of function
+ */
+struct ipi_data {
+ ulong addr;
+ ulong arg0;
+ ulong arg1;
+};
+
+/**
+ * handle_ipi() - interrupt handler for software interrupts
+ *
+ * The IPI interrupt handler must be called to handle software interrupts. It
+ * calls the function specified in the hart's IPI data structure.
+ *
+ * @hart: Hart ID of the current hart
+ */
+void handle_ipi(ulong hart);
+
+/**
+ * smp_call_function() - Call a function on all other harts
+ *
+ * Send IPIs with the specified function call to all harts.
+ *
+ * @addr: Address of function
+ * @arg0: First argument of function
+ * @arg1: Second argument of function
+ * @return 0 if OK, -ve on error
+ */
+int smp_call_function(ulong addr, ulong arg0, ulong arg1);
+
+#endif
diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h
index d311ee6..26a008c 100644
--- a/arch/riscv/include/asm/syscon.h
+++ b/arch/riscv/include/asm/syscon.h
@@ -8,12 +8,12 @@
/*
* System controllers in a RISC-V system
- *
- * So far only SiFive's Core Local Interruptor (CLINT) is defined.
*/
enum {
RISCV_NONE,
RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */
+ RISCV_SYSCON_PLIC, /* Platform Level Interrupt Controller (PLIC) */
+ RISCV_SYSCON_PLMT, /* Platform Level Machine Timer (PLMT) */
};
#endif /* _ASM_SYSCON_H */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index edfa616..1c332db 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -11,9 +11,13 @@ obj-$(CONFIG_CMD_GO) += boot.o
obj-y += cache.o
obj-$(CONFIG_RISCV_RDTIME) += rdtime.o
obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
+obj-$(CONFIG_ANDES_PLIC) += andes_plic.o
+obj-$(CONFIG_ANDES_PLMT) += andes_plmt.o
obj-y += interrupts.o
obj-y += reset.o
+obj-$(CONFIG_SBI_IPI) += sbi_ipi.o
obj-y += setjmp.o
+obj-$(CONFIG_SMP) += smp.o
# For building EFI apps
CFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI)
diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c
new file mode 100644
index 0000000..2ffe49a
--- /dev/null
+++ b/arch/riscv/lib/andes_plic.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019, Rick Chen <rick@andestech.com>
+ *
+ * U-Boot syscon driver for Andes's Platform Level Interrupt Controller (PLIC).
+ * The PLIC block holds memory-mapped claim and pending registers
+ * associated with software interrupt.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/syscon.h>
+#include <cpu.h>
+
+/* pending register */
+#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + (hart) * 8)
+/* enable register */
+#define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80)
+/* claim register */
+#define CLAIM_REG(base, hart) ((ulong)(base) + 0x200004 + (hart) * 0x1000)
+
+#define ENABLE_HART_IPI (0x80808080)
+#define SEND_IPI_TO_HART(hart) (0x80 >> (hart))
+
+DECLARE_GLOBAL_DATA_PTR;
+static int init_plic(void);
+
+#define PLIC_BASE_GET(void) \
+ do { \
+ long *ret; \
+ \
+ if (!gd->arch.plic) { \
+ ret = syscon_get_first_range(RISCV_SYSCON_PLIC); \
+ if (IS_ERR(ret)) \
+ return PTR_ERR(ret); \
+ gd->arch.plic = ret; \
+ init_plic(); \
+ } \
+ } while (0)
+
+static int enable_ipi(int harts)
+{
+ int i;
+ int en = ENABLE_HART_IPI;
+
+ for (i = 0; i < harts; i++) {
+ en = en >> i;
+ writel(en, (void __iomem *)ENABLE_REG(gd->arch.plic, i));
+ }
+
+ return 0;
+}
+
+static int init_plic(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_find_first_device(UCLASS_CPU, &dev);
+ if (ret)
+ return ret;
+
+ if (ret == 0 && dev) {
+ ret = cpu_get_count(dev);
+ if (ret < 0)
+ return ret;
+
+ enable_ipi(ret);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+int riscv_send_ipi(int hart)
+{
+ PLIC_BASE_GET();
+
+ writel(SEND_IPI_TO_HART(hart),
+ (void __iomem *)PENDING_REG(gd->arch.plic, gd->arch.boot_hart));
+
+ return 0;
+}
+
+int riscv_clear_ipi(int hart)
+{
+ u32 source_id;
+
+ PLIC_BASE_GET();
+
+ source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plic, hart));
+ writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plic, hart));
+
+ return 0;
+}
+
+static const struct udevice_id andes_plic_ids[] = {
+ { .compatible = "riscv,plic1", .data = RISCV_SYSCON_PLIC },
+ { }
+};
+
+U_BOOT_DRIVER(andes_plic) = {
+ .name = "andes_plic",
+ .id = UCLASS_SYSCON,
+ .of_match = andes_plic_ids,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/arch/riscv/lib/andes_plmt.c b/arch/riscv/lib/andes_plmt.c
new file mode 100644
index 0000000..84f4607
--- /dev/null
+++ b/arch/riscv/lib/andes_plmt.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019, Rick Chen <rick@andestech.com>
+ *
+ * U-Boot syscon driver for Andes's Platform Level Machine Timer (PLMT).
+ * The PLMT block holds memory-mapped mtime register
+ * associated with timer tick.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/syscon.h>
+
+/* mtime register */
+#define MTIME_REG(base) ((ulong)(base))
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PLMT_BASE_GET(void) \
+ do { \
+ long *ret; \
+ \
+ if (!gd->arch.plmt) { \
+ ret = syscon_get_first_range(RISCV_SYSCON_PLMT); \
+ if (IS_ERR(ret)) \
+ return PTR_ERR(ret); \
+ gd->arch.plmt = ret; \
+ } \
+ } while (0)
+
+int riscv_get_time(u64 *time)
+{
+ PLMT_BASE_GET();
+
+ *time = readq((void __iomem *)MTIME_REG(gd->arch.plmt));
+
+ return 0;
+}
+
+static const struct udevice_id andes_plmt_ids[] = {
+ { .compatible = "riscv,plmt0", .data = RISCV_SYSCON_PLMT },
+ { }
+};
+
+U_BOOT_DRIVER(andes_plmt) = {
+ .name = "andes_plmt",
+ .id = UCLASS_SYSCON,
+ .of_match = andes_plmt_ids,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/arch/riscv/lib/asm-offsets.c b/arch/riscv/lib/asm-offsets.c
index e0b71f5..f998402 100644
--- a/arch/riscv/lib/asm-offsets.c
+++ b/arch/riscv/lib/asm-offsets.c
@@ -14,6 +14,7 @@
int main(void)
{
DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart));
+ DEFINE(GD_AVAILABLE_HARTS, offsetof(gd_t, arch.available_harts));
return 0;
}
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c
index f36b870..efbd3e2 100644
--- a/arch/riscv/lib/bootm.c
+++ b/arch/riscv/lib/bootm.c
@@ -13,6 +13,7 @@
#include <image.h>
#include <asm/byteorder.h>
#include <asm/csr.h>
+#include <asm/smp.h>
#include <dm/device.h>
#include <dm/root.h>
#include <u-boot/zlib.h>
@@ -81,6 +82,9 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
{
void (*kernel)(ulong hart, void *dtb);
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
+#ifdef CONFIG_SMP
+ int ret;
+#endif
kernel = (void (*)(ulong, void *))images->ep;
@@ -92,8 +96,15 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
announce_and_cleanup(fake);
if (!fake) {
- if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
+ if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
+#ifdef CONFIG_SMP
+ ret = smp_call_function(images->ep,
+ (ulong)images->ft_addr, 0);
+ if (ret)
+ hang();
+#endif
kernel(gd->arch.boot_hart, images->ft_addr);
+ }
}
}
diff --git a/arch/riscv/lib/sbi_ipi.c b/arch/riscv/lib/sbi_ipi.c
new file mode 100644
index 0000000..170346d
--- /dev/null
+++ b/arch/riscv/lib/sbi_ipi.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Fraunhofer AISEC,
+ * Lukas Auer <lukas.auer@aisec.fraunhofer.de>
+ */
+
+#include <common.h>
+#include <asm/sbi.h>
+
+int riscv_send_ipi(int hart)
+{
+ ulong mask;
+
+ mask = 1UL << hart;
+ sbi_send_ipi(&mask);
+
+ return 0;
+}
+
+int riscv_clear_ipi(int hart)
+{
+ sbi_clear_ipi();
+
+ return 0;
+}
diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c
new file mode 100644
index 0000000..caa292c
--- /dev/null
+++ b/arch/riscv/lib/smp.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Fraunhofer AISEC,
+ * Lukas Auer <lukas.auer@aisec.fraunhofer.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/barrier.h>
+#include <asm/smp.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * riscv_send_ipi() - Send inter-processor interrupt (IPI)
+ *
+ * Platform code must provide this function.
+ *
+ * @hart: Hart ID of receiving hart
+ * @return 0 if OK, -ve on error
+ */
+extern int riscv_send_ipi(int hart);
+
+/**
+ * riscv_clear_ipi() - Clear inter-processor interrupt (IPI)
+ *
+ * Platform code must provide this function.
+ *
+ * @hart: Hart ID of hart to be cleared
+ * @return 0 if OK, -ve on error
+ */
+extern int riscv_clear_ipi(int hart);
+
+static int send_ipi_many(struct ipi_data *ipi)
+{
+ ofnode node, cpus;
+ u32 reg;
+ int ret;
+
+ cpus = ofnode_path("/cpus");
+ if (!ofnode_valid(cpus)) {
+ pr_err("Can't find cpus node!\n");
+ return -EINVAL;
+ }
+
+ ofnode_for_each_subnode(node, cpus) {
+ /* skip if hart is marked as not available in the device tree */
+ if (!ofnode_is_available(node))
+ continue;
+
+ /* read hart ID of CPU */
+ ret = ofnode_read_u32(node, "reg", &reg);
+ if (ret)
+ continue;
+
+ /* skip if it is the hart we are running on */
+ if (reg == gd->arch.boot_hart)
+ continue;
+
+ if (reg >= CONFIG_NR_CPUS) {
+ pr_err("Hart ID %d is out of range, increase CONFIG_NR_CPUS\n",
+ reg);
+ continue;
+ }
+
+ /* skip if hart is not available */
+ if (!(gd->arch.available_harts & (1 << reg)))
+ continue;
+
+ gd->arch.ipi[reg].addr = ipi->addr;
+ gd->arch.ipi[reg].arg0 = ipi->arg0;
+ gd->arch.ipi[reg].arg1 = ipi->arg1;
+
+ ret = riscv_send_ipi(reg);
+ if (ret) {
+ pr_err("Cannot send IPI to hart %d\n", reg);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void handle_ipi(ulong hart)
+{
+ int ret;
+ void (*smp_function)(ulong hart, ulong arg0, ulong arg1);
+
+ if (hart >= CONFIG_NR_CPUS)
+ return;
+
+ ret = riscv_clear_ipi(hart);
+ if (ret) {
+ pr_err("Cannot clear IPI of hart %ld\n", hart);
+ return;
+ }
+
+ __smp_mb();
+
+ smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
+ invalidate_icache_all();
+
+ smp_function(hart, gd->arch.ipi[hart].arg0, gd->arch.ipi[hart].arg1);
+}
+
+int smp_call_function(ulong addr, ulong arg0, ulong arg1)
+{
+ int ret = 0;
+ struct ipi_data ipi;
+
+ ipi.addr = addr;
+ ipi.arg0 = arg0;
+ ipi.arg1 = arg1;
+
+ ret = send_ipi_many(&ipi);
+
+ return ret;
+}
diff --git a/board/AndesTech/ax25-ae350/Kconfig b/board/AndesTech/ax25-ae350/Kconfig
index 44cb302..5e682b6 100644
--- a/board/AndesTech/ax25-ae350/Kconfig
+++ b/board/AndesTech/ax25-ae350/Kconfig
@@ -24,5 +24,6 @@ config ENV_OFFSET
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
select RISCV_NDS
+ imply SMP
endif
diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig
index 88d07d5..cf057e7 100644
--- a/board/emulation/qemu-riscv/Kconfig
+++ b/board/emulation/qemu-riscv/Kconfig
@@ -34,5 +34,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
imply BOARD_LATE_INIT
imply OF_BOARD_SETUP
imply SIFIVE_SERIAL
+ imply SMP
endif
diff --git a/board/gardena/smart-gateway-at91sam/Kconfig b/board/gardena/smart-gateway-at91sam/Kconfig
new file mode 100644
index 0000000..ea2b5ff
--- /dev/null
+++ b/board/gardena/smart-gateway-at91sam/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_GARDENA_SMART_GATEWAY_AT91SAM
+
+config SYS_BOARD
+ default "smart-gateway-at91sam"
+
+config SYS_VENDOR
+ default "gardena"
+
+config SYS_CONFIG_NAME
+ default "gardena-smart-gateway-at91sam"
+
+endif
diff --git a/board/gardena/smart-gateway-at91sam/MAINTAINERS b/board/gardena/smart-gateway-at91sam/MAINTAINERS
new file mode 100644
index 0000000..a5e4c71
--- /dev/null
+++ b/board/gardena/smart-gateway-at91sam/MAINTAINERS
@@ -0,0 +1,7 @@
+GARDENA_SMART_GATEWAY_AT91SAM BOARD
+M: Stefan Roese <sr@denx.de>
+S: Maintained
+F: board/gardena/smart-gateway-at91sam/
+F: include/configs/gardena-smart-gateway-at91sam.h
+F: configs/gardena-smart-gateway-at91sam_defconfig
+F: arch/arm/dts/gardena-smart-gateway-at91sam.dts
diff --git a/board/gardena/smart-gateway-at91sam/Makefile b/board/gardena/smart-gateway-at91sam/Makefile
new file mode 100644
index 0000000..a2ed79f
--- /dev/null
+++ b/board/gardena/smart-gateway-at91sam/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y += board.o
+
+ifdef CONFIG_SPL_BUILD
+obj-y += spl.o
+endif
diff --git a/board/gardena/smart-gateway-at91sam/board.c b/board/gardena/smart-gateway-at91sam/board.c
new file mode 100644
index 0000000..6a1389e
--- /dev/null
+++ b/board/gardena/smart-gateway-at91sam/board.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Atmel Corporation
+ * Copyright (C) 2019 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <led.h>
+#include <asm/arch/at91_common.h>
+#include <asm/arch/clk.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void at91_prepare_cpu_var(void)
+{
+ env_set("cpu", get_cpu_name());
+}
+
+int board_late_init(void)
+{
+ at91_prepare_cpu_var();
+
+ if (IS_ENABLED(CONFIG_LED))
+ led_default_state();
+
+ return 0;
+}
+
+#ifdef CONFIG_DEBUG_UART_BOARD_INIT
+void board_debug_uart_init(void)
+{
+ at91_seriald_hw_init();
+}
+#endif
+
+int board_early_init_f(void)
+{
+#ifdef CONFIG_DEBUG_UART
+ debug_uart_init();
+#endif
+ return 0;
+}
+
+int board_init(void)
+{
+ /* Address of boot parameters */
+ gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+ return 0;
+}
+
+int dram_init(void)
+{
+ gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
+ CONFIG_SYS_SDRAM_SIZE);
+
+ return 0;
+}
diff --git a/board/gardena/smart-gateway-at91sam/spl.c b/board/gardena/smart-gateway-at91sam/spl.c
new file mode 100644
index 0000000..3ab6760
--- /dev/null
+++ b/board/gardena/smart-gateway-at91sam/spl.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Atmel Corporation
+ * Copyright (C) 2019 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <nand.h>
+#include <spl.h>
+#include <asm/arch/at91sam9x5_matrix.h>
+#include <asm/arch/at91sam9_smc.h>
+#include <asm/arch/atmel_mpddrc.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/gpio.h>
+
+static void at91sam9x5ek_nand_hw_init(void)
+{
+ struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC;
+ struct at91_matrix *matrix = (struct at91_matrix *)ATMEL_BASE_MATRIX;
+ unsigned long csa;
+
+ /* Enable CS3 */
+ csa = readl(&matrix->ebicsa);
+ csa |= AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA;
+
+ /* NAND flash on D16 */
+ csa |= AT91_MATRIX_NFD0_ON_D16;
+
+ /* Configure IO drive */
+ csa &= ~AT91_MATRIX_EBI_EBI_IOSR_NORMAL;
+
+ writel(csa, &matrix->ebicsa);
+
+ /* Configure SMC CS3 for NAND/SmartMedia */
+ writel(AT91_SMC_SETUP_NWE(1) | AT91_SMC_SETUP_NCS_WR(0) |
+ AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(0),
+ &smc->cs[3].setup);
+ writel(AT91_SMC_PULSE_NWE(3) | AT91_SMC_PULSE_NCS_WR(5) |
+ AT91_SMC_PULSE_NRD(4) | AT91_SMC_PULSE_NCS_RD(6),
+ &smc->cs[3].pulse);
+ writel(AT91_SMC_CYCLE_NWE(5) | AT91_SMC_CYCLE_NRD(6),
+ &smc->cs[3].cycle);
+ writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE |
+ AT91_SMC_MODE_EXNW_DISABLE |
+#ifdef CONFIG_SYS_NAND_DBW_16
+ AT91_SMC_MODE_DBW_16 |
+#else /* CONFIG_SYS_NAND_DBW_8 */
+ AT91_SMC_MODE_DBW_8 |
+#endif
+ AT91_SMC_MODE_TDF_CYCLE(1),
+ &smc->cs[3].mode);
+
+ at91_periph_clk_enable(ATMEL_ID_PIOCD);
+
+ /* Configure RDY/BSY */
+ at91_set_gpio_input(CONFIG_SYS_NAND_READY_PIN, 1);
+
+ /* Enable NandFlash */
+ at91_set_gpio_output(CONFIG_SYS_NAND_ENABLE_PIN, 1);
+
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 0, 1); /* NAND OE */
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 1, 1); /* NAND WE */
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 2, 1); /* NAND ALE */
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 3, 1); /* NAND CLE */
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 6, 1);
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 7, 1);
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 8, 1);
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 9, 1);
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 10, 1);
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 11, 1);
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 12, 1);
+ at91_pio3_set_a_periph(AT91_PIO_PORTD, 13, 1);
+}
+
+void at91_spl_board_init(void)
+{
+ at91sam9x5ek_nand_hw_init();
+}
+
+static void ddr2_conf(struct atmel_mpddrc_config *ddr2)
+{
+ ddr2->md = (ATMEL_MPDDRC_MD_DBW_16_BITS | ATMEL_MPDDRC_MD_DDR2_SDRAM);
+
+ ddr2->cr = (ATMEL_MPDDRC_CR_NC_COL_10 |
+ ATMEL_MPDDRC_CR_NR_ROW_13 |
+ ATMEL_MPDDRC_CR_CAS_DDR_CAS3 |
+ ATMEL_MPDDRC_CR_NB_8BANKS |
+ ATMEL_MPDDRC_CR_DECOD_INTERLEAVED);
+
+ ddr2->rtr = 0x411;
+
+ ddr2->tpr0 = (6 << ATMEL_MPDDRC_TPR0_TRAS_OFFSET |
+ 2 << ATMEL_MPDDRC_TPR0_TRCD_OFFSET |
+ 2 << ATMEL_MPDDRC_TPR0_TWR_OFFSET |
+ 8 << ATMEL_MPDDRC_TPR0_TRC_OFFSET |
+ 2 << ATMEL_MPDDRC_TPR0_TRP_OFFSET |
+ 2 << ATMEL_MPDDRC_TPR0_TRRD_OFFSET |
+ 2 << ATMEL_MPDDRC_TPR0_TWTR_OFFSET |
+ 2 << ATMEL_MPDDRC_TPR0_TMRD_OFFSET);
+
+ ddr2->tpr1 = (2 << ATMEL_MPDDRC_TPR1_TXP_OFFSET |
+ 200 << ATMEL_MPDDRC_TPR1_TXSRD_OFFSET |
+ 19 << ATMEL_MPDDRC_TPR1_TXSNR_OFFSET |
+ 18 << ATMEL_MPDDRC_TPR1_TRFC_OFFSET);
+
+ ddr2->tpr2 = (7 << ATMEL_MPDDRC_TPR2_TFAW_OFFSET |
+ 2 << ATMEL_MPDDRC_TPR2_TRTP_OFFSET |
+ 3 << ATMEL_MPDDRC_TPR2_TRPA_OFFSET |
+ 7 << ATMEL_MPDDRC_TPR2_TXARDS_OFFSET |
+ 2 << ATMEL_MPDDRC_TPR2_TXARD_OFFSET);
+}
+
+void mem_init(void)
+{
+ struct at91_matrix *matrix = (struct at91_matrix *)ATMEL_BASE_MATRIX;
+ struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+ struct atmel_mpddrc_config ddr2;
+ unsigned long csa;
+
+ ddr2_conf(&ddr2);
+
+ /* Enable DDR2 clock */
+ writel(AT91_PMC_DDR, &pmc->scer);
+
+ /* Chip select 1 is for DDR2/SDRAM */
+ csa = readl(&matrix->ebicsa);
+ csa |= AT91_MATRIX_EBI_CS1A_SDRAMC;
+ csa &= ~AT91_MATRIX_EBI_DBPU_OFF;
+ csa |= AT91_MATRIX_EBI_DBPD_OFF;
+ csa |= AT91_MATRIX_EBI_EBI_IOSR_NORMAL;
+ writel(csa, &matrix->ebicsa);
+
+ /* DDRAM2 Controller initialize */
+ ddr2_init(ATMEL_BASE_DDRSDRC, ATMEL_BASE_CS1, &ddr2);
+}
diff --git a/board/ronetix/pm9g45/pm9g45.c b/board/ronetix/pm9g45/pm9g45.c
index 17e520a..c5d28c6 100644
--- a/board/ronetix/pm9g45/pm9g45.c
+++ b/board/ronetix/pm9g45/pm9g45.c
@@ -124,7 +124,7 @@ int board_init(void)
/* arch number of AT91SAM9M10G45EK-Board */
gd->bd->bi_arch_number = MACH_TYPE_PM9G45;
/* adress of boot parameters */
- gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
+ gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
#ifdef CONFIG_CMD_NAND
pm9g45_nand_hw_init();
@@ -139,15 +139,15 @@ int board_init(void)
int dram_init(void)
{
/* dram_init must store complete ramsize in gd->ram_size */
- gd->ram_size = get_ram_size((void *)PHYS_SDRAM,
- PHYS_SDRAM_SIZE);
+ gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
+ CONFIG_SYS_SDRAM_SIZE);
return 0;
}
int dram_init_banksize(void)
{
- gd->bd->bi_dram[0].start = PHYS_SDRAM;
- gd->bd->bi_dram[0].size = PHYS_SDRAM_SIZE;
+ gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+ gd->bd->bi_dram[0].size = CONFIG_SYS_SDRAM_SIZE;
return 0;
}
diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig
index 6be3d88..f464379 100644
--- a/board/sifive/fu540/Kconfig
+++ b/board/sifive/fu540/Kconfig
@@ -38,5 +38,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
imply PHY_LIB
imply PHY_MSCC
imply SIFIVE_SERIAL
+ imply SMP
endif
diff --git a/cmd/fs.c b/cmd/fs.c
index 9446767..aaafbf9 100644
--- a/cmd/fs.c
+++ b/cmd/fs.c
@@ -76,6 +76,20 @@ U_BOOT_CMD(
" device type 'interface' instance 'dev'."
)
+static int do_ln_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ return do_ln(cmdtp, flag, argc, argv, FS_TYPE_ANY);
+}
+
+U_BOOT_CMD(
+ ln, 5, 1, do_ln_wrapper,
+ "Create a symbolic link",
+ "<interface> <dev[:part]> target linkname\n"
+ " - create a symbolic link to 'target' with the name 'linkname' on\n"
+ " device type 'interface' instance 'dev'."
+)
+
static int do_fstype_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
diff --git a/configs/ae350_rv32_defconfig b/configs/ae350_rv32_defconfig
index 6e0be88..f029455 100644
--- a/configs/ae350_rv32_defconfig
+++ b/configs/ae350_rv32_defconfig
@@ -34,4 +34,3 @@ CONFIG_BAUDRATE=38400
CONFIG_SYS_NS16550=y
CONFIG_SPI=y
CONFIG_ATCSPI200_SPI=y
-CONFIG_ATCPIT100_TIMER=y
diff --git a/configs/ae350_rv64_defconfig b/configs/ae350_rv64_defconfig
index b472a76..98635a2 100644
--- a/configs/ae350_rv64_defconfig
+++ b/configs/ae350_rv64_defconfig
@@ -35,4 +35,3 @@ CONFIG_BAUDRATE=38400
CONFIG_SYS_NS16550=y
CONFIG_SPI=y
CONFIG_ATCSPI200_SPI=y
-CONFIG_ATCPIT100_TIMER=y
diff --git a/configs/gardena-smart-gateway-at91sam_defconfig b/configs/gardena-smart-gateway-at91sam_defconfig
new file mode 100644
index 0000000..b395a5a
--- /dev/null
+++ b/configs/gardena-smart-gateway-at91sam_defconfig
@@ -0,0 +1,83 @@
+CONFIG_ARM=y
+CONFIG_SYS_THUMB_BUILD=y
+CONFIG_ARCH_AT91=y
+CONFIG_SYS_TEXT_BASE=0x22900000
+CONFIG_TARGET_GARDENA_SMART_GATEWAY_AT91SAM=y
+CONFIG_SPL_GPIO_SUPPORT=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x1000
+CONFIG_SPL=y
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_DEBUG_UART_BASE=0xfffff200
+CONFIG_DEBUG_UART_CLOCK=132000000
+CONFIG_SMBIOS_PRODUCT_NAME="at91sam9x5ek"
+CONFIG_DEBUG_UART=y
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_FIT=y
+CONFIG_NAND_BOOT=y
+CONFIG_BOOTDELAY=3
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256k(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs rw"
+CONFIG_SYS_CONSOLE_IS_IN_ENV=y
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+CONFIG_ARCH_EARLY_INIT_R=y
+CONFIG_SPL_SYS_MALLOC_SIMPLE=y
+CONFIG_SPL_SEPARATE_BSS=y
+# CONFIG_TPL_BANNER_PRINT is not set
+# CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR is not set
+CONFIG_SPL_NAND_SUPPORT=y
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_NAND=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_MTDIDS_DEFAULT="nand0=nand0"
+CONFIG_MTDPARTS_DEFAULT="nand0:1536k(uboot),1024k(unused),512k(dtb_old),4608k(kernel_old),86528k(ubi),-(rootfs_old)"
+CONFIG_CMD_UBI=y
+CONFIG_OF_CONTROL=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_DEFAULT_DEVICE_TREE="at91sam9g25-gardena-smart-gateway"
+CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clocks clock-names interrupts interrupt-parent interrupts-extended dmas dma-names"
+CONFIG_ENV_IS_IN_UBI=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_DM=y
+CONFIG_SPL_DM=y
+CONFIG_BLK=y
+CONFIG_CLK=y
+CONFIG_CLK_AT91=y
+CONFIG_DM_GPIO=y
+CONFIG_AT91_GPIO=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+# CONFIG_MMC is not set
+CONFIG_NAND_ATMEL=y
+CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER=y
+# CONFIG_CONFIG_UBI_SILENCE_MSG is not set
+CONFIG_DM_ETH=y
+CONFIG_MACB=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_AT91=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEBUG_UART_ATMEL=y
+CONFIG_ATMEL_USART=y
+CONFIG_TIMER=y
+CONFIG_SPL_TIMER=y
+CONFIG_ATMEL_PIT_TIMER=y
+# CONFIG_SYS_WHITE_ON_BLACK is not set
+CONFIG_WATCHDOG=y
+CONFIG_WDT=y
+CONFIG_WDT_AT91=y
+# CONFIG_UBIFS_SILENCE_MSG is not set
+CONFIG_USE_TINY_PRINTF=y
diff --git a/configs/pm9g45_defconfig b/configs/pm9g45_defconfig
index 928e446..c3f7e14 100644
--- a/configs/pm9g45_defconfig
+++ b/configs/pm9g45_defconfig
@@ -2,27 +2,57 @@ CONFIG_ARM=y
CONFIG_ARCH_AT91=y
CONFIG_SYS_TEXT_BASE=0x73f00000
CONFIG_TARGET_PM9G45=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_DEBUG_UART_BASE=0xffffee00
+CONFIG_DEBUG_UART_CLOCK=132000000
+CONFIG_DEBUG_UART=y
CONFIG_NR_DRAM_BANKS=1
-CONFIG_SYS_EXTRA_OPTIONS="AT91SAM9G45"
+CONFIG_NAND_BOOT=y
CONFIG_BOOTDELAY=3
CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="fbcon=rotate:3 console=tty0 console=ttyS0,115200 root=/dev/mtdblock4 mtdparts=atmel_nand:128k(bootstrap)ro,256k(uboot)ro,1664k(env),2M(linux)ro,-(root) rw rootfstype=jffs2"
-# CONFIG_DISPLAY_CPUINFO is not set
+# CONFIG_CONSOLE_MUX is not set
+CONFIG_SYS_CONSOLE_IS_IN_ENV=y
# CONFIG_DISPLAY_BOARDINFO is not set
-CONFIG_BOARD_EARLY_INIT_F=y
CONFIG_HUSH_PARSER=y
CONFIG_SYS_PROMPT="U-Boot> "
+# CONFIG_CMD_BDI is not set
+CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_IMI is not set
# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_MMC=y
CONFIG_CMD_NAND=y
CONFIG_CMD_USB=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
CONFIG_CMD_PING=y
-CONFIG_CMD_CACHE=y
-CONFIG_CMD_JFFS2=y
+CONFIG_CMD_FAT=y
+CONFIG_OF_CONTROL=y
+CONFIG_DEFAULT_DEVICE_TREE="at91sam9m10g45ek"
CONFIG_ENV_IS_IN_NAND=y
-# CONFIG_MMC is not set
-CONFIG_NAND=y
+CONFIG_DM=y
+CONFIG_CLK=y
+CONFIG_CLK_AT91=y
+CONFIG_DM_GPIO=y
+CONFIG_AT91_GPIO=y
+CONFIG_DM_MMC=y
+CONFIG_GENERIC_ATMEL_MCI=y
CONFIG_NAND_ATMEL=y
+CONFIG_DM_ETH=y
+CONFIG_MACB=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_AT91=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEBUG_UART_ATMEL=y
+CONFIG_DEBUG_UART_ANNOUNCE=y
+CONFIG_ATMEL_USART=y
+CONFIG_TIMER=y
+CONFIG_ATMEL_PIT_TIMER=y
CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EHCI_HCD=y
CONFIG_USB_STORAGE=y
diff --git a/configs/smartweb_defconfig b/configs/smartweb_defconfig
index 7c7220a..807a569 100644
--- a/configs/smartweb_defconfig
+++ b/configs/smartweb_defconfig
@@ -59,6 +59,5 @@ CONFIG_USB_ETHER_ASIX=y
CONFIG_USB_ETHER_MCS7830=y
CONFIG_WDT=y
CONFIG_WDT_AT91=y
-CONFIG_AT91_HW_WDT_TIMEOUT=y
CONFIG_SPL_TINY_MEMSET=y
# CONFIG_EFI_LOADER is not set
diff --git a/configs/taurus_defconfig b/configs/taurus_defconfig
index 022b0b6..d69f489 100644
--- a/configs/taurus_defconfig
+++ b/configs/taurus_defconfig
@@ -62,5 +62,4 @@ CONFIG_USB_GADGET_PRODUCT_NUM=0x02d2
CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_WDT=y
CONFIG_WDT_AT91=y
-CONFIG_AT91_HW_WDT_TIMEOUT=y
CONFIG_USE_TINY_PRINTF=y
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index 8ad0c62..2c2faaf 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -18,6 +18,7 @@ void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
#include <hexdump.h>
+#ifndef __UBOOT__
#define ubi_assert(expr) do { \
if (unlikely(!(expr))) { \
pr_crit("UBI assert failed in %s at %u (pid %d)\n", \
@@ -25,6 +26,15 @@ void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
dump_stack(); \
} \
} while (0)
+#else
+#define ubi_assert(expr) do { \
+ if (unlikely(!(expr))) { \
+ pr_debug("UBI assert failed in %s at %u\n", \
+ __func__, __LINE__); \
+ dump_stack(); \
+ } \
+} while (0)
+#endif
#define ubi_dbg_print_hex_dump(ps, pt, r, g, b, len, a) \
print_hex_dump(ps, pt, r, g, b, len, a)
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 182331f..7261416 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -550,8 +550,14 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) {
status = macb_mdio_read(macb, MII_BMSR);
- if (status & BMSR_LSTATUS)
+ if (status & BMSR_LSTATUS) {
+ /*
+ * Delay a bit after the link is established,
+ * so that the next xfer does not fail
+ */
+ mdelay(10);
break;
+ }
udelay(100);
}
}
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 4bdad62..27f274f 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -37,6 +37,9 @@ struct at91_pinctrl_priv {
#define OUTPUT BIT(7)
#define OUTPUT_VAL_SHIFT 8
#define OUTPUT_VAL (0x1 << OUTPUT_VAL_SHIFT)
+#define SLEWRATE_SHIFT 9
+#define SLEWRATE_MASK 0x1
+#define SLEWRATE (SLEWRATE_MASK << SLEWRATE_SHIFT)
#define DEBOUNCE BIT(16)
#define DEBOUNCE_VAL_SHIFT 17
#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT)
@@ -50,10 +53,22 @@ struct at91_pinctrl_priv {
* DRIVE_STRENGTH_DEFAULT is just a placeholder to avoid changing the drive
* strength when there is no dt config for it.
*/
-#define DRIVE_STRENGTH_DEFAULT (0 << DRIVE_STRENGTH_SHIFT)
-#define DRIVE_STRENGTH_LOW (1 << DRIVE_STRENGTH_SHIFT)
-#define DRIVE_STRENGTH_MED (2 << DRIVE_STRENGTH_SHIFT)
-#define DRIVE_STRENGTH_HI (3 << DRIVE_STRENGTH_SHIFT)
+enum drive_strength_bit {
+ DRIVE_STRENGTH_BIT_DEF,
+ DRIVE_STRENGTH_BIT_LOW,
+ DRIVE_STRENGTH_BIT_MED,
+ DRIVE_STRENGTH_BIT_HI,
+};
+
+#define DRIVE_STRENGTH_BIT_MSK(name) (DRIVE_STRENGTH_BIT_##name << \
+ DRIVE_STRENGTH_SHIFT)
+
+enum slewrate_bit {
+ SLEWRATE_BIT_DIS,
+ SLEWRATE_BIT_ENA,
+};
+
+#define SLEWRATE_BIT_MSK(name) (SLEWRATE_BIT_##name << SLEWRATE_SHIFT)
enum at91_mux {
AT91_MUX_GPIO = 0,
@@ -90,6 +105,7 @@ struct at91_pinctrl_mux_ops {
void (*disable_schmitt_trig)(struct at91_port *pio, u32 mask);
void (*set_drivestrength)(struct at91_port *pio, u32 pin,
u32 strength);
+ void (*set_slewrate)(struct at91_port *pio, u32 pin, u32 slewrate);
};
static u32 two_bit_pin_value_shift_amount(u32 pin)
@@ -238,11 +254,52 @@ static void at91_mux_sam9x5_set_drivestrength(struct at91_port *pio,
/* strength is inverse on SAM9x5s with our defines
* 0 = hi, 1 = med, 2 = low, 3 = rsvd */
- setting = DRIVE_STRENGTH_HI - setting;
+ setting = DRIVE_STRENGTH_BIT_MSK(HI) - setting;
set_drive_strength(reg, pin, setting);
}
+static void at91_mux_sam9x60_set_drivestrength(struct at91_port *pio, u32 pin,
+ u32 setting)
+{
+ void *reg = &pio->driver12;
+ u32 tmp;
+
+ if (setting <= DRIVE_STRENGTH_BIT_DEF ||
+ setting == DRIVE_STRENGTH_BIT_MED ||
+ setting > DRIVE_STRENGTH_BIT_HI)
+ return;
+
+ tmp = readl(reg);
+
+ /* Strength is 0: low, 1: hi */
+ if (setting == DRIVE_STRENGTH_BIT_LOW)
+ tmp &= ~BIT(pin);
+ else
+ tmp |= BIT(pin);
+
+ writel(tmp, reg);
+}
+
+static void at91_mux_sam9x60_set_slewrate(struct at91_port *pio, u32 pin,
+ u32 setting)
+{
+ void *reg = &pio->reserved12[3];
+ u32 tmp;
+
+ if (setting < SLEWRATE_BIT_DIS || setting > SLEWRATE_BIT_ENA)
+ return;
+
+ tmp = readl(reg);
+
+ if (setting == SLEWRATE_BIT_DIS)
+ tmp &= ~BIT(pin);
+ else
+ tmp |= BIT(pin);
+
+ writel(tmp, reg);
+}
+
static struct at91_pinctrl_mux_ops at91rm9200_ops = {
.mux_A_periph = at91_mux_set_A_periph,
.mux_B_periph = at91_mux_set_B_periph,
@@ -273,6 +330,19 @@ static struct at91_pinctrl_mux_ops sama5d3_ops = {
.set_drivestrength = at91_mux_sama5d3_set_drivestrength,
};
+static struct at91_pinctrl_mux_ops sam9x60_ops = {
+ .mux_A_periph = at91_mux_pio3_set_A_periph,
+ .mux_B_periph = at91_mux_pio3_set_B_periph,
+ .mux_C_periph = at91_mux_pio3_set_C_periph,
+ .mux_D_periph = at91_mux_pio3_set_D_periph,
+ .set_deglitch = at91_mux_pio3_set_deglitch,
+ .set_debounce = at91_mux_pio3_set_debounce,
+ .set_pulldown = at91_mux_pio3_set_pulldown,
+ .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig,
+ .set_drivestrength = at91_mux_sam9x60_set_drivestrength,
+ .set_slewrate = at91_mux_sam9x60_set_slewrate,
+};
+
static void at91_mux_gpio_disable(struct at91_port *pio, u32 mask)
{
writel(mask, &pio->pdr);
@@ -339,6 +409,9 @@ static int at91_pinconf_set(struct at91_pinctrl_mux_ops *ops,
if (ops->set_drivestrength)
ops->set_drivestrength(pio, pin,
(config & DRIVE_STRENGTH) >> DRIVE_STRENGTH_SHIFT);
+ if (ops->set_slewrate)
+ ops->set_slewrate(pio, pin,
+ (config & SLEWRATE) >> SLEWRATE_SHIFT);
return 0;
}
@@ -440,6 +513,7 @@ static const struct udevice_id at91_pinctrl_match[] = {
{ .compatible = "atmel,sama5d3-pinctrl", .data = (ulong)&sama5d3_ops },
{ .compatible = "atmel,at91sam9x5-pinctrl", .data = (ulong)&at91sam9x5_ops },
{ .compatible = "atmel,at91rm9200-pinctrl", .data = (ulong)&at91rm9200_ops },
+ { .compatible = "microchip,sam9x60-pinctrl", .data = (ulong)&sam9x60_ops },
{}
};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 887cd68..fcbb0a8 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -508,6 +508,15 @@ config ATMEL_USART
configured in the device tree, and input clock frequency can
be got from the clk node.
+config SPL_UART_CLOCK
+ int "SPL fixed UART input clock"
+ depends on ATMEL_USART && SPL && !SPL_CLK
+ default 132096000 if ARCH_AT91
+ help
+ Provide a fixed clock value as input to the UART controller. This
+ might be needed on platforms which can't enable CONFIG_SPL_CLK
+ because of SPL image size restrictions.
+
config BCM283X_MU_SERIAL
bool "Support for BCM283x Mini-UART"
depends on DM_SERIAL && ARCH_BCM283X
diff --git a/drivers/serial/atmel_usart.c b/drivers/serial/atmel_usart.c
index aa8cdff..c450a4e 100644
--- a/drivers/serial/atmel_usart.c
+++ b/drivers/serial/atmel_usart.c
@@ -218,6 +218,17 @@ static const struct dm_serial_ops atmel_serial_ops = {
.setbrg = atmel_serial_setbrg,
};
+#if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_CLK)
+static int atmel_serial_enable_clk(struct udevice *dev)
+{
+ struct atmel_serial_priv *priv = dev_get_priv(dev);
+
+ /* Use fixed clock value in SPL */
+ priv->usart_clk_rate = CONFIG_SPL_UART_CLOCK;
+
+ return 0;
+}
+#else
static int atmel_serial_enable_clk(struct udevice *dev)
{
struct atmel_serial_priv *priv = dev_get_priv(dev);
@@ -245,6 +256,7 @@ static int atmel_serial_enable_clk(struct udevice *dev)
return 0;
}
+#endif
static int atmel_serial_probe(struct udevice *dev)
{
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 115fc45..34e78be 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -139,10 +139,6 @@ config WDT_AT91
Select this to enable Microchip watchdog timer, which can be found on
some AT91 devices.
-config AT91_HW_WDT_TIMEOUT
- bool "AT91 watchdog timeout specified"
- depends on WDT_AT91
-
config WDT_MT7621
bool "MediaTek MT7621 watchdog timer support"
depends on WDT && ARCH_MT7620
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 13f8772..000769d 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -17,6 +17,7 @@
#include <asm/io.h>
#include <asm/arch/at91_wdt.h>
#include <common.h>
+#include <div64.h>
#include <dm.h>
#include <errno.h>
#include <wdt.h>
@@ -30,28 +31,21 @@ DECLARE_GLOBAL_DATA_PTR;
*/
#define WDT_SEC2TICKS(s) (((s) << 8) - 1)
-/* Hardware timeout in seconds */
-#define WDT_MAX_TIMEOUT 16
-#define WDT_MIN_TIMEOUT 0
-#define WDT_DEFAULT_TIMEOUT 2
-
-struct at91_wdt_priv {
- void __iomem *regs;
- u32 regval;
- u32 timeout;
-};
-
/*
* Set the watchdog time interval in 1/256Hz (write-once)
* Counter is 12 bit.
*/
-static int at91_wdt_start(struct udevice *dev, u64 timeout_s, ulong flags)
+static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
{
struct at91_wdt_priv *priv = dev_get_priv(dev);
- u32 timeout = WDT_SEC2TICKS(timeout_s);
+ u64 timeout;
+ u32 ticks;
- if (timeout_s > WDT_MAX_TIMEOUT || timeout_s < WDT_MIN_TIMEOUT)
- timeout = priv->timeout;
+ /* Calculate timeout in seconds and the resulting ticks */
+ timeout = timeout_ms;
+ do_div(timeout, 1000);
+ timeout = min_t(u64, timeout, WDT_MAX_TIMEOUT);
+ ticks = WDT_SEC2TICKS(timeout);
/* Check if disabled */
if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
@@ -65,12 +59,10 @@ static int at91_wdt_start(struct udevice *dev, u64 timeout_s, ulong flags)
* Since WDV is a 12-bit counter, the maximum period is
* 4096 / 256 = 16 seconds.
*/
-
priv->regval = AT91_WDT_MR_WDRSTEN /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff) /* restart at any time */
- | AT91_WDT_MR_WDV(timeout); /* timer value */
-
+ | AT91_WDT_MR_WDV(ticks); /* timer value */
writel(priv->regval, priv->regs + AT91_WDT_MR);
return 0;
@@ -115,10 +107,12 @@ static int at91_wdt_probe(struct udevice *dev)
if (!priv->regs)
return -EINVAL;
-#ifdef CONFIG_AT91_HW_WDT_TIMEOUT
+#if CONFIG_IS_ENABLED(OF_CONTROL)
priv->timeout = dev_read_u32_default(dev, "timeout-sec",
WDT_DEFAULT_TIMEOUT);
debug("%s: timeout %d", __func__, priv->timeout);
+#else
+ priv->timeout = WDT_DEFAULT_TIMEOUT;
#endif
debug("%s: Probing wdt%u\n", __func__, dev->seq);
diff --git a/env/ext4.c b/env/ext4.c
index 09c5e4a..388474a 100644
--- a/env/ext4.c
+++ b/env/ext4.c
@@ -60,7 +60,7 @@ static int env_ext4_save(void)
}
err = ext4fs_write(CONFIG_ENV_EXT4_FILE, (void *)&env_new,
- sizeof(env_t));
+ sizeof(env_t), FILETYPE_REG);
ext4fs_close();
if (err == -1) {
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
index 67e2471..464c33d 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -190,7 +190,7 @@ uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n)
return res;
}
-void put_ext4(uint64_t off, void *buf, uint32_t size)
+void put_ext4(uint64_t off, const void *buf, uint32_t size)
{
uint64_t startblock;
uint64_t remainder;
@@ -510,7 +510,8 @@ restart:
restart_read:
/* read the block no allocated to a file */
- first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx);
+ first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx,
+ NULL);
if (first_block_no_of_root <= 0)
goto fail;
@@ -607,7 +608,7 @@ restart_read:
dir->direntlen = cpu_to_le16(fs->blksz - totalbytes);
dir->namelen = strlen(filename);
- dir->filetype = FILETYPE_REG; /* regular file */
+ dir->filetype = file_type;
temp_dir = (char *)dir;
temp_dir = temp_dir + sizeof(struct ext2_dirent);
memcpy(temp_dir, filename, strlen(filename));
@@ -646,7 +647,7 @@ static int search_dir(struct ext2_inode *parent_inode, char *dirname)
/* get the block no allocated to a file */
for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
- blknr = read_allocated_block(parent_inode, blk_idx);
+ blknr = read_allocated_block(parent_inode, blk_idx, NULL);
if (blknr <= 0)
goto fail;
@@ -943,7 +944,7 @@ int ext4fs_filename_unlink(char *filename)
/* read the block no allocated to a file */
for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
- blknr = read_allocated_block(g_parent_inode, blk_idx);
+ blknr = read_allocated_block(g_parent_inode, blk_idx, NULL);
if (blknr <= 0)
break;
inodeno = unlink_filename(filename, blknr);
@@ -1522,7 +1523,7 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
#endif
static struct ext4_extent_header *ext4fs_get_extent_block
- (struct ext2_data *data, char *buf,
+ (struct ext2_data *data, struct ext_block_cache *cache,
struct ext4_extent_header *ext_block,
uint32_t fileblock, int log2_blksz)
{
@@ -1546,17 +1547,19 @@ static struct ext4_extent_header *ext4fs_get_extent_block
break;
} while (fileblock >= le32_to_cpu(index[i].ei_block));
- if (--i < 0)
- return NULL;
+ /*
+ * If first logical block number is higher than requested fileblock,
+ * it is a sparse file. This is handled on upper layer.
+ */
+ if (i > 0)
+ i--;
block = le16_to_cpu(index[i].ei_leaf_hi);
block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
-
- if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz,
- buf))
- ext_block = (struct ext4_extent_header *)buf;
- else
+ block <<= log2_blksz;
+ if (!ext_cache_read(cache, (lbaint_t)block, blksz))
return NULL;
+ ext_block = (struct ext4_extent_header *)cache->buf;
}
}
@@ -1584,7 +1587,7 @@ static int ext4fs_blockgroup
int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
{
- struct ext2_block_group blkgrp;
+ struct ext2_block_group *blkgrp;
struct ext2_sblock *sblock = &data->sblock;
struct ext_filesystem *fs = get_fs();
int log2blksz = get_fs()->dev_desc->log2blksz;
@@ -1592,17 +1595,28 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
long int blkno;
unsigned int blkoff;
+ /* Allocate blkgrp based on gdsize (for 64-bit support). */
+ blkgrp = zalloc(get_fs()->gdsize);
+ if (!blkgrp)
+ return 0;
+
/* It is easier to calculate if the first inode is 0. */
ino--;
status = ext4fs_blockgroup(data, ino / le32_to_cpu
- (sblock->inodes_per_group), &blkgrp);
- if (status == 0)
+ (sblock->inodes_per_group), blkgrp);
+ if (status == 0) {
+ free(blkgrp);
return 0;
+ }
inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
- blkno = ext4fs_bg_get_inode_table_id(&blkgrp, fs) +
+ blkno = ext4fs_bg_get_inode_table_id(blkgrp, fs) +
(ino % le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
blkoff = (ino % inodes_per_block) * fs->inodesz;
+
+ /* Free blkgrp as it is no longer required. */
+ free(blkgrp);
+
/* Read the inode. */
status = ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) -
log2blksz), blkoff,
@@ -1613,7 +1627,8 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
return 1;
}
-long int read_allocated_block(struct ext2_inode *inode, int fileblock)
+long int read_allocated_block(struct ext2_inode *inode, int fileblock,
+ struct ext_block_cache *cache)
{
long int blknr;
int blksz;
@@ -1630,20 +1645,26 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
long int startblock, endblock;
- char *buf = zalloc(blksz);
- if (!buf)
- return -ENOMEM;
+ struct ext_block_cache *c, cd;
struct ext4_extent_header *ext_block;
struct ext4_extent *extent;
int i;
+
+ if (cache) {
+ c = cache;
+ } else {
+ c = &cd;
+ ext_cache_init(c);
+ }
ext_block =
- ext4fs_get_extent_block(ext4fs_root, buf,
+ ext4fs_get_extent_block(ext4fs_root, c,
(struct ext4_extent_header *)
inode->b.blocks.dir_blocks,
fileblock, log2_blksz);
if (!ext_block) {
printf("invalid extent block\n");
- free(buf);
+ if (!cache)
+ ext_cache_fini(c);
return -EINVAL;
}
@@ -1655,19 +1676,22 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
if (startblock > fileblock) {
/* Sparse file */
- free(buf);
+ if (!cache)
+ ext_cache_fini(c);
return 0;
} else if (fileblock < endblock) {
start = le16_to_cpu(extent[i].ee_start_hi);
start = (start << 32) +
le32_to_cpu(extent[i].ee_start_lo);
- free(buf);
+ if (!cache)
+ ext_cache_fini(c);
return (fileblock - startblock) + start;
}
}
- free(buf);
+ if (!cache)
+ ext_cache_fini(c);
return 0;
}
diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h
index 1ee81ab..4dff191 100644
--- a/fs/ext4/ext4_common.h
+++ b/fs/ext4/ext4_common.h
@@ -72,7 +72,7 @@ int ext4fs_iget(int inode_no, struct ext2_inode *inode);
void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
unsigned int total_remaining_blocks,
unsigned int *total_no_of_block);
-void put_ext4(uint64_t off, void *buf, uint32_t size);
+void put_ext4(uint64_t off, const void *buf, uint32_t size);
struct ext2_block_group *ext4fs_get_group_descriptor
(const struct ext_filesystem *fs, uint32_t bg_idx);
uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg,
diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c
index 148593d..6adbab9 100644
--- a/fs/ext4/ext4_journal.c
+++ b/fs/ext4/ext4_journal.c
@@ -347,7 +347,7 @@ void recover_transaction(int prev_desc_logical_no)
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
(struct ext2_inode *)&inode_journal);
blknr = read_allocated_block((struct ext2_inode *)
- &inode_journal, i);
+ &inode_journal, i, NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
p_jdb = (char *)temp_buff;
@@ -372,7 +372,7 @@ void recover_transaction(int prev_desc_logical_no)
be32_to_cpu(jdb->h_sequence)) == 0)
continue;
}
- blknr = read_allocated_block(&inode_journal, i);
+ blknr = read_allocated_block(&inode_journal, i, NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
fs->blksz, metadata_buff);
put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz),
@@ -419,7 +419,8 @@ int ext4fs_check_journal_state(int recovery_flag)
}
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
- blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK);
+ blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK,
+ NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *) temp_buff;
@@ -443,7 +444,7 @@ int ext4fs_check_journal_state(int recovery_flag)
i = be32_to_cpu(jsb->s_first);
while (1) {
- blknr = read_allocated_block(&inode_journal, i);
+ blknr = read_allocated_block(&inode_journal, i, NULL);
memset(temp_buff1, '\0', fs->blksz);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
0, fs->blksz, temp_buff1);
@@ -537,7 +538,7 @@ end:
ext4_read_superblock((char *)fs->sb);
blknr = read_allocated_block(&inode_journal,
- EXT2_JOURNAL_SUPERBLOCK);
+ EXT2_JOURNAL_SUPERBLOCK, NULL);
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
(struct journal_superblock_t *)temp_buff,
(uint32_t) fs->blksz);
@@ -566,7 +567,7 @@ static void update_descriptor_block(long int blknr)
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
jsb_blknr = read_allocated_block(&inode_journal,
- EXT2_JOURNAL_SUPERBLOCK);
+ EXT2_JOURNAL_SUPERBLOCK, NULL);
ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *) temp_buff;
@@ -618,7 +619,7 @@ static void update_commit_block(long int blknr)
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
&inode_journal);
jsb_blknr = read_allocated_block(&inode_journal,
- EXT2_JOURNAL_SUPERBLOCK);
+ EXT2_JOURNAL_SUPERBLOCK, NULL);
ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *) temp_buff;
@@ -645,16 +646,17 @@ void ext4fs_update_journal(void)
long int blknr;
int i;
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
- blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
+ blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
update_descriptor_block(blknr);
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
if (journal_ptr[i]->blknr == -1)
break;
- blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
+ blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++,
+ NULL);
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
journal_ptr[i]->buf, fs->blksz);
}
- blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
+ blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
update_commit_block(blknr);
printf("update journal finished\n");
}
diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
index 4eb77c3..504d23a 100644
--- a/fs/ext4/ext4_write.c
+++ b/fs/ext4/ext4_write.c
@@ -465,6 +465,15 @@ static int ext4fs_delete_file(int inodeno)
if (le32_to_cpu(inode.size) % fs->blksz)
no_blocks++;
+ /*
+ * special case for symlinks whose target are small enough that
+ *it fits in struct ext2_inode.b.symlink: no block had been allocated
+ */
+ if ((le16_to_cpu(inode.mode) & S_IFLNK) &&
+ le32_to_cpu(inode.size) <= sizeof(inode.b.symlink)) {
+ no_blocks = 0;
+ }
+
if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
/* FIXME delete extent index blocks, i.e. eh_depth >= 1 */
struct ext4_extent_header *eh =
@@ -479,7 +488,7 @@ static int ext4fs_delete_file(int inodeno)
/* release data blocks */
for (i = 0; i < no_blocks; i++) {
- blknr = read_allocated_block(&inode, i);
+ blknr = read_allocated_block(&inode, i, NULL);
if (blknr == 0)
continue;
if (blknr < 0)
@@ -695,7 +704,7 @@ void ext4fs_deinit(void)
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
&inode_journal);
blknr = read_allocated_block(&inode_journal,
- EXT2_JOURNAL_SUPERBLOCK);
+ EXT2_JOURNAL_SUPERBLOCK, NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *)temp_buff;
@@ -752,7 +761,7 @@ void ext4fs_deinit(void)
* contigous sectors as ext4fs_read_file
*/
static int ext4fs_write_file(struct ext2_inode *file_inode,
- int pos, unsigned int len, char *buf)
+ int pos, unsigned int len, const char *buf)
{
int i;
int blockcnt;
@@ -764,7 +773,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
int delayed_start = 0;
int delayed_extent = 0;
int delayed_next = 0;
- char *delayed_buf = NULL;
+ const char *delayed_buf = NULL;
/* Adjust len so it we can't read past the end of the file. */
if (len > filesize)
@@ -776,7 +785,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
long int blknr;
int blockend = fs->blksz;
int skipfirst = 0;
- blknr = read_allocated_block(file_inode, i);
+ blknr = read_allocated_block(file_inode, i, NULL);
if (blknr <= 0)
return -1;
@@ -816,7 +825,6 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
(uint32_t) delayed_extent);
previous_block_number = -1;
}
- memset(buf, 0, fs->blksz - skipfirst);
}
buf += fs->blksz - skipfirst;
}
@@ -830,8 +838,8 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
return len;
}
-int ext4fs_write(const char *fname, unsigned char *buffer,
- unsigned long sizebytes)
+int ext4fs_write(const char *fname, const char *buffer,
+ unsigned long sizebytes, int type)
{
int ret = 0;
struct ext2_inode *file_inode = NULL;
@@ -854,8 +862,12 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
struct ext2_block_group *bgd = NULL;
struct ext_filesystem *fs = get_fs();
ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
+ bool store_link_in_inode = false;
memset(filename, 0x00, 256);
+ if (type != FILETYPE_REG && type != FILETYPE_SYMLINK)
+ return -1;
+
g_parent_inode = zalloc(fs->inodesz);
if (!g_parent_inode)
goto fail;
@@ -893,8 +905,16 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
if (ret)
goto fail;
}
- /* calucalate how many blocks required */
- bytes_reqd_for_file = sizebytes;
+
+ /* calculate how many blocks required */
+ if (type == FILETYPE_SYMLINK &&
+ sizebytes <= sizeof(file_inode->b.symlink)) {
+ store_link_in_inode = true;
+ bytes_reqd_for_file = 0;
+ } else {
+ bytes_reqd_for_file = sizebytes;
+ }
+
blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
blks_reqd_for_file++;
@@ -907,7 +927,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
goto fail;
}
- inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG);
+ inodeno = ext4fs_update_parent_dentry(filename, type);
if (inodeno == -1)
goto fail;
/* prepare file inode */
@@ -915,14 +935,23 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
if (!inode_buffer)
goto fail;
file_inode = (struct ext2_inode *)inode_buffer;
- file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU |
- S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
+ file_inode->size = cpu_to_le32(sizebytes);
+ if (type == FILETYPE_SYMLINK) {
+ file_inode->mode = cpu_to_le16(S_IFLNK | S_IRWXU | S_IRWXG |
+ S_IRWXO);
+ if (store_link_in_inode) {
+ strncpy(file_inode->b.symlink, buffer, sizebytes);
+ sizebytes = 0;
+ }
+ } else {
+ file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | S_IRGRP |
+ S_IROTH | S_IXGRP | S_IXOTH);
+ }
/* ToDo: Update correct time */
file_inode->mtime = cpu_to_le32(timestamp);
file_inode->atime = cpu_to_le32(timestamp);
file_inode->ctime = cpu_to_le32(timestamp);
file_inode->nlinks = cpu_to_le16(1);
- file_inode->size = cpu_to_le32(sizebytes);
/* Allocate data blocks */
ext4fs_allocate_blocks(file_inode, blocks_remaining,
@@ -949,7 +978,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
if (ext4fs_put_metadata(temp_ptr, itable_blkno))
goto fail;
/* copy the file content into data blocks */
- if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
+ if (ext4fs_write_file(file_inode, 0, sizebytes, buffer) == -1) {
printf("Error in copying content\n");
/* FIXME: Deallocate data blocks */
goto fail;
@@ -1014,7 +1043,7 @@ int ext4_write_file(const char *filename, void *buf, loff_t offset,
return -1;
}
- ret = ext4fs_write(filename, buf, len);
+ ret = ext4fs_write(filename, buf, len, FILETYPE_REG);
if (ret) {
printf("** Error ext4fs_write() **\n");
goto fail;
@@ -1029,3 +1058,8 @@ fail:
return -1;
}
+
+int ext4fs_create_link(const char *target, const char *fname)
+{
+ return ext4fs_write(fname, target, strlen(target), FILETYPE_SYMLINK);
+}
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
index 2a28031..26db677 100644
--- a/fs/ext4/ext4fs.c
+++ b/fs/ext4/ext4fs.c
@@ -62,6 +62,9 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
lbaint_t delayed_next = 0;
char *delayed_buf = NULL;
short status;
+ struct ext_block_cache cache;
+
+ ext_cache_init(&cache);
if (blocksize <= 0)
return -1;
@@ -77,9 +80,11 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
int blockoff = pos - (blocksize * i);
int blockend = blocksize;
int skipfirst = 0;
- blknr = read_allocated_block(&(node->inode), i);
- if (blknr < 0)
+ blknr = read_allocated_block(&node->inode, i, &cache);
+ if (blknr < 0) {
+ ext_cache_fini(&cache);
return -1;
+ }
blknr = blknr << log2_fs_blocksize;
@@ -109,8 +114,10 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
delayed_skipfirst,
delayed_extent,
delayed_buf);
- if (status == 0)
+ if (status == 0) {
+ ext_cache_fini(&cache);
return -1;
+ }
previous_block_number = blknr;
delayed_start = blknr;
delayed_extent = blockend;
@@ -136,8 +143,10 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
delayed_skipfirst,
delayed_extent,
delayed_buf);
- if (status == 0)
+ if (status == 0) {
+ ext_cache_fini(&cache);
return -1;
+ }
previous_block_number = -1;
}
/* Zero no more than `len' bytes. */
@@ -153,12 +162,15 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
status = ext4fs_devread(delayed_start,
delayed_skipfirst, delayed_extent,
delayed_buf);
- if (status == 0)
+ if (status == 0) {
+ ext_cache_fini(&cache);
return -1;
+ }
previous_block_number = -1;
}
*actread = len;
+ ext_cache_fini(&cache);
return 0;
}
@@ -252,3 +264,32 @@ int ext4fs_uuid(char *uuid_str)
return -ENOSYS;
#endif
}
+
+void ext_cache_init(struct ext_block_cache *cache)
+{
+ memset(cache, 0, sizeof(*cache));
+}
+
+void ext_cache_fini(struct ext_block_cache *cache)
+{
+ free(cache->buf);
+ ext_cache_init(cache);
+}
+
+int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size)
+{
+ /* This could be more lenient, but this is simple and enough for now */
+ if (cache->buf && cache->block == block && cache->size == size)
+ return 1;
+ ext_cache_fini(cache);
+ cache->buf = malloc(size);
+ if (!cache->buf)
+ return 0;
+ if (!ext4fs_devread(block, 0, size, cache->buf)) {
+ free(cache->buf);
+ return 0;
+ }
+ cache->block = block;
+ cache->size = size;
+ return 1;
+}
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 6ade4ea..c5997c2 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -602,8 +602,13 @@ static int get_fs_info(fsdata *mydata)
mydata->data_begin = mydata->rootdir_sect +
mydata->rootdir_size -
(mydata->clust_size * 2);
- mydata->root_cluster =
- sect_to_clust(mydata, mydata->rootdir_sect);
+
+ /*
+ * The root directory is not cluster-aligned and may be on a
+ * "negative" cluster, this will be handled specially in
+ * next_cluster().
+ */
+ mydata->root_cluster = 0;
}
mydata->fatbufnum = -1;
@@ -733,20 +738,38 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent)
itr->last_cluster = 0;
}
-static void *next_cluster(fat_itr *itr)
+static void *next_cluster(fat_itr *itr, unsigned *nbytes)
{
fsdata *mydata = itr->fsdata; /* for silly macros */
int ret;
u32 sect;
+ u32 read_size;
/* have we reached the end? */
if (itr->last_cluster)
return NULL;
- sect = clust_to_sect(itr->fsdata, itr->next_clust);
+ if (itr->is_root && itr->fsdata->fatsize != 32) {
+ /*
+ * The root directory is located before the data area and
+ * cannot be indexed using the regular unsigned cluster
+ * numbers (it may start at a "negative" cluster or not at a
+ * cluster boundary at all), so consider itr->next_clust to be
+ * a offset in cluster-sized units from the start of rootdir.
+ */
+ unsigned sect_offset = itr->next_clust * itr->fsdata->clust_size;
+ unsigned remaining_sects = itr->fsdata->rootdir_size - sect_offset;
+ sect = itr->fsdata->rootdir_sect + sect_offset;
+ /* do not read past the end of rootdir */
+ read_size = min_t(u32, itr->fsdata->clust_size,
+ remaining_sects);
+ } else {
+ sect = clust_to_sect(itr->fsdata, itr->next_clust);
+ read_size = itr->fsdata->clust_size;
+ }
- debug("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n",
- sect, itr->fsdata->clust_size, DIRENTSPERBLOCK);
+ debug("FAT read(sect=%d), clust_size=%d, read_size=%u, DIRENTSPERBLOCK=%zd\n",
+ sect, itr->fsdata->clust_size, read_size, DIRENTSPERBLOCK);
/*
* NOTE: do_fat_read_at() had complicated logic to deal w/
@@ -757,18 +780,17 @@ static void *next_cluster(fat_itr *itr)
* dent at a time and iteratively constructing the vfat long
* name.
*/
- ret = disk_read(sect, itr->fsdata->clust_size,
- itr->block);
+ ret = disk_read(sect, read_size, itr->block);
if (ret < 0) {
debug("Error: reading block\n");
return NULL;
}
+ *nbytes = read_size * itr->fsdata->sect_size;
itr->clust = itr->next_clust;
if (itr->is_root && itr->fsdata->fatsize != 32) {
itr->next_clust++;
- sect = clust_to_sect(itr->fsdata, itr->next_clust);
- if (sect - itr->fsdata->rootdir_sect >=
+ if (itr->next_clust * itr->fsdata->clust_size >=
itr->fsdata->rootdir_size) {
debug("nextclust: 0x%x\n", itr->next_clust);
itr->last_cluster = 1;
@@ -787,9 +809,8 @@ static void *next_cluster(fat_itr *itr)
static dir_entry *next_dent(fat_itr *itr)
{
if (itr->remaining == 0) {
- struct dir_entry *dent = next_cluster(itr);
- unsigned nbytes = itr->fsdata->sect_size *
- itr->fsdata->clust_size;
+ unsigned nbytes;
+ struct dir_entry *dent = next_cluster(itr, &nbytes);
/* have we reached the last cluster? */
if (!dent) {
diff --git a/fs/fs.c b/fs/fs.c
index c5c35eb..736ebef 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -90,6 +90,11 @@ static inline int fs_write_unsupported(const char *filename, void *buf,
return -1;
}
+static inline int fs_ln_unsupported(const char *filename, const char *target)
+{
+ return -1;
+}
+
static inline void fs_close_unsupported(void)
{
}
@@ -154,6 +159,7 @@ struct fstype_info {
void (*closedir)(struct fs_dir_stream *dirs);
int (*unlink)(const char *filename);
int (*mkdir)(const char *dirname);
+ int (*ln)(const char *filename, const char *target);
};
static struct fstype_info fstypes[] = {
@@ -181,6 +187,7 @@ static struct fstype_info fstypes[] = {
.opendir = fat_opendir,
.readdir = fat_readdir,
.closedir = fat_closedir,
+ .ln = fs_ln_unsupported,
},
#endif
@@ -197,8 +204,10 @@ static struct fstype_info fstypes[] = {
.read = ext4_read_file,
#ifdef CONFIG_CMD_EXT4_WRITE
.write = ext4_write_file,
+ .ln = ext4fs_create_link,
#else
.write = fs_write_unsupported,
+ .ln = fs_ln_unsupported,
#endif
.uuid = ext4fs_uuid,
.opendir = fs_opendir_unsupported,
@@ -222,6 +231,7 @@ static struct fstype_info fstypes[] = {
.opendir = fs_opendir_unsupported,
.unlink = fs_unlink_unsupported,
.mkdir = fs_mkdir_unsupported,
+ .ln = fs_ln_unsupported,
},
#endif
#ifdef CONFIG_CMD_UBIFS
@@ -240,6 +250,7 @@ static struct fstype_info fstypes[] = {
.opendir = fs_opendir_unsupported,
.unlink = fs_unlink_unsupported,
.mkdir = fs_mkdir_unsupported,
+ .ln = fs_ln_unsupported,
},
#endif
#ifdef CONFIG_FS_BTRFS
@@ -258,6 +269,7 @@ static struct fstype_info fstypes[] = {
.opendir = fs_opendir_unsupported,
.unlink = fs_unlink_unsupported,
.mkdir = fs_mkdir_unsupported,
+ .ln = fs_ln_unsupported,
},
#endif
{
@@ -275,6 +287,7 @@ static struct fstype_info fstypes[] = {
.opendir = fs_opendir_unsupported,
.unlink = fs_unlink_unsupported,
.mkdir = fs_mkdir_unsupported,
+ .ln = fs_ln_unsupported,
},
};
@@ -602,6 +615,22 @@ int fs_mkdir(const char *dirname)
return ret;
}
+int fs_ln(const char *fname, const char *target)
+{
+ struct fstype_info *info = fs_get_info(fs_type);
+ int ret;
+
+ ret = info->ln(fname, target);
+
+ if (ret < 0) {
+ printf("** Unable to create link %s -> %s **\n", fname, target);
+ ret = -1;
+ }
+ fs_close();
+
+ return ret;
+}
+
int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype)
{
@@ -840,3 +869,18 @@ int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
return 0;
}
+
+int do_ln(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+ int fstype)
+{
+ if (argc != 5)
+ return CMD_RET_USAGE;
+
+ if (fs_set_blk_dev(argv[1], argv[2], fstype))
+ return 1;
+
+ if (fs_ln(argv[3], argv[4]))
+ return 1;
+
+ return 0;
+}
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index bad0c67..5f6e127 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -167,7 +167,7 @@ struct ubifs_global_debug_info {
#else
#define ubifs_assert(expr) do { \
if (unlikely(!(expr))) { \
- pr_crit("UBIFS assert failed in %s at %u\n", \
+ pr_debug("UBIFS assert failed in %s at %u\n", \
__func__, __LINE__); \
dump_stack(); \
} \
@@ -176,7 +176,7 @@ struct ubifs_global_debug_info {
#define ubifs_assert_cmt_locked(c) do { \
if (unlikely(down_write_trylock(&(c)->commit_sem))) { \
up_write(&(c)->commit_sem); \
- pr_crit("commit lock is not locked!\n"); \
+ pr_debug("commit lock is not locked!\n"); \
ubifs_assert(0); \
} \
} while (0)
diff --git a/include/configs/corvus.h b/include/configs/corvus.h
index 5dd5c28..749a67d 100644
--- a/include/configs/corvus.h
+++ b/include/configs/corvus.h
@@ -139,4 +139,7 @@
#define CONFIG_SYS_MCKR 0x1301
#define CONFIG_SYS_MCKR_CSS 0x1302
+#define CONFIG_SPL_PAD_TO CONFIG_SYS_NAND_U_BOOT_OFFS
+#define CONFIG_SYS_SPL_LEN CONFIG_SPL_PAD_TO
+
#endif
diff --git a/include/configs/gardena-smart-gateway-at91sam.h b/include/configs/gardena-smart-gateway-at91sam.h
new file mode 100644
index 0000000..e9a06e6
--- /dev/null
+++ b/include/configs/gardena-smart-gateway-at91sam.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2012 Atmel Corporation
+ * Copyright (C) 2019 Stefan Roese <sr@denx.de>
+ *
+ * Configuation settings for the GARDENA smart Gateway (AT91SAM9G25)
+ */
+
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+/* ARM asynchronous clock */
+#define CONFIG_SYS_AT91_SLOW_CLOCK 32768
+#define CONFIG_SYS_AT91_MAIN_CLOCK 12000000 /* 12 MHz crystal */
+
+#ifndef CONFIG_SPL_BUILD
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#endif
+#define CONFIG_SKIP_LOWLEVEL_INIT_ONLY
+
+/* general purpose I/O */
+#define CONFIG_ATMEL_LEGACY /* required until (g)pio is fixed */
+
+/* SDRAM */
+#define CONFIG_SYS_SDRAM_BASE 0x20000000
+#define CONFIG_SYS_SDRAM_SIZE 0x08000000 /* 128 megs */
+
+#define CONFIG_SYS_INIT_SP_ADDR \
+ (CONFIG_SYS_SDRAM_BASE + 16 * 1024 - GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_MALLOC_LEN (16 * 1024 * 1024)
+
+/* NAND flash */
+#define CONFIG_SYS_MAX_NAND_DEVICE 1
+#define CONFIG_SYS_NAND_BASE 0x40000000
+#define CONFIG_SYS_NAND_DBW_8 1
+/* our ALE is AD21 */
+#define CONFIG_SYS_NAND_MASK_ALE BIT(21)
+/* our CLE is AD22 */
+#define CONFIG_SYS_NAND_MASK_CLE BIT(22)
+#define CONFIG_SYS_NAND_ENABLE_PIN AT91_PIN_PD4
+#define CONFIG_SYS_NAND_READY_PIN AT91_PIN_PD5
+
+#define CONFIG_SYS_LOAD_ADDR 0x22000000 /* load address */
+
+/* environment organization */
+#define CONFIG_ENV_UBI_PART "ubi"
+#define CONFIG_ENV_UBI_VOLUME "env"
+#define CONFIG_ENV_UBI_VOLUME_REDUND "env_r"
+#define CONFIG_ENV_SIZE (64 << 10)
+
+/* SPL */
+#define CONFIG_SPL_TEXT_BASE 0x300000
+#define CONFIG_SPL_MAX_SIZE 0x7000
+#define CONFIG_SPL_STACK 0x308000
+
+#define CONFIG_SPL_BSS_START_ADDR 0x20000000
+#define CONFIG_SPL_BSS_MAX_SIZE 0x80000
+#define CONFIG_SYS_SPL_MALLOC_START 0x20080000
+#define CONFIG_SYS_SPL_MALLOC_SIZE 0x80000
+
+#define CONFIG_SYS_MONITOR_LEN (512 << 10)
+
+#define CONFIG_SYS_MASTER_CLOCK 132096000
+#define CONFIG_SYS_AT91_PLLA 0x20c73f03
+#define CONFIG_SYS_MCKR 0x1301
+#define CONFIG_SYS_MCKR_CSS 0x1302
+
+#define CONFIG_SPL_NAND_DRIVERS
+#define CONFIG_SPL_NAND_BASE
+#define CONFIG_SPL_NAND_RAW_ONLY
+#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x40000
+#define CONFIG_SYS_NAND_U_BOOT_SIZE 0xa0000
+#define CONFIG_SYS_UBOOT_START CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_NAND_U_BOOT_DST CONFIG_SYS_TEXT_BASE
+
+#define CONFIG_SYS_NAND_5_ADDR_CYCLE
+#define CONFIG_SYS_NAND_PAGE_SIZE 0x800
+#define CONFIG_SYS_NAND_PAGE_COUNT 64
+#define CONFIG_SYS_NAND_OOBSIZE 64
+#define CONFIG_SYS_NAND_BLOCK_SIZE 0x20000
+#define CONFIG_SYS_NAND_BAD_BLOCK_POS 0x0
+
+#define CONFIG_SPL_PAD_TO CONFIG_SYS_NAND_U_BOOT_OFFS
+#define CONFIG_SYS_SPL_LEN CONFIG_SPL_PAD_TO
+
+#endif
diff --git a/include/configs/pm9g45.h b/include/configs/pm9g45.h
index 46b8030..e34873c 100644
--- a/include/configs/pm9g45.h
+++ b/include/configs/pm9g45.h
@@ -15,110 +15,119 @@
#ifndef __CONFIG_H
#define __CONFIG_H
-/*
- * SoC must be defined first, before hardware.h is included.
- * In this case SoC is defined in boards.cfg.
- */
-#include <asm/hardware.h>
-
-#define CONFIG_SYS_AT91_CPU_NAME "AT91SAM9G45"
-
-#define CONFIG_MACH_TYPE MACH_TYPE_PM9G45
-
/* ARM asynchronous clock */
-#define CONFIG_SYS_AT91_MAIN_CLOCK 12000000 /* from 12 MHz crystal */
-#define CONFIG_SYS_AT91_SLOW_CLOCK 32768 /* slow clock xtal */
-
-#define CONFIG_ARCH_CPU_INIT
-
-#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */
-#define CONFIG_SETUP_MEMORY_TAGS 1
-#define CONFIG_INITRD_TAG 1
+#define CONFIG_SYS_AT91_SLOW_CLOCK 32768
+#define CONFIG_SYS_AT91_MAIN_CLOCK 12000000 /* from 12 MHz crystal */
+#define CONFIG_CMDLINE_TAG /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+#define CONFIG_INITRD_TAG
#define CONFIG_SKIP_LOWLEVEL_INIT
-/*
- * Hardware drivers
- */
-#define CONFIG_AT91_GPIO 1
-#define CONFIG_ATMEL_USART 1
-#define CONFIG_USART_BASE ATMEL_BASE_DBGU
-#define CONFIG_USART_ID ATMEL_ID_SYS
-
-#define CONFIG_SYS_USE_NANDFLASH 1
-
-/* LED */
-#define CONFIG_AT91_LED
-#define CONFIG_RED_LED GPIO_PIN_PD(31) /* this is the user1 led */
-#define CONFIG_GREEN_LED GPIO_PIN_PD(0) /* this is the user2 led */
-
+/* general purpose I/O */
+#define CONFIG_ATMEL_LEGACY /* required until (g)pio is fixed */
/*
* BOOTP options
*/
-#define CONFIG_BOOTP_BOOTFILESIZE 1
-
-#define CONFIG_JFFS2_CMDLINE 1
-#define CONFIG_JFFS2_NAND 1
-#define CONFIG_JFFS2_DEV "nand0" /* NAND dev jffs2 lives on */
-#define CONFIG_JFFS2_PART_OFFSET 0 /* start of jffs2 partition */
-#define CONFIG_JFFS2_PART_SIZE (256 * 1024 * 1024) /* partition */
+#define CONFIG_BOOTP_BOOTFILESIZE
/* SDRAM */
-#define PHYS_SDRAM 0x70000000
-#define PHYS_SDRAM_SIZE 0x08000000 /* 128 megs */
+#define CONFIG_SYS_SDRAM_BASE 0x70000000
+#define CONFIG_SYS_SDRAM_SIZE 0x08000000
+
+#define CONFIG_SYS_INIT_SP_ADDR \
+ (CONFIG_SYS_SDRAM_BASE + 16 * 1024 - GENERATED_GBL_DATA_SIZE)
/* NAND flash */
#ifdef CONFIG_CMD_NAND
-#define CONFIG_SYS_MAX_NAND_DEVICE 1
-#define CONFIG_SYS_NAND_BASE 0x40000000
-#define CONFIG_SYS_NAND_DBW_8 1
+#define CONFIG_SYS_MAX_NAND_DEVICE 1
+#define CONFIG_SYS_NAND_BASE ATMEL_BASE_CS3
+#define CONFIG_SYS_NAND_DBW_8
/* our ALE is AD21 */
-#define CONFIG_SYS_NAND_MASK_ALE (1 << 21)
+#define CONFIG_SYS_NAND_MASK_ALE BIT(21)
/* our CLE is AD22 */
-#define CONFIG_SYS_NAND_MASK_CLE (1 << 22)
-#define CONFIG_SYS_NAND_ENABLE_PIN GPIO_PIN_PC(14)
-#define CONFIG_SYS_NAND_READY_PIN GPIO_PIN_PD(3)
-
+#define CONFIG_SYS_NAND_MASK_CLE BIT(22)
+#define CONFIG_SYS_NAND_ENABLE_PIN AT91_PIN_PC14
+#define CONFIG_SYS_NAND_READY_PIN AT91_PIN_PD3
+#define CONFIG_SYS_NAND_DRIVER_ECC_LAYOUT
#endif
/* Ethernet */
-#define CONFIG_MACB 1
-#define CONFIG_RMII 1
-#define CONFIG_NET_RETRY_COUNT 20
-#define CONFIG_RESET_PHY_R 1
-
-/* USB */
-#define CONFIG_USB_ATMEL
-#define CONFIG_USB_ATMEL_CLK_SEL_UPLL
-#define CONFIG_USB_OHCI_NEW 1
-#define CONFIG_SYS_USB_OHCI_CPU_INIT 1
-#define CONFIG_SYS_USB_OHCI_REGS_BASE 0x00700000 /* _UHP_OHCI_BASE */
-#define CONFIG_SYS_USB_OHCI_SLOT_NAME "at91sam9g45"
-#define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 2
-
-/* board specific(not enough SRAM) */
-#define CONFIG_AT91SAM9G45_LCD_BASE PHYS_SDRAM + 0xE00000
-
-#define CONFIG_SYS_LOAD_ADDR PHYS_SDRAM + 0x2000000 /* load addr */
-
-#define CONFIG_SYS_MEMTEST_START PHYS_SDRAM
-#define CONFIG_SYS_MEMTEST_END CONFIG_AT91SAM9G45_LCD_BASE
-
-/* bootstrap + u-boot + env + linux in nandflash */
-#define CONFIG_ENV_OFFSET 0x60000
-#define CONFIG_ENV_OFFSET_REDUND 0x80000
-#define CONFIG_ENV_SIZE 0x20000 /* 1 sector = 128 kB */
-#define CONFIG_BOOTCOMMAND "nand read 0x72000000 0x200000 0x200000; bootm"
+#define CONFIG_RESET_PHY_R
+#define CONFIG_AT91_WANTS_COMMON_PHY
+
+#define CONFIG_SYS_LOAD_ADDR 0x22000000 /* load address */
+
+#define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE
+#define CONFIG_SYS_MEMTEST_END 0x23e00000
+
+#ifdef CONFIG_NAND_BOOT
+/* bootstrap + u-boot + env in nandflash */
+#define CONFIG_ENV_OFFSET 0x140000
+#define CONFIG_ENV_OFFSET_REDUND 0x100000
+#define CONFIG_ENV_SIZE 0x20000
+
+#define CONFIG_BOOTCOMMAND \
+ "nand read 0x70000000 0x200000 0x300000;" \
+ "bootm 0x70000000"
+#elif CONFIG_SD_BOOT
+/* bootstrap + u-boot + env + linux in mmc */
+#define CONFIG_ENV_SIZE 0x4000
+
+#define CONFIG_BOOTCOMMAND "fatload mmc 0:1 0x71000000 dtb; " \
+ "fatload mmc 0:1 0x72000000 zImage; " \
+ "bootz 0x72000000 - 0x71000000"
+#endif
/*
* Size of malloc() pool
*/
-#define CONFIG_SYS_MALLOC_LEN ROUND(3 * CONFIG_ENV_SIZE + 128*1024,\
- 0x1000)
+#define CONFIG_SYS_MALLOC_LEN ROUND(3 * CONFIG_ENV_SIZE + \
+ 128 * 1024, 0x1000)
+
+/* Defines for SPL */
+#define CONFIG_SPL_TEXT_BASE 0x300000
+#define CONFIG_SPL_MAX_SIZE 0x010000
+#define CONFIG_SPL_STACK 0x310000
+
+#define CONFIG_SYS_MONITOR_LEN 0x80000
+
+#ifdef CONFIG_SD_BOOT
+
+#define CONFIG_SPL_BSS_START_ADDR 0x70000000
+#define CONFIG_SPL_BSS_MAX_SIZE 0x00080000
+#define CONFIG_SYS_SPL_MALLOC_START 0x70080000
+#define CONFIG_SYS_SPL_MALLOC_SIZE 0x00080000
+
+#define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 1
+#define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "u-boot.img"
+
+#elif CONFIG_NAND_BOOT
+#define CONFIG_SPL_NAND_DRIVERS
+#define CONFIG_SPL_NAND_BASE
+#define CONFIG_SPL_NAND_ECC
+#define CONFIG_SPL_NAND_SOFTECC
+#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x40000
+#define CONFIG_SYS_NAND_U_BOOT_SIZE 0x80000
+#define CONFIG_SYS_NAND_5_ADDR_CYCLE
+
+#define CONFIG_SYS_NAND_PAGE_SIZE 0x800
+#define CONFIG_SYS_NAND_BLOCK_SIZE 0x20000
+#define CONFIG_SYS_NAND_PAGE_COUNT 64
+#define CONFIG_SYS_NAND_BAD_BLOCK_POS NAND_LARGE_BADBLOCK_POS
+#define CONFIG_SYS_NAND_ECCSIZE 256
+#define CONFIG_SYS_NAND_ECCBYTES 3
+#define CONFIG_SYS_NAND_OOBSIZE 64
+#define CONFIG_SYS_NAND_ECCPOS { 40, 41, 42, 43, 44, 45, 46, 47, \
+ 48, 49, 50, 51, 52, 53, 54, 55, \
+ 56, 57, 58, 59, 60, 61, 62, 63, }
+#endif
-#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM
-#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000 - \
- GENERATED_GBL_DATA_SIZE)
+#define CONFIG_SPL_ATMEL_SIZE
+#define CONFIG_SYS_MASTER_CLOCK 132096000
+#define CONFIG_SYS_AT91_PLLA 0x20c73f03
+#define CONFIG_SYS_MCKR 0x1301
+#define CONFIG_SYS_MCKR_CSS 0x1302
#endif
diff --git a/include/configs/smartweb.h b/include/configs/smartweb.h
index 28af575..f95b294 100644
--- a/include/configs/smartweb.h
+++ b/include/configs/smartweb.h
@@ -221,4 +221,8 @@
#define CONFIG_SYS_ICACHE_OFF
#define CONFIG_SYS_DCACHE_OFF
#endif
+
+#define CONFIG_SPL_PAD_TO CONFIG_SYS_NAND_U_BOOT_OFFS
+#define CONFIG_SYS_SPL_LEN CONFIG_SPL_PAD_TO
+
#endif /* __CONFIG_H */
diff --git a/include/configs/taurus.h b/include/configs/taurus.h
index 1d24577..3582eb2 100644
--- a/include/configs/taurus.h
+++ b/include/configs/taurus.h
@@ -173,4 +173,7 @@
#define CONFIG_SYS_MCKR_CSS (0x02 | CONFIG_SYS_MCKR)
#define CONFIG_SYS_AT91_PLLB 0x10193F05
+#define CONFIG_SPL_PAD_TO CONFIG_SYS_NAND_U_BOOT_OFFS
+#define CONFIG_SYS_SPL_LEN CONFIG_SPL_PAD_TO
+
#endif
diff --git a/include/dt-bindings/pinctrl/at91.h b/include/dt-bindings/pinctrl/at91.h
index 2732d6c..616f5ce 100644
--- a/include/dt-bindings/pinctrl/at91.h
+++ b/include/dt-bindings/pinctrl/at91.h
@@ -17,6 +17,7 @@
#define AT91_PINCTRL_DIS_SCHMIT (1 << 4)
#define AT91_PINCTRL_OUTPUT (1 << 7)
#define AT91_PINCTRL_OUTPUT_VAL(x) ((x & 0x1) << 8)
+#define AT91_PINCTRL_SLEWRATE (1 << 9)
#define AT91_PINCTRL_DEBOUNCE (1 << 16)
#define AT91_PINCTRL_DEBOUNCE_VAL(x) (x << 17)
@@ -27,6 +28,9 @@
#define AT91_PINCTRL_DRIVE_STRENGTH_MED (0x2 << 5)
#define AT91_PINCTRL_DRIVE_STRENGTH_HI (0x3 << 5)
+#define AT91_PINCTRL_SLEWRATE_DIS (0x0 << 9)
+#define AT91_PINCTRL_SLEWRATE_ENA (0x1 << 9)
+
#define AT91_PIOA 0
#define AT91_PIOB 1
#define AT91_PIOC 2
diff --git a/include/efi_api.h b/include/efi_api.h
index 8647bfa..5b0a100 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -333,6 +333,10 @@ struct efi_system_table {
EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, \
0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define LOADED_IMAGE_DEVICE_PATH_GUID \
+ EFI_GUID(0xbc62157e, 0x3e33, 0x4fec, \
+ 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf)
+
#define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000
struct efi_loaded_image {
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 512880a..00b81c6 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -135,6 +135,7 @@ extern const efi_guid_t efi_guid_event_group_reset_system;
/* GUID of the device tree table */
extern const efi_guid_t efi_guid_fdt;
extern const efi_guid_t efi_guid_loaded_image;
+extern const efi_guid_t efi_guid_loaded_image_device_path;
extern const efi_guid_t efi_guid_device_path_to_text_protocol;
extern const efi_guid_t efi_simple_file_system_protocol_guid;
extern const efi_guid_t efi_file_info_guid;
@@ -203,15 +204,11 @@ struct efi_object {
* struct efi_loaded_image_obj - handle of a loaded image
*
* @header: EFI object header
- * @reloc_base: base address for the relocated image
- * @reloc_size: size of the relocated image
* @exit_jmp: long jump buffer for returning form started image
* @entry: entry address of the relocated image
*/
struct efi_loaded_image_obj {
struct efi_object header;
- void *reloc_base;
- aligned_u64 reloc_size;
efi_status_t exit_status;
struct jmp_buf_data exit_jmp;
EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
@@ -320,10 +317,19 @@ efi_status_t efi_create_handle(efi_handle_t *handle);
void efi_delete_handle(efi_handle_t obj);
/* Call this to validate a handle and find the EFI object for it */
struct efi_object *efi_search_obj(const efi_handle_t handle);
+/* Load image */
+efi_status_t EFIAPI efi_load_image(bool boot_policy,
+ efi_handle_t parent_image,
+ struct efi_device_path *file_path,
+ void *source_buffer,
+ efi_uintn_t source_size,
+ efi_handle_t *image_handle);
/* Start image */
efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
efi_uintn_t *exit_data_size,
u16 **exit_data);
+/* Unload image */
+efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle);
/* Find a protocol on a handle */
efi_status_t efi_search_protocol(const efi_handle_t handle,
const efi_guid_t *protocol_guid,
diff --git a/include/ext4fs.h b/include/ext4fs.h
index 2421011..34585d4 100644
--- a/include/ext4fs.h
+++ b/include/ext4fs.h
@@ -117,6 +117,12 @@ struct ext_filesystem {
struct blk_desc *dev_desc;
};
+struct ext_block_cache {
+ char *buf;
+ lbaint_t block;
+ int size;
+};
+
extern struct ext2_data *ext4fs_root;
extern struct ext2fs_node *ext4fs_file;
@@ -128,10 +134,11 @@ extern int gindex;
int ext4fs_init(void);
void ext4fs_deinit(void);
int ext4fs_filename_unlink(char *filename);
-int ext4fs_write(const char *fname, unsigned char *buffer,
- unsigned long sizebytes);
+int ext4fs_write(const char *fname, const char *buffer,
+ unsigned long sizebytes, int type);
int ext4_write_file(const char *filename, void *buf, loff_t offset, loff_t len,
loff_t *actwrite);
+int ext4fs_create_link(const char *target, const char *fname);
#endif
struct ext_filesystem *get_fs(void);
@@ -146,11 +153,15 @@ int ext4fs_size(const char *filename, loff_t *size);
void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot);
int ext4fs_devread(lbaint_t sector, int byte_offset, int byte_len, char *buf);
void ext4fs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info);
-long int read_allocated_block(struct ext2_inode *inode, int fileblock);
+long int read_allocated_block(struct ext2_inode *inode, int fileblock,
+ struct ext_block_cache *cache);
int ext4fs_probe(struct blk_desc *fs_dev_desc,
disk_partition_t *fs_partition);
int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
loff_t *actread);
int ext4_read_superblock(char *buffer);
int ext4fs_uuid(char *uuid_str);
+void ext_cache_init(struct ext_block_cache *cache);
+void ext_cache_fini(struct ext_block_cache *cache);
+int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size);
#endif
diff --git a/include/fs.h b/include/fs.h
index aa3604d..6854597 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -191,6 +191,8 @@ int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype);
int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype);
+int do_ln(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+ int fstype);
/*
* Determine the UUID of the specified filesystem and print it. Optionally it is
diff --git a/include/watchdog.h b/include/watchdog.h
index 14073cf..3a357de 100644
--- a/include/watchdog.h
+++ b/include/watchdog.h
@@ -51,9 +51,15 @@ int init_func_watchdog_reset(void);
#if defined(__ASSEMBLY__)
#define WATCHDOG_RESET bl watchdog_reset
#else
- extern void watchdog_reset(void);
+ /* Don't require the watchdog to be enabled in SPL */
+ #if defined(CONFIG_SPL_BUILD) && \
+ !defined(CONFIG_SPL_WATCHDOG_SUPPORT)
+ #define WATCHDOG_RESET() {}
+ #else
+ extern void watchdog_reset(void);
- #define WATCHDOG_RESET watchdog_reset
+ #define WATCHDOG_RESET watchdog_reset
+ #endif
#endif
#else
/*
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 4170161..4fccadc 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -141,6 +141,7 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
efi_deserialize_load_option(&lo, load_option);
if (lo.attributes & LOAD_OPTION_ACTIVE) {
+ u32 attributes;
efi_status_t ret;
debug("%s: trying to load \"%ls\" from %pD\n",
@@ -151,6 +152,16 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
if (ret != EFI_SUCCESS)
goto error;
+ attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS;
+ size = sizeof(n);
+ ret = EFI_CALL(efi_set_variable(
+ L"BootCurrent",
+ (efi_guid_t *)&efi_global_variable_guid,
+ attributes, size, &n));
+ if (ret != EFI_SUCCESS)
+ goto error;
+
printf("Booting: %ls\n", lo.label);
efi_dp_split_file_path(lo.file_path, device_path, file_path);
}
@@ -162,21 +173,53 @@ error:
}
/*
- * Attempt to load, in the order specified by BootOrder EFI variable, the
- * available load-options, finding and returning the first one that can
- * be loaded successfully.
+ * Attempt to load from BootNext or in the order specified by BootOrder
+ * EFI variable, the available load-options, finding and returning
+ * the first one that can be loaded successfully.
*/
void *efi_bootmgr_load(struct efi_device_path **device_path,
struct efi_device_path **file_path)
{
- uint16_t *bootorder;
+ u16 bootnext, *bootorder;
efi_uintn_t size;
void *image = NULL;
int i, num;
+ efi_status_t ret;
bs = systab.boottime;
rs = systab.runtime;
+ /* BootNext */
+ bootnext = 0;
+ size = sizeof(bootnext);
+ ret = EFI_CALL(efi_get_variable(L"BootNext",
+ (efi_guid_t *)&efi_global_variable_guid,
+ NULL, &size, &bootnext));
+ if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
+ /* BootNext does exist here */
+ if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16))
+ printf("BootNext must be 16-bit integer\n");
+
+ /* delete BootNext */
+ ret = EFI_CALL(efi_set_variable(
+ L"BootNext",
+ (efi_guid_t *)&efi_global_variable_guid,
+ 0, 0, &bootnext));
+
+ /* load BootNext */
+ if (ret == EFI_SUCCESS) {
+ if (size == sizeof(u16)) {
+ image = try_load_entry(bootnext, device_path,
+ file_path);
+ if (image)
+ return image;
+ }
+ } else {
+ printf("Deleting BootNext failed\n");
+ }
+ }
+
+ /* BootOrder */
bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
if (!bootorder) {
printf("BootOrder not defined\n");
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 4fc550d..b215bd7 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -26,6 +26,9 @@ LIST_HEAD(efi_obj_list);
/* List of all events */
LIST_HEAD(efi_events);
+/* Handle of the currently executing image */
+static efi_handle_t current_image;
+
/*
* If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
* we need to do trickery with caches. Since we don't want to break the EFI
@@ -1519,6 +1522,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
efi_status_t ret;
struct efi_loaded_image *info = NULL;
struct efi_loaded_image_obj *obj = NULL;
+ struct efi_device_path *dp;
/* In case of EFI_OUT_OF_RESOURCES avoid illegal free by caller. */
*handle_ptr = NULL;
@@ -1542,15 +1546,19 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
if (device_path) {
info->device_handle = efi_dp_find_obj(device_path, NULL);
- /*
- * When asking for the device path interface, return
- * bootefi_device_path
- */
- ret = efi_add_protocol(&obj->header,
- &efi_guid_device_path, device_path);
- if (ret != EFI_SUCCESS)
+
+ dp = efi_dp_append(device_path, file_path);
+ if (!dp) {
+ ret = EFI_OUT_OF_RESOURCES;
goto failure;
+ }
+ } else {
+ dp = NULL;
}
+ ret = efi_add_protocol(&obj->header,
+ &efi_guid_loaded_image_device_path, dp);
+ if (ret != EFI_SUCCESS)
+ goto failure;
/*
* When asking for the loaded_image interface, just
@@ -1679,18 +1687,19 @@ error:
*
* Return: status code
*/
-static efi_status_t EFIAPI efi_load_image(bool boot_policy,
- efi_handle_t parent_image,
- struct efi_device_path *file_path,
- void *source_buffer,
- efi_uintn_t source_size,
- efi_handle_t *image_handle)
+efi_status_t EFIAPI efi_load_image(bool boot_policy,
+ efi_handle_t parent_image,
+ struct efi_device_path *file_path,
+ void *source_buffer,
+ efi_uintn_t source_size,
+ efi_handle_t *image_handle)
{
struct efi_device_path *dp, *fp;
struct efi_loaded_image *info = NULL;
struct efi_loaded_image_obj **image_obj =
(struct efi_loaded_image_obj **)image_handle;
efi_status_t ret;
+ void *dest_buffer;
EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image,
file_path, source_buffer, source_size, image_handle);
@@ -1706,7 +1715,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
}
if (!source_buffer) {
- ret = efi_load_image_from_path(file_path, &source_buffer,
+ ret = efi_load_image_from_path(file_path, &dest_buffer,
&source_size);
if (ret != EFI_SUCCESS)
goto error;
@@ -1719,155 +1728,31 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
/* In this case, file_path is the "device" path, i.e.
* something like a HARDWARE_DEVICE:MEMORY_MAPPED
*/
- u64 addr;
- void *dest_buffer;
-
- ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
- EFI_RUNTIME_SERVICES_CODE,
- efi_size_in_pages(source_size), &addr);
- if (ret != EFI_SUCCESS)
- goto error;
- dest_buffer = (void *)(uintptr_t)addr;
- memcpy(dest_buffer, source_buffer, source_size);
- source_buffer = dest_buffer;
-
+ dest_buffer = source_buffer;
dp = file_path;
fp = NULL;
}
ret = efi_setup_loaded_image(dp, fp, image_obj, &info);
- if (ret != EFI_SUCCESS)
- goto error_invalid_image;
- ret = efi_load_pe(*image_obj, source_buffer, info);
- if (ret != EFI_SUCCESS)
- goto error_invalid_image;
- /* Update the type of the allocated memory */
- efi_add_memory_map((uintptr_t)source_buffer,
- efi_size_in_pages(source_size),
- info->image_code_type, false);
- info->system_table = &systab;
- info->parent_handle = parent_image;
- return EFI_EXIT(EFI_SUCCESS);
-error_invalid_image:
- /* The image is invalid. Release all associated resources. */
- efi_free_pages((uintptr_t)source_buffer,
- efi_size_in_pages(source_size));
- efi_delete_handle(*image_handle);
- *image_handle = NULL;
- free(info);
+ if (ret == EFI_SUCCESS)
+ ret = efi_load_pe(*image_obj, dest_buffer, info);
+ if (!source_buffer)
+ /* Release buffer to which file was loaded */
+ efi_free_pages((uintptr_t)dest_buffer,
+ efi_size_in_pages(source_size));
+ if (ret == EFI_SUCCESS) {
+ info->system_table = &systab;
+ info->parent_handle = parent_image;
+ } else {
+ /* The image is invalid. Release all associated resources. */
+ efi_delete_handle(*image_handle);
+ *image_handle = NULL;
+ free(info);
+ }
error:
return EFI_EXIT(ret);
}
/**
- * efi_start_image() - call the entry point of an image
- * @image_handle: handle of the image
- * @exit_data_size: size of the buffer
- * @exit_data: buffer to receive the exit data of the called image
- *
- * This function implements the StartImage service.
- *
- * See the Unified Extensible Firmware Interface (UEFI) specification for
- * details.
- *
- * Return: status code
- */
-efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
- efi_uintn_t *exit_data_size,
- u16 **exit_data)
-{
- struct efi_loaded_image_obj *image_obj =
- (struct efi_loaded_image_obj *)image_handle;
- efi_status_t ret;
-
- EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
-
- efi_is_direct_boot = false;
-
- /* call the image! */
- if (setjmp(&image_obj->exit_jmp)) {
- /*
- * We called the entry point of the child image with EFI_CALL
- * in the lines below. The child image called the Exit() boot
- * service efi_exit() which executed the long jump that brought
- * us to the current line. This implies that the second half
- * of the EFI_CALL macro has not been executed.
- */
-#ifdef CONFIG_ARM
- /*
- * efi_exit() called efi_restore_gd(). We have to undo this
- * otherwise __efi_entry_check() will put the wrong value into
- * app_gd.
- */
- gd = app_gd;
-#endif
- /*
- * To get ready to call EFI_EXIT below we have to execute the
- * missed out steps of EFI_CALL.
- */
- assert(__efi_entry_check());
- debug("%sEFI: %lu returned by started image\n",
- __efi_nesting_dec(),
- (unsigned long)((uintptr_t)image_obj->exit_status &
- ~EFI_ERROR_MASK));
- return EFI_EXIT(image_obj->exit_status);
- }
-
- ret = EFI_CALL(image_obj->entry(image_handle, &systab));
-
- /*
- * Usually UEFI applications call Exit() instead of returning.
- * But because the world doesn't consist of ponies and unicorns,
- * we're happy to emulate that behavior on behalf of a payload
- * that forgot.
- */
- return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL));
-}
-
-/**
- * efi_exit() - leave an EFI application or driver
- * @image_handle: handle of the application or driver that is exiting
- * @exit_status: status code
- * @exit_data_size: size of the buffer in bytes
- * @exit_data: buffer with data describing an error
- *
- * This function implements the Exit service.
- *
- * See the Unified Extensible Firmware Interface (UEFI) specification for
- * details.
- *
- * Return: status code
- */
-static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
- efi_status_t exit_status,
- efi_uintn_t exit_data_size,
- u16 *exit_data)
-{
- /*
- * TODO: We should call the unload procedure of the loaded
- * image protocol.
- */
- struct efi_loaded_image_obj *image_obj =
- (struct efi_loaded_image_obj *)image_handle;
-
- EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status,
- exit_data_size, exit_data);
-
- /* Make sure entry/exit counts for EFI world cross-overs match */
- EFI_EXIT(exit_status);
-
- /*
- * But longjmp out with the U-Boot gd, not the application's, as
- * the other end is a setjmp call inside EFI context.
- */
- efi_restore_gd();
-
- image_obj->exit_status = exit_status;
- longjmp(&image_obj->exit_jmp, 1);
-
- panic("EFI application exited");
-}
-
-/**
* efi_unload_image() - unload an EFI image
* @image_handle: handle of the image to be unloaded
*
@@ -1878,7 +1763,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
*
* Return: status code
*/
-static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
+efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
{
struct efi_object *efiobj;
@@ -2735,6 +2620,139 @@ out:
}
/**
+ * efi_start_image() - call the entry point of an image
+ * @image_handle: handle of the image
+ * @exit_data_size: size of the buffer
+ * @exit_data: buffer to receive the exit data of the called image
+ *
+ * This function implements the StartImage service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * Return: status code
+ */
+efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
+ efi_uintn_t *exit_data_size,
+ u16 **exit_data)
+{
+ struct efi_loaded_image_obj *image_obj =
+ (struct efi_loaded_image_obj *)image_handle;
+ efi_status_t ret;
+ void *info;
+ efi_handle_t parent_image = current_image;
+
+ EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
+
+ /* Check parameters */
+ ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image,
+ &info, NULL, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL));
+ if (ret != EFI_SUCCESS)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ efi_is_direct_boot = false;
+
+ /* call the image! */
+ if (setjmp(&image_obj->exit_jmp)) {
+ /*
+ * We called the entry point of the child image with EFI_CALL
+ * in the lines below. The child image called the Exit() boot
+ * service efi_exit() which executed the long jump that brought
+ * us to the current line. This implies that the second half
+ * of the EFI_CALL macro has not been executed.
+ */
+#ifdef CONFIG_ARM
+ /*
+ * efi_exit() called efi_restore_gd(). We have to undo this
+ * otherwise __efi_entry_check() will put the wrong value into
+ * app_gd.
+ */
+ gd = app_gd;
+#endif
+ /*
+ * To get ready to call EFI_EXIT below we have to execute the
+ * missed out steps of EFI_CALL.
+ */
+ assert(__efi_entry_check());
+ debug("%sEFI: %lu returned by started image\n",
+ __efi_nesting_dec(),
+ (unsigned long)((uintptr_t)image_obj->exit_status &
+ ~EFI_ERROR_MASK));
+ current_image = parent_image;
+ return EFI_EXIT(image_obj->exit_status);
+ }
+
+ current_image = image_handle;
+ ret = EFI_CALL(image_obj->entry(image_handle, &systab));
+
+ /*
+ * Usually UEFI applications call Exit() instead of returning.
+ * But because the world doesn't consist of ponies and unicorns,
+ * we're happy to emulate that behavior on behalf of a payload
+ * that forgot.
+ */
+ return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL));
+}
+
+/**
+ * efi_exit() - leave an EFI application or driver
+ * @image_handle: handle of the application or driver that is exiting
+ * @exit_status: status code
+ * @exit_data_size: size of the buffer in bytes
+ * @exit_data: buffer with data describing an error
+ *
+ * This function implements the Exit service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
+ efi_status_t exit_status,
+ efi_uintn_t exit_data_size,
+ u16 *exit_data)
+{
+ /*
+ * TODO: We should call the unload procedure of the loaded
+ * image protocol.
+ */
+ efi_status_t ret;
+ void *info;
+ struct efi_loaded_image_obj *image_obj =
+ (struct efi_loaded_image_obj *)image_handle;
+
+ EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status,
+ exit_data_size, exit_data);
+
+ /* Check parameters */
+ if (image_handle != current_image)
+ goto out;
+ ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image,
+ &info, NULL, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL));
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ /* Make sure entry/exit counts for EFI world cross-overs match */
+ EFI_EXIT(exit_status);
+
+ /*
+ * But longjmp out with the U-Boot gd, not the application's, as
+ * the other end is a setjmp call inside EFI context.
+ */
+ efi_restore_gd();
+
+ image_obj->exit_status = exit_status;
+ longjmp(&image_obj->exit_jmp, 1);
+
+ panic("EFI application exited");
+out:
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+/**
* efi_handle_protocol() - get interface of a protocol on a handle
* @handle: handle on which the protocol shall be opened
* @protocol: GUID of the protocol
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 8e0965b..051fc1d 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -797,9 +797,26 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
ret = EFI_NOT_READY;
goto out;
}
+ /*
+ * CTRL+A - CTRL+Z have to be signaled as a - z.
+ * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z.
+ */
+ switch (next_key.key.unicode_char) {
+ case 0x01 ... 0x07:
+ case 0x0b ... 0x0c:
+ case 0x0e ... 0x1a:
+ if (!(next_key.key_state.key_toggle_state &
+ EFI_CAPS_LOCK_ACTIVE) ^
+ !(next_key.key_state.key_shift_state &
+ (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)))
+ next_key.key.unicode_char += 0x40;
+ else
+ next_key.key.unicode_char += 0x60;
+ }
*key_data = next_key;
key_available = false;
efi_con_in.wait_for_key->is_signaled = false;
+
out:
return EFI_EXIT(ret);
}
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index 0483403..182d735 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -135,6 +135,25 @@ static int sanitize_path(char *path)
}
/**
+ * efi_create_file() - create file or directory
+ *
+ * @fh: file handle
+ * @attributes: attributes for newly created file
+ * Returns: 0 for success
+ */
+static int efi_create_file(struct file_handle *fh, u64 attributes)
+{
+ loff_t actwrite;
+ void *buffer = &actwrite;
+
+ if (attributes & EFI_FILE_DIRECTORY)
+ return fs_mkdir(fh->path);
+ else
+ return fs_write(fh->path, map_to_sysmem(buffer), 0, 0,
+ &actwrite);
+}
+
+/**
* file_open() - open a file handle
*
* @fs: file system
@@ -176,6 +195,7 @@ static struct efi_file_handle *file_open(struct file_system *fs,
if (parent) {
char *p = fh->path;
+ int exists;
if (plen > 0) {
strcpy(p, parent->path);
@@ -192,18 +212,17 @@ static struct efi_file_handle *file_open(struct file_system *fs,
if (set_blk_dev(fh))
goto error;
- if ((mode & EFI_FILE_MODE_CREATE) &&
- (attributes & EFI_FILE_DIRECTORY)) {
- if (fs_mkdir(fh->path))
- goto error;
- } else if (!((mode & EFI_FILE_MODE_CREATE) ||
- fs_exists(fh->path)))
- goto error;
-
+ exists = fs_exists(fh->path);
/* fs_exists() calls fs_close(), so open file system again */
if (set_blk_dev(fh))
goto error;
+ if (!exists) {
+ if (!(mode & EFI_FILE_MODE_CREATE) ||
+ efi_create_file(fh, attributes))
+ goto error;
+ }
+
/* figure out if file is a directory: */
fh->isdir = is_dir(fh);
} else {
@@ -257,10 +276,12 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
/* Open file */
*new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes);
- if (*new_handle)
+ if (*new_handle) {
+ EFI_PRINT("file handle %p\n", *new_handle);
ret = EFI_SUCCESS;
- else
+ } else {
ret = EFI_NOT_FOUND;
+ }
out:
return EFI_EXIT(ret);
}
@@ -616,9 +637,72 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
efi_uintn_t buffer_size,
void *buffer)
{
- EFI_ENTRY("%p, %p, %zu, %p", file, info_type, buffer_size, buffer);
+ struct file_handle *fh = to_fh(file);
+ efi_status_t ret = EFI_UNSUPPORTED;
+
+ EFI_ENTRY("%p, %pUl, %zu, %p", file, info_type, buffer_size, buffer);
+
+ if (!guidcmp(info_type, &efi_file_info_guid)) {
+ struct efi_file_info *info = (struct efi_file_info *)buffer;
+ char *filename = basename(fh);
+ char *new_file_name, *pos;
+ loff_t file_size;
- return EFI_EXIT(EFI_UNSUPPORTED);
+ if (buffer_size < sizeof(struct efi_file_info)) {
+ ret = EFI_BAD_BUFFER_SIZE;
+ goto out;
+ }
+ /* We cannot change the directory attribute */
+ if (!fh->isdir != !(info->attribute & EFI_FILE_DIRECTORY)) {
+ ret = EFI_ACCESS_DENIED;
+ goto out;
+ }
+ /* Check for renaming */
+ new_file_name = malloc(utf16_utf8_strlen(info->file_name));
+ if (!new_file_name) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ pos = new_file_name;
+ utf16_utf8_strcpy(&pos, info->file_name);
+ if (strcmp(new_file_name, filename)) {
+ /* TODO: we do not support renaming */
+ EFI_PRINT("Renaming not supported\n");
+ free(new_file_name);
+ ret = EFI_ACCESS_DENIED;
+ goto out;
+ }
+ free(new_file_name);
+ /* Check for truncation */
+ if (set_blk_dev(fh)) {
+ ret = EFI_DEVICE_ERROR;
+ goto out;
+ }
+ if (fs_size(fh->path, &file_size)) {
+ ret = EFI_DEVICE_ERROR;
+ goto out;
+ }
+ if (file_size != info->file_size) {
+ /* TODO: we do not support truncation */
+ EFI_PRINT("Truncation not supported\n");
+ ret = EFI_ACCESS_DENIED;
+ goto out;
+ }
+ /*
+ * We do not care for the other attributes
+ * TODO: Support read only
+ */
+ ret = EFI_SUCCESS;
+ } else if (!guidcmp(info_type, &efi_file_system_info_guid)) {
+ if (buffer_size < sizeof(struct efi_file_system_info)) {
+ ret = EFI_BAD_BUFFER_SIZE;
+ goto out;
+ }
+ } else {
+ ret = EFI_UNSUPPORTED;
+ }
+out:
+ return EFI_EXIT(ret);
}
static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file)
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index fe66e7b..93feefd 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -14,6 +14,8 @@
const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
+const efi_guid_t efi_guid_loaded_image_device_path
+ = LOADED_IMAGE_DEVICE_PATH_GUID;
const efi_guid_t efi_simple_file_system_protocol_guid =
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
@@ -59,10 +61,10 @@ static efi_status_t efi_print_image_info(struct efi_loaded_image_obj *obj,
{
printf("UEFI image");
printf(" [0x%p:0x%p]",
- obj->reloc_base, obj->reloc_base + obj->reloc_size - 1);
- if (pc && pc >= obj->reloc_base &&
- pc < obj->reloc_base + obj->reloc_size)
- printf(" pc=0x%zx", pc - obj->reloc_base);
+ image->image_base, image->image_base + image->image_size - 1);
+ if (pc && pc >= image->image_base &&
+ pc < image->image_base + image->image_size)
+ printf(" pc=0x%zx", pc - image->image_base);
if (image->file_path)
printf(" '%pD'", image->file_path);
printf("\n");
@@ -227,7 +229,6 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
unsigned long rel_size;
int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC;
uint64_t image_base;
- uint64_t image_size;
unsigned long virt_size = 0;
int supported = 0;
@@ -271,7 +272,6 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
IMAGE_NT_HEADERS64 *nt64 = (void *)nt;
IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader;
image_base = opt->ImageBase;
- image_size = opt->SizeOfImage;
efi_set_code_and_data_type(loaded_image_info, opt->Subsystem);
efi_reloc = efi_alloc(virt_size,
loaded_image_info->image_code_type);
@@ -287,7 +287,6 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
} else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader;
image_base = opt->ImageBase;
- image_size = opt->SizeOfImage;
efi_set_code_and_data_type(loaded_image_info, opt->Subsystem);
efi_reloc = efi_alloc(virt_size,
loaded_image_info->image_code_type);
@@ -306,6 +305,11 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
return EFI_LOAD_ERROR;
}
+ /* Copy PE headers */
+ memcpy(efi_reloc, efi, sizeof(*dos) + sizeof(*nt)
+ + nt->FileHeader.SizeOfOptionalHeader
+ + num_sections * sizeof(IMAGE_SECTION_HEADER));
+
/* Load sections into RAM */
for (i = num_sections - 1; i >= 0; i--) {
IMAGE_SECTION_HEADER *sec = &sections[i];
@@ -330,10 +334,8 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
invalidate_icache_all();
/* Populate the loaded image interface bits */
- loaded_image_info->image_base = efi;
- loaded_image_info->image_size = image_size;
- handle->reloc_base = efi_reloc;
- handle->reloc_size = virt_size;
+ loaded_image_info->image_base = efi_reloc;
+ loaded_image_info->image_size = virt_size;
return EFI_SUCCESS;
}
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index 55622d2..dbe29b8 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -15,6 +15,9 @@
DECLARE_GLOBAL_DATA_PTR;
+/* Magic number identifying memory allocated from pool */
+#define EFI_ALLOC_POOL_MAGIC 0x1fe67ddf6491caa2
+
efi_uintn_t efi_memory_map_key;
struct efi_mem_list {
@@ -33,7 +36,12 @@ LIST_HEAD(efi_mem);
void *efi_bounce_buffer;
#endif
-/*
+/**
+ * efi_pool_allocation - memory block allocated from pool
+ *
+ * @num_pages: number of pages allocated
+ * @checksum: checksum
+ *
* U-Boot services each EFI AllocatePool request as a separate
* (multiple) page allocation. We have to track the number of pages
* to be able to free the correct amount later.
@@ -43,9 +51,26 @@ void *efi_bounce_buffer;
*/
struct efi_pool_allocation {
u64 num_pages;
+ u64 checksum;
char data[] __aligned(ARCH_DMA_MINALIGN);
};
+/**
+ * checksum() - calculate checksum for memory allocated from pool
+ *
+ * @alloc: allocation header
+ * Return: checksum, always non-zero
+ */
+static u64 checksum(struct efi_pool_allocation *alloc)
+{
+ u64 addr = (uintptr_t)alloc;
+ u64 ret = (addr >> 32) ^ (addr << 32) ^ alloc->num_pages ^
+ EFI_ALLOC_POOL_MAGIC;
+ if (!ret)
+ ++ret;
+ return ret;
+}
+
/*
* Sorts the memory list from highest address to lowest address
*
@@ -204,8 +229,8 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
bool carve_again;
uint64_t carved_pages = 0;
- debug("%s: 0x%llx 0x%llx %d %s\n", __func__,
- start, pages, memory_type, overlap_only_ram ? "yes" : "no");
+ EFI_PRINT("%s: 0x%llx 0x%llx %d %s\n", __func__,
+ start, pages, memory_type, overlap_only_ram ? "yes" : "no");
if (memory_type >= EFI_MAX_MEMORY_TYPE)
return EFI_INVALID_PARAMETER;
@@ -409,17 +434,24 @@ void *efi_alloc(uint64_t len, int memory_type)
return NULL;
}
-/*
- * Free memory pages.
+/**
+ * efi_free_pages() - free memory pages
*
- * @memory start of the memory area to be freed
- * @pages number of pages to be freed
- * @return status code
+ * @memory: start of the memory area to be freed
+ * @pages: number of pages to be freed
+ * Return: status code
*/
efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
{
uint64_t r = 0;
+ /* Sanity check */
+ if (!memory || (memory & EFI_PAGE_MASK)) {
+ printf("%s: illegal free 0x%llx, 0x%zx\n", __func__,
+ memory, pages);
+ return EFI_INVALID_PARAMETER;
+ }
+
r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
/* Merging of adjacent free regions is missing */
@@ -429,13 +461,13 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
return EFI_NOT_FOUND;
}
-/*
- * Allocate memory from pool.
+/**
+ * efi_allocate_pool - allocate memory from pool
*
- * @pool_type type of the pool from which memory is to be allocated
- * @size number of bytes to be allocated
- * @buffer allocated memory
- * @return status code
+ * @pool_type: type of the pool from which memory is to be allocated
+ * @size: number of bytes to be allocated
+ * @buffer: allocated memory
+ * Return: status code
*/
efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer)
{
@@ -458,17 +490,18 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer)
if (r == EFI_SUCCESS) {
alloc = (struct efi_pool_allocation *)(uintptr_t)addr;
alloc->num_pages = num_pages;
+ alloc->checksum = checksum(alloc);
*buffer = alloc->data;
}
return r;
}
-/*
- * Free memory from pool.
+/**
+ * efi_free_pool() - free memory from pool
*
- * @buffer start of memory to be freed
- * @return status code
+ * @buffer: start of memory to be freed
+ * Return: status code
*/
efi_status_t efi_free_pool(void *buffer)
{
@@ -479,8 +512,15 @@ efi_status_t efi_free_pool(void *buffer)
return EFI_INVALID_PARAMETER;
alloc = container_of(buffer, struct efi_pool_allocation, data);
- /* Sanity check, was the supplied address returned by allocate_pool */
- assert(((uintptr_t)alloc & EFI_PAGE_MASK) == 0);
+
+ /* Check that this memory was allocated by efi_allocate_pool() */
+ if (((uintptr_t)alloc & EFI_PAGE_MASK) ||
+ alloc->checksum != checksum(alloc)) {
+ printf("%s: illegal free 0x%p\n", __func__, buffer);
+ return EFI_INVALID_PARAMETER;
+ }
+ /* Avoid double free */
+ alloc->checksum = 0;
r = efi_free_pages((uintptr_t)alloc, alloc->num_pages);
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index 8266d06..a908843 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -10,6 +10,9 @@
#define OBJ_LIST_NOT_INITIALIZED 1
+/* Language code for American English according to RFC 4646 */
+#define EN_US L"en-US"
+
static efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED;
/* Initialize and populate EFI object list */
@@ -24,6 +27,30 @@ efi_status_t efi_init_obj_list(void)
*/
efi_save_gd();
+ /*
+ * Variable PlatformLang defines the language that the machine has been
+ * configured for.
+ */
+ ret = EFI_CALL(efi_set_variable(L"PlatformLang",
+ &efi_global_variable_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(EN_US), EN_US));
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ /*
+ * Variable PlatformLangCodes defines the language codes that the
+ * machine can support.
+ */
+ ret = EFI_CALL(efi_set_variable(L"PlatformLangCodes",
+ &efi_global_variable_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(EN_US), EN_US));
+ if (ret != EFI_SUCCESS)
+ goto out;
+
/* Initialize once only */
if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
return efi_obj_list_initialized;
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 699f418..37728c3 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -180,7 +180,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
if (ret)
return EFI_EXIT(ret);
- debug("%s: get '%s'\n", __func__, native_name);
+ EFI_PRINT("get '%s'\n", native_name);
val = env_get(native_name);
free(native_name);
@@ -211,7 +211,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
if (hex2bin(data, s, len))
return EFI_EXIT(EFI_DEVICE_ERROR);
- debug("%s: got value: \"%s\"\n", __func__, s);
+ EFI_PRINT("got value: \"%s\"\n", s);
} else if ((s = prefix(val, "(utf8)"))) {
unsigned len = strlen(s) + 1;
@@ -226,9 +226,9 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
memcpy(data, s, len);
((char *)data)[len] = '\0';
- debug("%s: got value: \"%s\"\n", __func__, (char *)data);
+ EFI_PRINT("got value: \"%s\"\n", (char *)data);
} else {
- debug("%s: invalid value: '%s'\n", __func__, val);
+ EFI_PRINT("invalid value: '%s'\n", val);
return EFI_EXIT(EFI_DEVICE_ERROR);
}
@@ -485,7 +485,7 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
s = bin2hex(s, data, data_size);
*s = '\0';
- debug("%s: setting: %s=%s\n", __func__, native_name, val);
+ EFI_PRINT("setting: %s=%s\n", native_name, val);
if (env_set(native_name, val))
ret = EFI_DEVICE_ERROR;
diff --git a/lib/efi_selftest/efi_selftest_miniapp_exit.c b/lib/efi_selftest/efi_selftest_miniapp_exit.c
index 2ffdd65..d63b9e3 100644
--- a/lib/efi_selftest/efi_selftest_miniapp_exit.c
+++ b/lib/efi_selftest/efi_selftest_miniapp_exit.c
@@ -11,22 +11,70 @@
#include <common.h>
#include <efi_api.h>
-/*
+static efi_guid_t loaded_image_protocol_guid = LOADED_IMAGE_GUID;
+
+/**
+ * check_loaded_image_protocol() - check image_base/image_size
+ *
+ * Try to open the loaded image protocol. Check that this function is located
+ * between image_base and image_base + image_size.
+ *
+ * @image_handle: handle of the loaded image
+ * @systable: system table
+ * @return: status code
+ */
+static efi_status_t EFIAPI check_loaded_image_protocol
+ (efi_handle_t image_handle, struct efi_system_table *systable)
+{
+ struct efi_simple_text_output_protocol *cout = systable->con_out;
+ struct efi_boot_services *boottime = systable->boottime;
+ struct efi_loaded_image *loaded_image_protocol;
+ efi_status_t ret;
+
+ /*
+ * Open the loaded image protocol.
+ */
+ ret = boottime->open_protocol
+ (image_handle, &loaded_image_protocol_guid,
+ (void **)&loaded_image_protocol, NULL,
+ NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS) {
+ cout->output_string(cout,
+ L"Could not open loaded image protocol");
+ return ret;
+ }
+ if ((void *)check_loaded_image_protocol <
+ loaded_image_protocol->image_base ||
+ (void *)check_loaded_image_protocol >=
+ loaded_image_protocol->image_base +
+ loaded_image_protocol->image_size) {
+ cout->output_string(cout,
+ L"Incorrect image_base or image_size\n");
+ return EFI_NOT_FOUND;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
* Entry point of the EFI application.
*
- * @handle handle of the loaded image
- * @systable system table
- * @return status code
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * @return: status code
*/
efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable)
{
struct efi_simple_text_output_protocol *con_out = systable->con_out;
+ efi_status_t ret = EFI_UNSUPPORTED;
con_out->output_string(con_out, L"EFI application calling Exit\n");
+ if (check_loaded_image_protocol(handle, systable) != EFI_SUCCESS)
+ ret = EFI_NOT_FOUND;
+
/* The return value is checked by the calling test */
- systable->boottime->exit(handle, EFI_UNSUPPORTED, 0, NULL);
+ systable->boottime->exit(handle, ret, 0, NULL);
/*
* This statement should not be reached.
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 54b160d..56dbbe1 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -179,10 +179,10 @@ MKIMAGEFLAGS_boot.bin = -T atmelimage
ifeq ($(CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER),y)
MKIMAGEFLAGS_boot.bin += -n $(shell $(obj)/../tools/atmel_pmecc_params)
-boot.bin: $(obj)/../tools/atmel_pmecc_params
+$(obj)/boot.bin: $(obj)/../tools/atmel_pmecc_params
endif
-boot.bin: $(obj)/u-boot-spl.bin FORCE
+$(obj)/boot.bin: $(obj)/u-boot-spl.bin FORCE
$(call if_changed,mkimage)
else
ifdef CONFIG_ARCH_ZYNQ
@@ -225,7 +225,7 @@ endif
endif
ifeq ($(CONFIG_SYS_SOC),"at91")
-ALL-y += boot.bin
+ALL-y += $(obj)/boot.bin
endif
ALL-$(CONFIG_SPL_X86_16BIT_INIT) += $(obj)/u-boot-x86-16bit-spl.bin
diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py
index 36b35ee..bc226a8 100644
--- a/test/py/tests/test_efi_selftest.py
+++ b/test/py/tests/test_efi_selftest.py
@@ -141,7 +141,7 @@ def test_efi_selftest_text_input_ex(u_boot_console):
u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect(
- ['Unicode char 4 \(unknown\), scan code 0 \(CTRL\+Null\)'])
+ ['Unicode char 100 \\(\'d\'\\), scan code 0 \\(CTRL\\+Null\\)'])
if m != 0:
raise Exception('EOT failed in \'text input\' test')
u_boot_console.drain_console()
diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py
index 43eeb4b..9324657 100644
--- a/test/py/tests/test_fs/conftest.py
+++ b/test/py/tests/test_fs/conftest.py
@@ -13,6 +13,7 @@ supported_fs_basic = ['fat16', 'fat32', 'ext4']
supported_fs_ext = ['fat16', 'fat32']
supported_fs_mkdir = ['fat16', 'fat32']
supported_fs_unlink = ['fat16', 'fat32']
+supported_fs_symlink = ['ext4']
#
# Filesystem test specific setup
@@ -48,6 +49,7 @@ def pytest_configure(config):
global supported_fs_ext
global supported_fs_mkdir
global supported_fs_unlink
+ global supported_fs_symlink
def intersect(listA, listB):
return [x for x in listA if x in listB]
@@ -59,6 +61,7 @@ def pytest_configure(config):
supported_fs_ext = intersect(supported_fs, supported_fs_ext)
supported_fs_mkdir = intersect(supported_fs, supported_fs_mkdir)
supported_fs_unlink = intersect(supported_fs, supported_fs_unlink)
+ supported_fs_symlink = intersect(supported_fs, supported_fs_symlink)
def pytest_generate_tests(metafunc):
"""Parametrize fixtures, fs_obj_xxx
@@ -84,6 +87,9 @@ def pytest_generate_tests(metafunc):
if 'fs_obj_unlink' in metafunc.fixturenames:
metafunc.parametrize('fs_obj_unlink', supported_fs_unlink,
indirect=True, scope='module')
+ if 'fs_obj_symlink' in metafunc.fixturenames:
+ metafunc.parametrize('fs_obj_symlink', supported_fs_symlink,
+ indirect=True, scope='module')
#
# Helper functions
@@ -143,6 +149,8 @@ def mk_fs(config, fs_type, size, id):
mkfs_opt = '-F 16'
elif fs_type == 'fat32':
mkfs_opt = '-F 32'
+ elif fs_type == 'ext4':
+ mkfs_opt = '-O ^metadata_csum'
else:
mkfs_opt = ''
@@ -523,3 +531,72 @@ def fs_obj_unlink(request, u_boot_config):
call('rmdir %s' % mount_dir, shell=True)
if fs_img:
call('rm -f %s' % fs_img, shell=True)
+
+#
+# Fixture for symlink fs test
+#
+# NOTE: yield_fixture was deprecated since pytest-3.0
+@pytest.yield_fixture()
+def fs_obj_symlink(request, u_boot_config):
+ """Set up a file system to be used in symlink fs test.
+
+ Args:
+ request: Pytest request object.
+ u_boot_config: U-boot configuration.
+
+ Return:
+ A fixture for basic fs test, i.e. a triplet of file system type,
+ volume file name and a list of MD5 hashes.
+ """
+ fs_type = request.param
+ fs_img = ''
+
+ fs_ubtype = fstype_to_ubname(fs_type)
+ check_ubconfig(u_boot_config, fs_ubtype)
+
+ mount_dir = u_boot_config.persistent_data_dir + '/mnt'
+
+ small_file = mount_dir + '/' + SMALL_FILE
+ medium_file = mount_dir + '/' + MEDIUM_FILE
+
+ try:
+
+ # 3GiB volume
+ fs_img = mk_fs(u_boot_config, fs_type, 0x40000000, '1GB')
+
+ # Mount the image so we can populate it.
+ check_call('mkdir -p %s' % mount_dir, shell=True)
+ mount_fs(fs_type, fs_img, mount_dir)
+
+ # Create a subdirectory.
+ check_call('mkdir %s/SUBDIR' % mount_dir, shell=True)
+
+ # Create a small file in this image.
+ check_call('dd if=/dev/urandom of=%s bs=1M count=1'
+ % small_file, shell=True)
+
+ # Create a medium file in this image.
+ check_call('dd if=/dev/urandom of=%s bs=10M count=1'
+ % medium_file, shell=True)
+
+ # Generate the md5sums of reads that we will test against small file
+ out = check_output(
+ 'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
+ % small_file, shell=True)
+ md5val = [out.split()[0]]
+ out = check_output(
+ 'dd if=%s bs=10M skip=0 count=1 2> /dev/null | md5sum'
+ % medium_file, shell=True)
+ md5val.extend([out.split()[0]])
+
+ umount_fs(mount_dir)
+ except CalledProcessError:
+ pytest.skip('Setup failed for filesystem: ' + fs_type)
+ return
+ else:
+ yield [fs_ubtype, fs_img, md5val]
+ finally:
+ umount_fs(mount_dir)
+ call('rmdir %s' % mount_dir, shell=True)
+ if fs_img:
+ call('rm -f %s' % fs_img, shell=True)
diff --git a/test/py/tests/test_fs/fstest_defs.py b/test/py/tests/test_fs/fstest_defs.py
index 5f10756..35b2bb6 100644
--- a/test/py/tests/test_fs/fstest_defs.py
+++ b/test/py/tests/test_fs/fstest_defs.py
@@ -6,6 +6,9 @@ MIN_FILE='testfile'
# $SMALL_FILE is the name of the 1MB file in the file system image
SMALL_FILE='1MB.file'
+# $MEDIUM_FILE is the name of the 10MB file in the file system image
+MEDIUM_FILE='10MB.file'
+
# $BIG_FILE is the name of the 2.5GB file in the file system image
BIG_FILE='2.5GB.file'
diff --git a/test/py/tests/test_fs/fstest_helpers.py b/test/py/tests/test_fs/fstest_helpers.py
new file mode 100644
index 0000000..faec298
--- /dev/null
+++ b/test/py/tests/test_fs/fstest_helpers.py
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2019, Texas Instrument
+# Author: JJ Hiblot <jjhiblot@ti.com>
+#
+
+from subprocess import check_call, CalledProcessError
+
+def assert_fs_integrity(fs_type, fs_img):
+ try:
+ if fs_type == 'ext4':
+ check_call('fsck.ext4 -n -f %s' % fs_img, shell=True)
+ except CalledProcessError:
+ raise
diff --git a/test/py/tests/test_fs/test_basic.py b/test/py/tests/test_fs/test_basic.py
index 140ca29..71f3e86 100644
--- a/test/py/tests/test_fs/test_basic.py
+++ b/test/py/tests/test_fs/test_basic.py
@@ -11,6 +11,7 @@ This test verifies basic read/write operation on file system.
import pytest
import re
from fstest_defs import *
+from fstest_helpers import assert_fs_integrity
@pytest.mark.boardspec('sandbox')
@pytest.mark.slow
@@ -237,6 +238,7 @@ class TestFsBasic(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_fs12(self, u_boot_console, fs_obj_basic):
"""
@@ -252,6 +254,7 @@ class TestFsBasic(object):
'host bind 0 %s' % fs_img,
'%swrite host 0:0 %x /. 0x10' % (fs_type, ADDR)])
assert('Unable to write' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_fs13(self, u_boot_console, fs_obj_basic):
"""
@@ -286,3 +289,4 @@ class TestFsBasic(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
diff --git a/test/py/tests/test_fs/test_ext.py b/test/py/tests/test_fs/test_ext.py
index 06cad55..2c47738 100644
--- a/test/py/tests/test_fs/test_ext.py
+++ b/test/py/tests/test_fs/test_ext.py
@@ -11,6 +11,7 @@ This test verifies extended write operation on file system.
import pytest
import re
from fstest_defs import *
+from fstest_helpers import assert_fs_integrity
@pytest.mark.boardspec('sandbox')
@pytest.mark.slow
@@ -36,6 +37,7 @@ class TestFsExt(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_fs_ext2(self, u_boot_console, fs_obj_ext):
"""
@@ -58,6 +60,7 @@ class TestFsExt(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_fs_ext3(self, u_boot_console, fs_obj_ext):
"""
@@ -72,6 +75,7 @@ class TestFsExt(object):
'%swrite host 0:0 %x /dir1/none/%s.w3 $filesize'
% (fs_type, ADDR, MIN_FILE)])
assert('Unable to write "/dir1/none/' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_fs_ext4(self, u_boot_console, fs_obj_ext):
"""
@@ -104,6 +108,7 @@ class TestFsExt(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[1] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_fs_ext5(self, u_boot_console, fs_obj_ext):
"""
@@ -136,6 +141,7 @@ class TestFsExt(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[2] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_fs_ext6(self, u_boot_console, fs_obj_ext):
"""
@@ -160,6 +166,7 @@ class TestFsExt(object):
'printenv filesize',
'setenv filesize'])
assert('filesize=0' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_fs_ext7(self, u_boot_console, fs_obj_ext):
"""
@@ -192,6 +199,7 @@ class TestFsExt(object):
'md5sum %x $filesize' % ADDR,
'setenv filesize'])
assert(md5val[3] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_fs_ext8(self, u_boot_console, fs_obj_ext):
"""
@@ -209,6 +217,7 @@ class TestFsExt(object):
'%swrite host 0:0 %x /dir1/%s.w8 0x1400 %x'
% (fs_type, ADDR, MIN_FILE, 0x100000 + 0x1400))
assert('Unable to write "/dir1' in output)
+ assert_fs_integrity(fs_type, fs_img)
def test_fs_ext9(self, u_boot_console, fs_obj_ext):
"""
@@ -223,3 +232,4 @@ class TestFsExt(object):
'%swrite host 0:0 %x /dir1/%s.w9 0x1400 0x1400'
% (fs_type, ADDR, MIN_FILE)])
assert('Unable to write "/dir1' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
diff --git a/test/py/tests/test_fs/test_mkdir.py b/test/py/tests/test_fs/test_mkdir.py
index b3fe11c..fa9561e 100644
--- a/test/py/tests/test_fs/test_mkdir.py
+++ b/test/py/tests/test_fs/test_mkdir.py
@@ -9,6 +9,7 @@ This test verifies mkdir operation on file system.
"""
import pytest
+from fstest_helpers import assert_fs_integrity
@pytest.mark.boardspec('sandbox')
@pytest.mark.slow
@@ -29,6 +30,8 @@ class TestMkdir(object):
'%sls host 0:0 dir1' % fs_type)
assert('./' in output)
assert('../' in output)
+ assert_fs_integrity(fs_type, fs_img)
+
def test_mkdir2(self, u_boot_console, fs_obj_mkdir):
"""
@@ -46,6 +49,7 @@ class TestMkdir(object):
'%sls host 0:0 dir1/dir2' % fs_type)
assert('./' in output)
assert('../' in output)
+ assert_fs_integrity(fs_type, fs_img)
def test_mkdir3(self, u_boot_console, fs_obj_mkdir):
"""
@@ -58,6 +62,7 @@ class TestMkdir(object):
'host bind 0 %s' % fs_img,
'%smkdir host 0:0 none/dir3' % fs_type])
assert('Unable to create a directory' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_mkdir4(self, u_boot_console, fs_obj_mkdir):
"""
@@ -69,6 +74,7 @@ class TestMkdir(object):
'host bind 0 %s' % fs_img,
'%smkdir host 0:0 .' % fs_type])
assert('Unable to create a directory' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_mkdir5(self, u_boot_console, fs_obj_mkdir):
"""
@@ -80,6 +86,7 @@ class TestMkdir(object):
'host bind 0 %s' % fs_img,
'%smkdir host 0:0 ..' % fs_type])
assert('Unable to create a directory' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_mkdir6(self, u_boot_console, fs_obj_mkdir):
"""
@@ -111,3 +118,4 @@ class TestMkdir(object):
'%sls host 0:0 dir6/0123456789abcdef13/..' % fs_type)
assert('0123456789abcdef00/' in output)
assert('0123456789abcdef13/' in output)
+ assert_fs_integrity(fs_type, fs_img)
diff --git a/test/py/tests/test_fs/test_symlink.py b/test/py/tests/test_fs/test_symlink.py
new file mode 100644
index 0000000..9ced101
--- /dev/null
+++ b/test/py/tests/test_fs/test_symlink.py
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2019, Texas Instrument
+# Author: Jean-Jacques Hiblot <jjhiblot@ti.com>
+#
+# U-Boot File System:symlink Test
+
+"""
+This test verifies unlink operation (deleting a file or a directory)
+on file system.
+"""
+
+import pytest
+import re
+from fstest_defs import *
+from fstest_helpers import assert_fs_integrity
+
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.slow
+class TestSymlink(object):
+ def test_symlink1(self, u_boot_console, fs_obj_symlink):
+ """
+ Test Case 1 - create a link. and follow it when reading
+ """
+ fs_type, fs_img, md5val = fs_obj_symlink
+ with u_boot_console.log.section('Test Case 1 - create link and read'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ 'setenv filesize',
+ 'ln host 0:0 %s /%s.link ' % (SMALL_FILE, SMALL_FILE),
+ ])
+ assert('' in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ '%sload host 0:0 %x /%s.link' % (fs_type, ADDR, SMALL_FILE),
+ 'printenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ # Test Case 4b - Read full 1MB of small file
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_symlink2(self, u_boot_console, fs_obj_symlink):
+ """
+ Test Case 2 - create chained links
+ """
+ fs_type, fs_img, md5val = fs_obj_symlink
+ with u_boot_console.log.section('Test Case 2 - create chained links'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ 'setenv filesize',
+ 'ln host 0:0 %s /%s.link1 ' % (SMALL_FILE, SMALL_FILE),
+ 'ln host 0:0 /%s.link1 /SUBDIR/%s.link2' % (
+ SMALL_FILE, SMALL_FILE),
+ 'ln host 0:0 SUBDIR/%s.link2 /%s.link3' % (
+ SMALL_FILE, SMALL_FILE),
+ ])
+ assert('' in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ '%sload host 0:0 %x /%s.link3' % (fs_type, ADDR, SMALL_FILE),
+ 'printenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ # Test Case 4b - Read full 1MB of small file
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_symlink3(self, u_boot_console, fs_obj_symlink):
+ """
+ Test Case 3 - replace file/link with link
+ """
+ fs_type, fs_img, md5val = fs_obj_symlink
+ with u_boot_console.log.section('Test Case 1 - create link and read'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ 'setenv filesize',
+ 'ln host 0:0 %s /%s ' % (MEDIUM_FILE, SMALL_FILE),
+ 'ln host 0:0 %s /%s.link ' % (MEDIUM_FILE, MEDIUM_FILE),
+ ])
+ assert('' in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
+ 'printenv filesize'])
+ assert('filesize=a00000' in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[1] in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ 'ln host 0:0 %s.link /%s ' % (MEDIUM_FILE, SMALL_FILE),
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
+ 'printenv filesize'])
+ assert('filesize=a00000' in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[1] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_symlink4(self, u_boot_console, fs_obj_symlink):
+ """
+ Test Case 4 - create a broken link
+ """
+ fs_type, fs_img, md5val = fs_obj_symlink
+ with u_boot_console.log.section('Test Case 1 - create link and read'):
+
+ output = u_boot_console.run_command_list([
+ 'setenv filesize',
+ 'ln host 0:0 nowhere /link ',
+ ])
+ assert('' in ''.join(output))
+
+ output = u_boot_console.run_command(
+ '%sload host 0:0 %x /link' %
+ (fs_type, ADDR))
+ with u_boot_console.disable_check('error_notification'):
+ output = u_boot_console.run_command('printenv filesize')
+ assert('"filesize" not defined' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
diff --git a/test/py/tests/test_fs/test_unlink.py b/test/py/tests/test_fs/test_unlink.py
index 2b81746..97aafc6 100644
--- a/test/py/tests/test_fs/test_unlink.py
+++ b/test/py/tests/test_fs/test_unlink.py
@@ -10,6 +10,7 @@ on file system.
"""
import pytest
+from fstest_helpers import assert_fs_integrity
@pytest.mark.boardspec('sandbox')
@pytest.mark.slow
@@ -30,6 +31,7 @@ class TestUnlink(object):
'%sls host 0:0 dir1/' % fs_type)
assert(not 'file1' in output)
assert('file2' in output)
+ assert_fs_integrity(fs_type, fs_img)
def test_unlink2(self, u_boot_console, fs_obj_unlink):
"""
@@ -48,6 +50,7 @@ class TestUnlink(object):
output = u_boot_console.run_command(
'%sls host 0:0 dir2' % fs_type)
assert('0 file(s), 2 dir(s)' in output)
+ assert_fs_integrity(fs_type, fs_img)
def test_unlink3(self, u_boot_console, fs_obj_unlink):
"""
@@ -59,6 +62,7 @@ class TestUnlink(object):
'host bind 0 %s' % fs_img,
'%srm host 0:0 dir1/nofile' % fs_type])
assert('nofile: doesn\'t exist' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_unlink4(self, u_boot_console, fs_obj_unlink):
"""
@@ -71,9 +75,10 @@ class TestUnlink(object):
'%srm host 0:0 dir4' % fs_type])
assert('' == ''.join(output))
- output = u_boot_console.run_command(
- '%sls host 0:0 /' % fs_type)
- assert(not 'dir4' in output)
+ output = u_boot_console.run_command(
+ '%sls host 0:0 /' % fs_type)
+ assert(not 'dir4' in output)
+ assert_fs_integrity(fs_type, fs_img)
def test_unlink5(self, u_boot_console, fs_obj_unlink):
"""
@@ -86,6 +91,7 @@ class TestUnlink(object):
'host bind 0 %s' % fs_img,
'%srm host 0:0 dir5' % fs_type])
assert('directory is not empty' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_unlink6(self, u_boot_console, fs_obj_unlink):
"""
@@ -97,6 +103,7 @@ class TestUnlink(object):
'host bind 0 %s' % fs_img,
'%srm host 0:0 dir5/.' % fs_type])
assert('directory is not empty' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
def test_unlink7(self, u_boot_console, fs_obj_unlink):
"""
@@ -108,3 +115,4 @@ class TestUnlink(object):
'host bind 0 %s' % fs_img,
'%srm host 0:0 dir5/..' % fs_type])
assert('directory is not empty' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
diff --git a/test/py/tests/test_mmc_rd.py b/test/py/tests/test_mmc_rd.py
index a13bc0a..2dc715b 100644
--- a/test/py/tests/test_mmc_rd.py
+++ b/test/py/tests/test_mmc_rd.py
@@ -6,6 +6,7 @@
# read if the test configuration contains a CRC of the expected data.
import pytest
+import time
import u_boot_utils
"""
@@ -57,6 +58,116 @@ env__mmc_rd_configs = (
)
"""
+def mmc_dev(u_boot_console, is_emmc, devid, partid):
+ """Run the "mmc dev" command.
+
+ Args:
+ u_boot_console: A U-Boot console connection.
+ is_emmc: Whether the device is eMMC
+ devid: Device ID
+ partid: Partition ID
+
+ Returns:
+ Nothing.
+ """
+
+ # Select MMC device
+ cmd = 'mmc dev %d' % devid
+ if is_emmc:
+ cmd += ' %d' % partid
+ response = u_boot_console.run_command(cmd)
+ assert 'no card present' not in response
+ if is_emmc:
+ partid_response = '(part %d)' % partid
+ else:
+ partid_response = ''
+ good_response = 'mmc%d%s is current device' % (devid, partid_response)
+ assert good_response in response
+
+@pytest.mark.buildconfigspec('cmd_mmc')
+def test_mmc_dev(u_boot_console, env__mmc_rd_config):
+ """Test the "mmc dev" command.
+
+ Args:
+ u_boot_console: A U-Boot console connection.
+ env__mmc_rd_config: The single MMC configuration on which
+ to run the test. See the file-level comment above for details
+ of the format.
+
+ Returns:
+ Nothing.
+ """
+
+ is_emmc = env__mmc_rd_config['is_emmc']
+ devid = env__mmc_rd_config['devid']
+ partid = env__mmc_rd_config.get('partid', 0)
+
+ # Select MMC device
+ mmc_dev(u_boot_console, is_emmc, devid, partid)
+
+@pytest.mark.buildconfigspec('cmd_mmc')
+def test_mmc_rescan(u_boot_console, env__mmc_rd_config):
+ """Test the "mmc rescan" command.
+
+ Args:
+ u_boot_console: A U-Boot console connection.
+ env__mmc_rd_config: The single MMC configuration on which
+ to run the test. See the file-level comment above for details
+ of the format.
+
+ Returns:
+ Nothing.
+ """
+
+ is_emmc = env__mmc_rd_config['is_emmc']
+ devid = env__mmc_rd_config['devid']
+ partid = env__mmc_rd_config.get('partid', 0)
+
+ # Select MMC device
+ mmc_dev(u_boot_console, is_emmc, devid, partid)
+
+ # Rescan MMC device
+ cmd = 'mmc rescan'
+ response = u_boot_console.run_command(cmd)
+ assert 'no card present' not in response
+
+@pytest.mark.buildconfigspec('cmd_mmc')
+def test_mmc_info(u_boot_console, env__mmc_rd_config):
+ """Test the "mmc info" command.
+
+ Args:
+ u_boot_console: A U-Boot console connection.
+ env__mmc_rd_config: The single MMC configuration on which
+ to run the test. See the file-level comment above for details
+ of the format.
+
+ Returns:
+ Nothing.
+ """
+
+ is_emmc = env__mmc_rd_config['is_emmc']
+ devid = env__mmc_rd_config['devid']
+ partid = env__mmc_rd_config.get('partid', 0)
+ info_device = env__mmc_rd_config['info_device']
+ info_speed = env__mmc_rd_config['info_speed']
+ info_mode = env__mmc_rd_config['info_mode']
+ info_buswidth = env__mmc_rd_config['info_buswidth']
+
+ # Select MMC device
+ mmc_dev(u_boot_console, is_emmc, devid, partid)
+
+ # Read MMC device information
+ cmd = 'mmc info'
+ response = u_boot_console.run_command(cmd)
+ good_response = "Device: %s" % info_device
+ assert good_response in response
+ good_response = "Bus Speed: %s" % info_speed
+ assert good_response in response
+ good_response = "Mode : %s" % info_mode
+ assert good_response in response
+ good_response = "Bus Width: %s" % info_buswidth
+ assert good_response in response
+
@pytest.mark.buildconfigspec('cmd_mmc')
def test_mmc_rd(u_boot_console, env__mmc_rd_config):
"""Test the "mmc read" command.
@@ -77,6 +188,7 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config):
sector = env__mmc_rd_config.get('sector', 0)
count_sectors = env__mmc_rd_config.get('count', 1)
expected_crc32 = env__mmc_rd_config.get('crc32', None)
+ read_duration_max = env__mmc_rd_config.get('read_duration_max', 0)
count_bytes = count_sectors * 512
bcfg = u_boot_console.config.buildconfig
@@ -86,17 +198,7 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config):
addr = '0x%08x' % ram_base
# Select MMC device
- cmd = 'mmc dev %d' % devid
- if is_emmc:
- cmd += ' %d' % partid
- response = u_boot_console.run_command(cmd)
- assert 'no card present' not in response
- if is_emmc:
- partid_response = '(part %d)' % partid
- else:
- partid_response = ''
- good_response = 'mmc%d%s is current device' % (devid, partid_response)
- assert good_response in response
+ mmc_dev(u_boot_console, is_emmc, devid, partid)
# Clear target RAM
if expected_crc32:
@@ -113,7 +215,9 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config):
# Read data
cmd = 'mmc read %s %x %x' % (addr, sector, count_sectors)
+ tstart = time.time()
response = u_boot_console.run_command(cmd)
+ tend = time.time()
good_response = 'MMC read: dev # %d, block # %d, count %d ... %d blocks read: OK' % (
devid, sector, count_sectors, count_sectors)
assert good_response in response
@@ -126,3 +230,10 @@ def test_mmc_rd(u_boot_console, env__mmc_rd_config):
assert expected_crc32 in response
else:
u_boot_console.log.warning('CONFIG_CMD_CRC32 != y: Skipping check')
+
+ # Check if the command did not take too long
+ if read_duration_max:
+ elapsed = tend - tstart
+ u_boot_console.log.info('Reading %d bytes took %f seconds' %
+ (count_bytes, elapsed))
+ assert elapsed <= (read_duration_max - 0.01)