[U-Boot] [PATCH 0/7] Implement UART-based boot of TI K3 AM65x SoCs

This series enables UART-based boot of TI K3 AM65x SoCs by extending the TI K3 System Firmware (SYSFW) loader with support for UART-based loading of SYSFW. This is done by tapping into the existing SPL Y-Modem serial loader framework to accomplish the actual loading functionality. The series also implements a feature called "early console" which allows setting up an alternate full console (as required by Y-Modem) provided through an alternate serial port (a serial port different from what will be used by U-Boot proper/Linux in a system) which can be configured and used prior to SYSFW being available
Specifically, the MAIN_UART0 in case of AM654x SoCs can't be used in the early boot process (on R5 SPL) to load SYSFW as it is not clocked. However since the MCU_UART0 is readily available prior to loading SYSFW we use it during the early boot process via said "early console" functionality, and then later switch over to using MAIN_UART0 both for the continued boot process as well as for the actual U-Boot console itself (and Linux, etc.)
This series depends on [1] to be able to boot to prompt on the TI AM654x EVM. Sample instructions on how to boot are provided in the updates to the board-specific README.
[1] https://patchwork.ozlabs.org/patch/1142068/
Andreas Dannenberg (7): spl: ymodem: Fix FIT loading termination handling spl: ymodem: Make SPL Y-Modem loader framework accessible arm: K3: common: Allow for early console functionality arm: K3: sysfw-loader: Allow loading SYSFW via Y-Modem armv7R: dts: k3: am654: Add MCU_UART0 related definitions configs: am65x_evm_r5: Activate early console functionality board: ti: am65x: Add UART boot procedure in README
arch/arm/dts/k3-am654-r5-base-board.dts | 19 +++++++++++++++ arch/arm/mach-k3/Kconfig | 21 ++++++++++++++++ arch/arm/mach-k3/common.c | 26 ++++++++++++++++++++ arch/arm/mach-k3/common.h | 1 + arch/arm/mach-k3/sysfw-loader.c | 21 ++++++++++++++++ board/ti/am65x/README | 32 +++++++++++++++++++++++++ common/spl/spl_ymodem.c | 9 +++---- configs/am65x_evm_r5_defconfig | 1 + include/spl.h | 3 +++ 9 files changed, 129 insertions(+), 4 deletions(-)

During FIT reading through ymodem_read_fit() the function xyzModem_stream_read() is being used which returns zero once the end of a stream has been reached. This could lead to an premature exit from ymodem_read_fit() with certain-sized FIT images reporting that zero bytes overall were read. Such a premature exit would then result in an -EIO failure being triggered within the spl_load_simple_fit() caller function and ultimately lead to a boot failure.
Fix this logic by simply aborting the stream read loops and continuing with the regular code flow which ultimately would lead to returning the number of bytes to be read ('size') as expected by the callers of ymodem_read_fit().
Fixes: fa715193c083 ("spl: Add an option to load a FIT containing U-Boot from UART") Signed-off-by: Andreas Dannenberg dannenberg@ti.com --- common/spl/spl_ymodem.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/common/spl/spl_ymodem.c b/common/spl/spl_ymodem.c index 20f4260062..8ad580d8ae 100644 --- a/common/spl/spl_ymodem.c +++ b/common/spl/spl_ymodem.c @@ -44,7 +44,8 @@ static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset, while (info->image_read < offset) { res = xyzModem_stream_read(buf, BUF_SIZE, &err); if (res <= 0) - return res; + break; + info->image_read += res; }
@@ -57,7 +58,7 @@ static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset, while (info->image_read < offset + size) { res = xyzModem_stream_read(buf, BUF_SIZE, &err); if (res <= 0) - return res; + break;
memcpy(addr, buf, res); info->image_read += res;

On Thu, Aug 15, 2019 at 03:55:26PM -0500, Andreas Dannenberg wrote:
During FIT reading through ymodem_read_fit() the function xyzModem_stream_read() is being used which returns zero once the end of a stream has been reached. This could lead to an premature exit from ymodem_read_fit() with certain-sized FIT images reporting that zero bytes overall were read. Such a premature exit would then result in an -EIO failure being triggered within the spl_load_simple_fit() caller function and ultimately lead to a boot failure.
Fix this logic by simply aborting the stream read loops and continuing with the regular code flow which ultimately would lead to returning the number of bytes to be read ('size') as expected by the callers of ymodem_read_fit().
Fixes: fa715193c083 ("spl: Add an option to load a FIT containing U-Boot from UART") Signed-off-by: Andreas Dannenberg dannenberg@ti.com
Applied to u-boot/master, thanks!

Expose SPL's Y-Modem core loader function via the common SPL header file so it can be re-used for purposes other than loading U-Boot itself.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com --- common/spl/spl_ymodem.c | 4 ++-- include/spl.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/common/spl/spl_ymodem.c b/common/spl/spl_ymodem.c index 8ad580d8ae..c02c05624d 100644 --- a/common/spl/spl_ymodem.c +++ b/common/spl/spl_ymodem.c @@ -68,8 +68,8 @@ static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset, return size; }
-static int spl_ymodem_load_image(struct spl_image_info *spl_image, - struct spl_boot_device *bootdev) +int spl_ymodem_load_image(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev) { ulong size = 0; int err; diff --git a/include/spl.h b/include/spl.h index a90f971a23..a2c6278c00 100644 --- a/include/spl.h +++ b/include/spl.h @@ -356,6 +356,9 @@ int spl_mmc_load(struct spl_image_info *spl_image, int raw_part, unsigned long raw_sect);
+int spl_ymodem_load_image(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev); + /** * spl_invoke_atf - boot using an ARM trusted firmware image */

On Thu, Aug 15, 2019 at 03:55:27PM -0500, Andreas Dannenberg wrote:
Expose SPL's Y-Modem core loader function via the common SPL header file so it can be re-used for purposes other than loading U-Boot itself.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com
Applied to u-boot/master, thanks!

Implement an early console functionality in SPL that can be used before the main console is being brought up. This helps in situations where the main console is dependent on System Firmware (SYSFW) being up and running, which is usually not the case during the very early stages of boot. Using this early console functionality will allow for an alternate serial port to be used to support things like UART-based boot and early diagnostic messages until the main console is ready to get activated.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com --- arch/arm/mach-k3/Kconfig | 21 +++++++++++++++++++++ arch/arm/mach-k3/common.c | 26 ++++++++++++++++++++++++++ arch/arm/mach-k3/common.h | 1 + 3 files changed, 48 insertions(+)
diff --git a/arch/arm/mach-k3/Kconfig b/arch/arm/mach-k3/Kconfig index 9652c96a78..a878277e39 100644 --- a/arch/arm/mach-k3/Kconfig +++ b/arch/arm/mach-k3/Kconfig @@ -66,6 +66,27 @@ config SYS_K3_BOOT_CORE_ID int default 16
+config K3_EARLY_CONS + bool "Activate to allow for an early console during SPL" + depends on SPL + help + Turn this option on to enable an early console functionality in SPL + before the main console is being brought up. This can be useful in + situations where the main console is dependent on System Firmware + (SYSFW) being up and running, which is usually not the case during + the very early stages of boot. Using this early console functionality + will allow for an alternate serial port to be used to support things + like UART-based boot and early diagnostic messages until the main + console is ready to get activated. + +config K3_EARLY_CONS_IDX + depends on K3_EARLY_CONS + int "Index of serial device to use for SPL early console" + default 1 + help + Use this option to set the index of the serial device to be used + for the early console during SPL execution. + config K3_LOAD_SYSFW bool depends on SPL diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c index bab5ffdf40..279bd96467 100644 --- a/arch/arm/mach-k3/common.c +++ b/arch/arm/mach-k3/common.c @@ -27,6 +27,32 @@ struct ti_sci_handle *get_ti_sci_handle(void) return (struct ti_sci_handle *)ti_sci_get_handle_from_sysfw(dev); }
+DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_K3_EARLY_CONS +int early_console_init(void) +{ + struct udevice *dev; + int ret; + + gd->baudrate = CONFIG_BAUDRATE; + + ret = uclass_get_device_by_seq(UCLASS_SERIAL, CONFIG_K3_EARLY_CONS_IDX, + &dev); + if (ret) { + printf("Error getting serial dev for early console! (%d)\n", + ret); + return ret; + } + + gd->cur_serial_dev = dev; + gd->flags |= GD_FLG_SERIAL_READY; + gd->have_console = 1; + + return 0; +} +#endif + #ifdef CONFIG_SYS_K3_SPL_ATF void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) { diff --git a/arch/arm/mach-k3/common.h b/arch/arm/mach-k3/common.h index ac7e80d9af..ab68e14de8 100644 --- a/arch/arm/mach-k3/common.h +++ b/arch/arm/mach-k3/common.h @@ -9,3 +9,4 @@ #include <asm/armv7_mpu.h>
void setup_k3_mpu_regions(void); +int early_console_init(void);

On Thu, Aug 15, 2019 at 03:55:28PM -0500, Andreas Dannenberg wrote:
Implement an early console functionality in SPL that can be used before the main console is being brought up. This helps in situations where the main console is dependent on System Firmware (SYSFW) being up and running, which is usually not the case during the very early stages of boot. Using this early console functionality will allow for an alternate serial port to be used to support things like UART-based boot and early diagnostic messages until the main console is ready to get activated.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com
Applied to u-boot/master, thanks!

In order to allow booting TI K3 family SoCs via Y-Modem add support for loading System Firmware by tapping into the associated SPL core loader function.
In this context also make sure a console is available and if not go ahead and activate the early console feature which allows bringing up an alternate full console before the main console is activated. Such an alternate console is typically setup in a way that the associated UART can be fully initialized prior to SYSFW services being available.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com --- arch/arm/mach-k3/sysfw-loader.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/arch/arm/mach-k3/sysfw-loader.c b/arch/arm/mach-k3/sysfw-loader.c index 7a482bdc8a..5903bbe12a 100644 --- a/arch/arm/mach-k3/sysfw-loader.c +++ b/arch/arm/mach-k3/sysfw-loader.c @@ -12,6 +12,9 @@ #include <remoteproc.h> #include <linux/soc/ti/ti_sci_protocol.h> #include <asm/arch/sys_proto.h> +#include "common.h" + +DECLARE_GLOBAL_DATA_PTR;
/* Name of the FIT image nodes for SYSFW and its config data */ #define SYSFW_FIRMWARE "sysfw.bin" @@ -214,6 +217,24 @@ void k3_sysfw_loader(void (*config_pm_done_callback)(void)) 0); #endif break; +#endif +#if CONFIG_IS_ENABLED(YMODEM_SUPPORT) + case BOOT_DEVICE_UART: +#ifdef CONFIG_K3_EARLY_CONS + /* + * Establish a serial console if not yet available as required + * for UART-based boot. For this use the early console feature + * that allows setting up a UART for use before SYSFW has been + * brought up. Note that the associated UART module's clocks + * must have gotten enabled by the ROM bootcode which will be + * the case when continuing to boot serially from the same + * UART that the ROM loaded the initial bootloader from. + */ + if (!gd->have_console) + early_console_init(); +#endif + ret = spl_ymodem_load_image(&spl_image, &bootdev); + break; #endif default: panic("Loading SYSFW image from device %u not supported!\n",

On Thu, Aug 15, 2019 at 03:55:29PM -0500, Andreas Dannenberg wrote:
In order to allow booting TI K3 family SoCs via Y-Modem add support for loading System Firmware by tapping into the associated SPL core loader function.
In this context also make sure a console is available and if not go ahead and activate the early console feature which allows bringing up an alternate full console before the main console is activated. Such an alternate console is typically setup in a way that the associated UART can be fully initialized prior to SYSFW services being available.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com
Applied to u-boot/master, thanks!

Although we currently use the MAIN_UART0 for R5 SPL console output there are cases where we require access to the MCU_UART0 as well for example in case of UART-based Y-Modem boot. To support these scenarios add related DTS definitions to be able to use that UART early on.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com --- arch/arm/dts/k3-am654-r5-base-board.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/arch/arm/dts/k3-am654-r5-base-board.dts b/arch/arm/dts/k3-am654-r5-base-board.dts index 7ed307f0d8..e31ed4fe64 100644 --- a/arch/arm/dts/k3-am654-r5-base-board.dts +++ b/arch/arm/dts/k3-am654-r5-base-board.dts @@ -16,6 +16,7 @@
aliases { serial0 = &wkup_uart0; + serial1 = &mcu_uart0; serial2 = &main_uart0; };
@@ -118,6 +119,14 @@ status = "okay"; };
+&mcu_uart0 { + u-boot,dm-spl; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_uart0_pins_default>; + clock-frequency = <48000000>; + status = "okay"; +}; + &main_uart0 { power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>; }; @@ -141,6 +150,16 @@ u-boot,dm-spl; };
+ mcu_uart0_pins_default: mcu_uart0_pins_default { + pinctrl-single,pins = < + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4) /* (P4) MCU_OSPI1_D1.MCU_UART0_RXD */ + AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4) /* (P5) MCU_OSPI1_D2.MCU_UART0_TXD */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 4) /* (P1) MCU_OSPI1_D3.MCU_UART0_CTSn */ + AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 4) /* (N3) MCU_OSPI1_CSn1.MCU_UART0_RTSn */ + >; + u-boot,dm-spl; + }; + wkup_i2c0_pins_default: wkup-i2c0-pins-default { pinctrl-single,pins = < AM65X_WKUP_IOPAD(0x00e0, PIN_INPUT, 0) /* (AC7) WKUP_I2C0_SCL */

On Thu, Aug 15, 2019 at 03:55:30PM -0500, Andreas Dannenberg wrote:
Although we currently use the MAIN_UART0 for R5 SPL console output there are cases where we require access to the MCU_UART0 as well for example in case of UART-based Y-Modem boot. To support these scenarios add related DTS definitions to be able to use that UART early on.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com
Applied to u-boot/master, thanks!

Activate early console functionality on AM654x devices to allow for an alternate serial port to be used to support UART-based boot. This is so that System Firmware (SYSFW) can get loaded over the serial port prior to the main console being brought up and made available.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com --- configs/am65x_evm_r5_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/am65x_evm_r5_defconfig b/configs/am65x_evm_r5_defconfig index c59b7d98dc..e372599080 100644 --- a/configs/am65x_evm_r5_defconfig +++ b/configs/am65x_evm_r5_defconfig @@ -5,6 +5,7 @@ CONFIG_SPL_LIBCOMMON_SUPPORT=y CONFIG_SPL_LIBGENERIC_SUPPORT=y CONFIG_SYS_MALLOC_F_LEN=0x55000 CONFIG_SOC_K3_AM6=y +CONFIG_K3_EARLY_CONS=y CONFIG_TARGET_AM654_R5_EVM=y CONFIG_SPL_MMC_SUPPORT=y CONFIG_SPL_SERIAL_SUPPORT=y

On Thu, Aug 15, 2019 at 03:55:31PM -0500, Andreas Dannenberg wrote:
Activate early console functionality on AM654x devices to allow for an alternate serial port to be used to support UART-based boot. This is so that System Firmware (SYSFW) can get loaded over the serial port prior to the main console being brought up and made available.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com
Applied to u-boot/master, thanks!

am65x ROM support booting over UART. And U-Boot built for am65x EVM supports UART boot as well. Add the UART boot procedure into the README also providing a corresponding example command sequence for execution on a host PC.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com --- board/ti/am65x/README | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/board/ti/am65x/README b/board/ti/am65x/README index 16384e05ea..2e3fd9c4a8 100644 --- a/board/ti/am65x/README +++ b/board/ti/am65x/README @@ -261,3 +261,35 @@ To boot kernel from eMMC, use the following commands: => setenv mmcdev 0 => setenv bootpart 0 => boot + +UART: +----- +ROM supports booting from MCU_UART0 via X-Modem protocol. The entire UART-based +boot process up to U-Boot (proper) prompt goes through different stages and uses +different UART peripherals as follows: + + WHO | Loading WHAT | HW Module | Protocol +----------+---------------+-------------+------------ +Boot ROM | tiboot3.bin | MCU_UART0 | X-Modem(*) +R5 SPL | sysfw.itb | MCU_UART0 | Y-Modem(*) +R5 SPL | tispl.bin | MAIN_UART0 | Y-Modem +A53 SPL | u-boot.img | MAIN_UART0 | Y-Modem + +(*) Note that in addition to X/Y-Modem related protocol timeouts the DMSC + watchdog timeout of 3min (typ.) needs to be observed until System Firmware + is fully loaded (from sysfw.itb) and started. + +Example bash script sequence for running on a Linux host PC feeding all boot +artifacts needed to the device: + +MCU_DEV=/dev/ttyUSB1 +MAIN_DEV=/dev/ttyUSB0 + +stty -F $MCU_DEV 115200 cs8 -cstopb -parenb +stty -F $MAIN_DEV 115200 cs8 -cstopb -parenb + +sb --xmodem tiboot3.bin > $MCU_DEV < $MCU_DEV +sb --ymodem sysfw.itb > $MCU_DEV < $MCU_DEV +sb --ymodem tispl.bin > $MAIN_DEV < $MAIN_DEV +sleep 1 +sb --xmodem u-boot.img > $MAIN_DEV < $MAIN_DEV

On Thu, Aug 15, 2019 at 03:55:32PM -0500, Andreas Dannenberg wrote:
am65x ROM support booting over UART. And U-Boot built for am65x EVM supports UART boot as well. Add the UART boot procedure into the README also providing a corresponding example command sequence for execution on a host PC.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com
Applied to u-boot/master, thanks!
participants (2)
-
Andreas Dannenberg
-
Tom Rini