From ea0f45d18708db2b21e2b771556b3ba1d6a65ed4 Mon Sep 17 00:00:00 2001 From: Su Baocheng Date: Tue, 28 Feb 2023 19:19:09 +0100 Subject: board: siemens: iot2050: Split the build for PG1 and PG2 Due to different signature keys, the PG1 and the PG2 boards can no longer use the same FSBL (tiboot3). This makes it impossible anyway to maintaine a single flash.bin for both variants, so we can also split the build. A new target is added to indicates the build is for PG1 vs. PG2 boards. Hence now the variants have separated defconfig files. The runtime board_is_sr1() check does make no sense anymore, so remove it and replace with build time check. Documentation is updated accordingly. New binary artifacts are already available via meta-iot2050. Signed-off-by: Su Baocheng [Jan: refactor config option into targets, tweak some wordings] Signed-off-by: Jan Kiszka --- doc/board/siemens/iot2050.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'doc') diff --git a/doc/board/siemens/iot2050.rst b/doc/board/siemens/iot2050.rst index 7e97f817ce4..fd3431fa3f8 100644 --- a/doc/board/siemens/iot2050.rst +++ b/doc/board/siemens/iot2050.rst @@ -24,9 +24,10 @@ Binary dependencies can be found in https://github.com/siemens/meta-iot2050/tree/master/recipes-bsp/u-boot/files/prebuild. The following binaries from that source need to be present in the build folder: - - tiboot3.bin - - sysfw.itb - - sysfw.itb_HS + - seboot_pg1.bin + - sysfw_sr1.itb + - sysfw_sr1.itb_HS + - seboot_pg2.bin - sysfw_sr2.itb - sysfw_sr2.itb_HS @@ -57,7 +58,13 @@ U-Boot: $ export ATF=/path/to/bl31.bin $ export TEE=/path/to/tee-pager_v2.bin - $ make iot2050_defconfig + + # configure for PG1 + $ make iot2050_pg1_defconfig + + # or configure for PG2 + $ make iot2050_pg2_defconfig + $ make Flashing -- cgit v1.3.1 From 6ac9131702768343bec150894daac7208963b440 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 28 Feb 2023 19:19:11 +0100 Subject: iot2050: Update firmware layout The latest version of the binary-only firmware parts come in a combined form of FSBL and sysfw containers. This implies some layout changes to the generated firmware image but also makes handling of artifacts much simpler (4 files less). The env locations will not change, just the space reserved for U-Boot will shrink from 4 to 3 MB - still plenty of space left in practice. Adjust configuration and documentation accordingly. Along this change, add a new reservation for update commands of the user-controlled OTP part. A specific userspace tool will fill it, and the FSBL will evaluate it during boot. This reservation will use 64K of the former sysfw section. Signed-off-by: Jan Kiszka --- arch/arm/dts/k3-am65-iot2050-boot-image.dtsi | 30 ++++++++-------------------- configs/iot2050_pg1_defconfig | 2 +- configs/iot2050_pg2_defconfig | 2 +- doc/board/siemens/iot2050.rst | 4 ---- tools/binman/missing-blob-help | 8 +------- 5 files changed, 11 insertions(+), 35 deletions(-) (limited to 'doc') diff --git a/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi b/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi index 46669576864..3ee0842e993 100644 --- a/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi +++ b/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi @@ -25,15 +25,15 @@ missing-msg = "iot2050-seboot"; }; - blob@0x080000 { - offset = <0x080000>; + blob@0x180000 { + offset = <0x180000>; filename = "tispl.bin"; }; - fit@0x280000 { + fit@0x380000 { description = "U-Boot for IOT2050"; fit,fdt-list = "of-list"; - offset = <0x280000>; + offset = <0x380000>; images { u-boot { description = "U-Boot"; @@ -94,25 +94,11 @@ fill-byte = [00]; }; - /* sysfw, basic variant */ - blob-ext@0x6c0000 { + /* OTP update command block */ + fill@0x6c0000 { offset = <0x6c0000>; -#ifdef CONFIG_TARGET_IOT2050_A53_PG1 - filename = "sysfw_sr1.itb"; -#else - filename = "sysfw_sr2.itb"; -#endif - missing-msg = "iot2050-sysfw"; - }; - /* sysfw, advanced variant */ - blob-ext@0x740000 { - offset = <0x740000>; -#ifdef CONFIG_TARGET_IOT2050_A53_PG1 - filename = "sysfw_sr1.itb_HS"; -#else - filename = "sysfw_sr2.itb_HS"; -#endif - missing-msg = "iot2050-sysfw"; + size = <0x010000>; + fill-byte = [ff]; }; }; }; diff --git a/configs/iot2050_pg1_defconfig b/configs/iot2050_pg1_defconfig index 579971c39cd..57a2a6d6f14 100644 --- a/configs/iot2050_pg1_defconfig +++ b/configs/iot2050_pg1_defconfig @@ -52,7 +52,7 @@ CONFIG_SPL_POWER_DOMAIN=y # CONFIG_SPL_SPI_FLASH_TINY is not set CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y CONFIG_SPL_SPI_LOAD=y -CONFIG_SYS_SPI_U_BOOT_OFFS=0x280000 +CONFIG_SYS_SPI_U_BOOT_OFFS=0x380000 CONFIG_SYS_MAXARGS=64 CONFIG_SYS_PBSIZE=1050 CONFIG_CMD_ASKENV=y diff --git a/configs/iot2050_pg2_defconfig b/configs/iot2050_pg2_defconfig index 65400b4696a..e3f82ad3065 100644 --- a/configs/iot2050_pg2_defconfig +++ b/configs/iot2050_pg2_defconfig @@ -54,7 +54,7 @@ CONFIG_SPL_POWER_DOMAIN=y # CONFIG_SPL_SPI_FLASH_TINY is not set CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y CONFIG_SPL_SPI_LOAD=y -CONFIG_SYS_SPI_U_BOOT_OFFS=0x280000 +CONFIG_SYS_SPI_U_BOOT_OFFS=0x380000 CONFIG_SYS_MAXARGS=64 CONFIG_SYS_PBSIZE=1050 CONFIG_CMD_ASKENV=y diff --git a/doc/board/siemens/iot2050.rst b/doc/board/siemens/iot2050.rst index fd3431fa3f8..26972e20ae9 100644 --- a/doc/board/siemens/iot2050.rst +++ b/doc/board/siemens/iot2050.rst @@ -25,11 +25,7 @@ https://github.com/siemens/meta-iot2050/tree/master/recipes-bsp/u-boot/files/pre The following binaries from that source need to be present in the build folder: - seboot_pg1.bin - - sysfw_sr1.itb - - sysfw_sr1.itb_HS - seboot_pg2.bin - - sysfw_sr2.itb - - sysfw_sr2.itb_HS Building -------- diff --git a/tools/binman/missing-blob-help b/tools/binman/missing-blob-help index f3a44d08acc..5fdb22c88c8 100644 --- a/tools/binman/missing-blob-help +++ b/tools/binman/missing-blob-help @@ -21,13 +21,7 @@ Please read the section on SCP firmware in board/sunxi/README.sunxi64 iot2050-seboot: See the documentation for IOT2050 board. Your image is missing SEBoot which is mandatory for board startup. Prebuilt SEBoot located at -meta-iot2050/tree/master/recipes-bsp/u-boot/files/prebuild/tiboot3.bin. - -iot2050-sysfw: -See the documentation for IOT2050 board. Your image is missing system -firmware which is mandatory for board startup. Prebuilt system firmware -located at meta-iot2050/tree/master/recipes-bsp/u-boot/files/prebuild/ -with sysfw prefix. +meta-iot2050/tree/master/recipes-bsp/u-boot/files/prebuild/seboot_pg*.bin. k3-rti-wdt-firmware: If CONFIG_WDT_K3_RTI_LOAD_FW is enabled, a firmware image is needed for -- cgit v1.3.1 From 033ab460d0930e4f7d365279f1c39d914b5e88a4 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 28 Feb 2023 19:19:17 +0100 Subject: iot2050: Add script for signing artifacts There are many ways to get a signed firmware for the IOT2050 devices, namely for the parts under user-control. This script documents one way of doing it, given a signing key. Augment the board documentation with the required procedure around it. Signed-off-by: Jan Kiszka --- doc/board/siemens/iot2050.rst | 52 +++++++++++++++++++++++++++++++++++++++++++ tools/iot2050-sign-fw.sh | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100755 tools/iot2050-sign-fw.sh (limited to 'doc') diff --git a/doc/board/siemens/iot2050.rst b/doc/board/siemens/iot2050.rst index 26972e20ae9..4e0925c72c9 100644 --- a/doc/board/siemens/iot2050.rst +++ b/doc/board/siemens/iot2050.rst @@ -79,3 +79,55 @@ Via external programmer Dediprog SF100 or SF600: .. code-block:: text $ dpcmd --vcc 2 -v -u flash.bin + +Signing (optional) +------------------ + +To enable verified boot for the firmware artifacts after the Siemens-managed +first-stage loader (seboot_pg*.bin), the following steps need to be taken +before and after the build: + +Generate dtsi holding the public key +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: text + + tools/key2dtsi.py -c -s key.pem public-key.dtsi + +This will be used to embed the public key into U-Boot SPL and main so that each +step can validate signatures of the succeeding one. + +Adjust U-Boot configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enabled at least the following options in U-Boot: + +.. code-block:: text + + CONFIG_SPL_FIT_SIGNATURE=y + CONFIG_DEVICE_TREE_INCLUDES="/path/to/public-key.dtsi" + CONFIG_RSA=y + +Note that there are more configuration changes needed in order to lock-down +the command line and the boot process of U-Boot for secure scenarios. These are +not in scope here. + +Build U-Boot +^^^^^^^^^^^^ + +See related section above. + +Sign flash.bin +^^^^^^^^^^^^^^ + +In the build folder still containing artifacts from step 3, invoke: + +.. code-block:: text + + tools/iot2050-sign-fw.sh /path/to/key.pem + +Flash signed flash.bin +^^^^^^^^^^^^^^^^^^^^^^ + +The signing has happen in-place in flash.bin, thus the flashing procedure +described above. diff --git a/tools/iot2050-sign-fw.sh b/tools/iot2050-sign-fw.sh new file mode 100755 index 00000000000..4d1d79498c2 --- /dev/null +++ b/tools/iot2050-sign-fw.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +if [ -z "$1" ]; then + echo "Usage: $0 KEY" + exit 1 +fi + +TEMP_X509=$(mktemp XXXXXXXX.temp) + +REVISION=${2:-0} +SHA_VAL=$(openssl dgst -sha512 -hex tispl.bin | sed -e "s/^.*= //g") +BIN_SIZE=$(stat -c %s tispl.bin) + +cat <$TEMP_X509 +[ req ] +distinguished_name = req_distinguished_name +x509_extensions = v3_ca +prompt = no +dirstring_type = nobmp + +[ req_distinguished_name ] +CN = IOT2050 Firmware Signature + +[ v3_ca ] +basicConstraints = CA:true +1.3.6.1.4.1.294.1.3 = ASN1:SEQUENCE:swrv +1.3.6.1.4.1.294.1.34 = ASN1:SEQUENCE:sysfw_image_integrity + +[ swrv ] +swrv = INTEGER:$REVISION + +[ sysfw_image_integrity ] +shaType = OID:2.16.840.1.101.3.4.2.3 +shaValue = FORMAT:HEX,OCT:$SHA_VAL +imageSize = INTEGER:$BIN_SIZE +EOF + +CERT_X509=$(mktemp XXXXXXXX.crt) + +openssl req -new -x509 -key $1 -nodes -outform DER -out $CERT_X509 -config $TEMP_X509 -sha512 +cat $CERT_X509 tispl.bin > tispl.bin_signed +# currently broken in upstream +#source/tools/binman/binman replace -i flash.bin -f tispl.bin_signed blob@0x180000 +dd if=tispl.bin_signed of=flash.bin bs=$((0x1000)) seek=$((0x180000/0x1000)) conv=notrunc + +rm $TEMP_X509 $CERT_X509 + +tools/mkimage -G $1 -r -o sha256,rsa4096 -F fit@0x380000.fit +# currently broken in upstream +#source/tools/binman/binman replace -i flash.bin -f fit@0x380000.fit fit@0x380000 +dd if=fit@0x380000.fit of=flash.bin bs=$((0x1000)) seek=$((0x380000/0x1000)) conv=notrunc -- cgit v1.3.1 From 367b1bf2ceb320e8862c6014b7138fa126268161 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 28 Feb 2023 19:19:18 +0100 Subject: arm: dts: iot2050: Optionally embed OTP programming data into image Use external blob otpcmd.bin to replace the 0xff filled OTP programming command block to create a firmware image that provisions the OTP on first boot. This otpcmd.bin is generated from the customer keys using steps described in the meta-iot2050 integration layer for the device. Based on original patch by Baocheng Su. Signed-off-by: Jan Kiszka --- arch/arm/dts/k3-am65-iot2050-boot-image.dtsi | 9 +++++++++ board/siemens/iot2050/Kconfig | 7 +++++++ doc/board/siemens/iot2050.rst | 8 ++++++++ tools/binman/missing-blob-help | 8 ++++++++ 4 files changed, 32 insertions(+) (limited to 'doc') diff --git a/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi b/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi index 9082a79a034..a2fc8bbc123 100644 --- a/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi +++ b/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi @@ -111,10 +111,19 @@ }; /* OTP update command block */ +#if CONFIG_IOT2050_EMBED_OTPCMD + blob-ext@0x6c0000 { + offset = <0x6c0000>; + size = <0x010000>; + filename = "otpcmd.bin"; + missing-msg = "iot2050-otpcmd"; + }; +#else fill@0x6c0000 { offset = <0x6c0000>; size = <0x010000>; fill-byte = [ff]; }; +#endif }; }; diff --git a/board/siemens/iot2050/Kconfig b/board/siemens/iot2050/Kconfig index a2b40881d11..e66b2427d95 100644 --- a/board/siemens/iot2050/Kconfig +++ b/board/siemens/iot2050/Kconfig @@ -49,4 +49,11 @@ config IOT2050_BOOT_SWITCH bool "Disable eMMC boot via USER button (Advanced version only)" default y +config IOT2050_EMBED_OTPCMD + bool "Embed OTP programming data" + help + Embed signed OTP programming data 'otpcmd.bin' into the firmware + image. This data will be evaluated and executed on first boot of the + device. + endif diff --git a/doc/board/siemens/iot2050.rst b/doc/board/siemens/iot2050.rst index 4e0925c72c9..cb49a0e36bf 100644 --- a/doc/board/siemens/iot2050.rst +++ b/doc/board/siemens/iot2050.rst @@ -27,6 +27,14 @@ The following binaries from that source need to be present in the build folder: - seboot_pg1.bin - seboot_pg2.bin +For building an image containing the OTP key provisioning data, below binary +needs to be present in the build folder: + + - otpcmd.bin + +Regarding how to generating this otpcmd.bin, please refer to: +https://github.com/siemens/meta-iot2050/tree/master/recipes-bsp/secure-boot-otp-provisioning/files/make-otpcmd.sh + Building -------- diff --git a/tools/binman/missing-blob-help b/tools/binman/missing-blob-help index 5fdb22c88c8..f013367ac36 100644 --- a/tools/binman/missing-blob-help +++ b/tools/binman/missing-blob-help @@ -23,6 +23,14 @@ See the documentation for IOT2050 board. Your image is missing SEBoot which is mandatory for board startup. Prebuilt SEBoot located at meta-iot2050/tree/master/recipes-bsp/u-boot/files/prebuild/seboot_pg*.bin. +iot2050-otpcmd: +See the documentation for IOT2050 board. Your image is missing OTP command data +block which is used for provisioning the customer keys to the board. +Please refer to +meta-iot2050/tree/master/recipes-bsp/secure-boot-otp-provisioning/files/make-otpcmd.sh +for how to generate this binary. If you are not using secure boot or do not +intend to provision the keys, disable CONFIG_IOT2050_EMBED_OTPCMD. + k3-rti-wdt-firmware: If CONFIG_WDT_K3_RTI_LOAD_FW is enabled, a firmware image is needed for the R5F core(s) to trigger the system reset. One possible source is -- cgit v1.3.1 From 7b5cfe3750783a7454d640da2a4fb0c14d95aba7 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 28 Feb 2023 19:19:19 +0100 Subject: doc: iot2050: Add a note about the watchdog firmware This is enabled by default, thus should be described as well. Signed-off-by: Jan Kiszka --- doc/board/siemens/iot2050.rst | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'doc') diff --git a/doc/board/siemens/iot2050.rst b/doc/board/siemens/iot2050.rst index cb49a0e36bf..efe94a448a9 100644 --- a/doc/board/siemens/iot2050.rst +++ b/doc/board/siemens/iot2050.rst @@ -27,6 +27,10 @@ The following binaries from that source need to be present in the build folder: - seboot_pg1.bin - seboot_pg2.bin +When using the watchdog, a related firmware for the R5 core(s) is needed, e.g. +https://github.com/siemens/k3-rti-wdt. The name and location of the image is +configured via CONFIG_WDT_K3_RTI_FW_FILE. + For building an image containing the OTP key provisioning data, below binary needs to be present in the build folder: -- cgit v1.3.1 From ed57c4078303b62bfce2c5d055a0561239ab899f Mon Sep 17 00:00:00 2001 From: chao zeng Date: Tue, 28 Feb 2023 19:19:22 +0100 Subject: arm: dts: iot2050: Add support for M.2 variant Add support for the M.2 board based on the iot2050 advanced board. The board has two m.2 connectors, one is B-keyed, the other E-keyed. The B-key slot can connect 5G/SSD devices, and E-key can be used for WIFI/BT devices. This variant is covered by PG2 firmware image. Signed-off-by: chao zeng [Jan: align DT to kernel, polish wording] Signed-off-by: Jan Kiszka --- arch/arm/dts/Makefile | 3 +- arch/arm/dts/k3-am6548-iot2050-advanced-m2.dts | 121 +++++++++++++++++++++++++ configs/iot2050_pg2_defconfig | 2 +- doc/board/siemens/iot2050.rst | 6 +- 4 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 arch/arm/dts/k3-am6548-iot2050-advanced-m2.dts (limited to 'doc') diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index c160e884bf6..79ed4ac0825 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -1259,7 +1259,8 @@ dtb-$(CONFIG_SOC_K3_AM654) += \ k3-am6528-iot2050-basic.dtb \ k3-am6528-iot2050-basic-pg2.dtb \ k3-am6548-iot2050-advanced.dtb \ - k3-am6548-iot2050-advanced-pg2.dtb + k3-am6548-iot2050-advanced-pg2.dtb \ + k3-am6548-iot2050-advanced-m2.dtb dtb-$(CONFIG_SOC_K3_J721E) += k3-j721e-common-proc-board.dtb \ k3-j721e-r5-common-proc-board.dtb \ k3-j7200-common-proc-board.dtb \ diff --git a/arch/arm/dts/k3-am6548-iot2050-advanced-m2.dts b/arch/arm/dts/k3-am6548-iot2050-advanced-m2.dts new file mode 100644 index 00000000000..9400e35882a --- /dev/null +++ b/arch/arm/dts/k3-am6548-iot2050-advanced-m2.dts @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Siemens AG, 2018-2023 + * + * Authors: + * Chao Zeng + * Jan Kiszka + * + * AM6548-based (quad-core) IOT2050 M.2 variant (based on Advanced Product + * Generation 2), 2 GB RAM, 16 GB eMMC, USB-serial converter on connector X30 + * + * Product homepage: + * https://new.siemens.com/global/en/products/automation/pc-based/iot-gateways/simatic-iot2050.html + */ + +#include "k3-am6548-iot2050-advanced-common.dtsi" +#include "k3-am65-iot2050-common-pg2.dtsi" + +/ { + compatible = "siemens,iot2050-advanced-m2", "ti,am654"; + model = "SIMATIC IOT2050 Advanced M2"; +}; + +&mcu_r5fss0 { + /* lock-step mode not supported on this board */ + ti,cluster-mode = <0>; +}; + +&main_pmx0 { + main_m2_enable_pins_default: main-m2-enable-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7) /* (AH13) GPIO1_17 */ + >; + }; + + main_bkey_pcie_reset: main-bkey-pcie-reset { + pinctrl-single,pins = < + AM65X_IOPAD(0x01bc, PIN_OUTPUT_PULLUP, 7) /* (AG13) GPIO1_15 */ + >; + }; + + main_pmx0_m2_config_pins_default: main-pmx0-m2-config-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x01c8, PIN_INPUT_PULLUP, 7) /* (AE13) GPIO1_18 */ + AM65X_IOPAD(0x01cc, PIN_INPUT_PULLUP, 7) /* (AD13) GPIO1_19 */ + >; + }; + + main_m2_pcie_mux_control: main-m2-pcie-mux-control { + pinctrl-single,pins = < + AM65X_IOPAD(0x0148, PIN_INPUT_PULLUP, 7) /* (AG22) GPIO0_82 */ + AM65X_IOPAD(0x0160, PIN_INPUT_PULLUP, 7) /* (AE20) GPIO0_88 */ + AM65X_IOPAD(0x0164, PIN_INPUT_PULLUP, 7) /* (AF19) GPIO0_89 */ + >; + }; +}; + +&main_pmx1 { + main_pmx1_m2_config_pins_default: main-pmx1-m2-config-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0018, PIN_INPUT_PULLUP, 7) /* (B22) GPIO1_88 */ + AM65X_IOPAD(0x001c, PIN_INPUT_PULLUP, 7) /* (C23) GPIO1_89 */ + >; + }; +}; + +&main_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = < + &main_m2_pcie_mux_control + &arduino_io_d4_to_d9_pins_default + >; +}; + +&main_gpio1 { + pinctrl-names = "default"; + pinctrl-0 = < + &main_m2_enable_pins_default + &main_pmx0_m2_config_pins_default + &main_pmx1_m2_config_pins_default + &cp2102n_reset_pin_default + >; +}; + +/* + * Base configuration for B-key slot with PCIe x2, E-key with USB 2.0 only. + * Firmware switches to other modes via device tree overlays. + */ + +&serdes0 { + assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>; + assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>; +}; + +&pcie0_rc { + pinctrl-names = "default"; + pinctrl-0 = <&main_bkey_pcie_reset>; + + num-lanes = <2>; + phys = <&serdes0 PHY_TYPE_PCIE 1>, <&serdes1 PHY_TYPE_PCIE 1>; + phy-names = "pcie-phy0","pcie-phy1"; + reset-gpios = <&main_gpio1 15 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&pcie1_rc { + status = "disabled"; +}; + +&dwc3_0 { + assigned-clock-parents = <&k3_clks 151 4>, /* set REF_CLK to 20MHz i.e. PER0_PLL/48 */ + <&k3_clks 151 9>; /* set PIPE3_TXB_CLK to CLK_12M_RC/256 (for HS only) */ + /delete-property/ phys; + /delete-property/ phy-names; +}; + +&usb0 { + maximum-speed = "high-speed"; + /delete-property/ snps,dis-u1-entry-quirk; + /delete-property/ snps,dis-u2-entry-quirk; +}; diff --git a/configs/iot2050_pg2_defconfig b/configs/iot2050_pg2_defconfig index d2bdeab593b..b20667780a3 100644 --- a/configs/iot2050_pg2_defconfig +++ b/configs/iot2050_pg2_defconfig @@ -69,7 +69,7 @@ CONFIG_CMD_TIME=y # CONFIG_ISO_PARTITION is not set CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y -CONFIG_OF_LIST="k3-am6528-iot2050-basic-pg2 k3-am6548-iot2050-advanced-pg2" +CONFIG_OF_LIST="k3-am6528-iot2050-basic-pg2 k3-am6548-iot2050-advanced-pg2 k3-am6548-iot2050-advanced-m2" CONFIG_SPL_MULTI_DTB_FIT=y CONFIG_SPL_OF_LIST="k3-am65-iot2050-spl" CONFIG_SPL_MULTI_DTB_FIT_NO_COMPRESSION=y diff --git a/doc/board/siemens/iot2050.rst b/doc/board/siemens/iot2050.rst index efe94a448a9..442d2cac216 100644 --- a/doc/board/siemens/iot2050.rst +++ b/doc/board/siemens/iot2050.rst @@ -6,7 +6,9 @@ SIMATIC IOT2050 BASIC and ADVANCED The SIMATIC IOT2050 is an open industrial IoT gateway that is using the TI AM6528 GP (Basic variant) or the AM6548 HS (Advanced variant). The Advanced -variant is prepared for secure boot. +variant is prepared for secure boot. M.2 Variant also uses the AM6548 HS. +Instead of a MiniPCI connector, it comes with two M.2 connectors and can +support 5G/WIFI/BT applications or connect an SSD. The IOT2050 starts only from OSPI. It loads a Siemens-provided bootloader called SE-Boot for the MCU domain (R5F cores), then hands over to ATF and @@ -70,7 +72,7 @@ U-Boot: # configure for PG1 $ make iot2050_pg1_defconfig - # or configure for PG2 + # or configure for PG2 or the M.2 variant $ make iot2050_pg2_defconfig $ make -- cgit v1.3.1 From 352ed65df7be1c28a94d895f83429f16b858efe0 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 28 Feb 2023 19:19:23 +0100 Subject: iot2050: Add support for configuring M.2 connector The M.2 slots of the related IOT2050 variant need to be configured according to the plugged cards. This tries to detect the card using the M.2 configuration pins of the B-key slot. If that fails, a U-Boot environment variable can be set to configure manually. This variable is write-permitted also in secure boot mode as it is not able to undermine the integrity of the booted system. The configuration is then applied to mux the serdes and to fix up the device tree passed to or loaded by the bootloader. The fix-ups are coming from device tree overlays that are embedded into the firmware image and there also integrity protected. The OS remains free to load a device tree to which they do not apply: U-Boot will not fail to boot in that case. Based on original patch by Chao Zeng. Signed-off-by: Jan Kiszka --- arch/arm/dts/Makefile | 4 +- arch/arm/dts/k3-am65-iot2050-boot-image.dtsi | 38 ++- ...-iot2050-advanced-m2-bkey-ekey-pcie-overlay.dts | 27 +++ ...m6548-iot2050-advanced-m2-bkey-usb3-overlay.dts | 47 ++++ board/siemens/iot2050/board.c | 259 ++++++++++++++++++++- doc/board/siemens/iot2050.rst | 18 ++ include/configs/iot2050.h | 1 + 7 files changed, 391 insertions(+), 3 deletions(-) create mode 100644 arch/arm/dts/k3-am6548-iot2050-advanced-m2-bkey-ekey-pcie-overlay.dts create mode 100644 arch/arm/dts/k3-am6548-iot2050-advanced-m2-bkey-usb3-overlay.dts (limited to 'doc') diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 79ed4ac0825..b25570d1d79 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -1260,7 +1260,9 @@ dtb-$(CONFIG_SOC_K3_AM654) += \ k3-am6528-iot2050-basic-pg2.dtb \ k3-am6548-iot2050-advanced.dtb \ k3-am6548-iot2050-advanced-pg2.dtb \ - k3-am6548-iot2050-advanced-m2.dtb + k3-am6548-iot2050-advanced-m2.dtb \ + k3-am6548-iot2050-advanced-m2-bkey-usb3-overlay.dtbo \ + k3-am6548-iot2050-advanced-m2-bkey-ekey-pcie-overlay.dtbo dtb-$(CONFIG_SOC_K3_J721E) += k3-j721e-common-proc-board.dtb \ k3-j721e-r5-common-proc-board.dtb \ k3-j7200-common-proc-board.dtb \ diff --git a/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi b/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi index a2fc8bbc123..03ccc543293 100644 --- a/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi +++ b/arch/arm/dts/k3-am65-iot2050-boot-image.dtsi @@ -61,6 +61,36 @@ }; }; +#ifdef CONFIG_TARGET_IOT2050_A53_PG2 + bkey-usb3-overlay { + description = "M.2-bkey-usb3-overlay"; + type = "blob"; + load = <0x82100000>; + arch = "arm64"; + compression = "none"; + blob-ext { + filename = "k3-am6548-iot2050-advanced-m2-bkey-usb3-overlay.dtbo"; + }; + hash { + algo = "sha256"; + }; + }; + + bkey-ekey-pcie-overlay { + description = "M.2-bkey-ekey-pcie-overlay"; + type = "blob"; + load = <0x82110000>; + arch = "arm64"; + compression = "none"; + blob-ext { + filename = "k3-am6548-iot2050-advanced-m2-bkey-ekey-pcie-overlay.dtbo"; + }; + hash { + algo = "sha256"; + }; + }; +#endif + #ifdef CONFIG_WDT_K3_RTI_FW_FILE k3-rti-wdt-firmware { type = "firmware"; @@ -84,9 +114,15 @@ description = "NAME"; firmware = "u-boot"; fdt = "fdt-SEQ"; + loadables = +#ifdef CONFIG_TARGET_IOT2050_A53_PG2 + "bkey-usb3-overlay", + "bkey-ekey-pcie-overlay", +#endif #ifdef CONFIG_WDT_K3_RTI_FW_FILE - loadables = "k3-rti-wdt-firmware"; + "k3-rti-wdt-firmware", #endif + <>; signature { sign-images = "firmware", "fdt", "loadables"; }; diff --git a/arch/arm/dts/k3-am6548-iot2050-advanced-m2-bkey-ekey-pcie-overlay.dts b/arch/arm/dts/k3-am6548-iot2050-advanced-m2-bkey-ekey-pcie-overlay.dts new file mode 100644 index 00000000000..c9e736098f9 --- /dev/null +++ b/arch/arm/dts/k3-am6548-iot2050-advanced-m2-bkey-ekey-pcie-overlay.dts @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IOT2050 M.2 variant, overlay for B-key PCIE0_LANE0 + E-key PCIE1_LANE0 + * Copyright (c) Siemens AG, 2022 + * + * Authors: + * Chao Zeng + * Jan Kiszka + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&pcie0_rc { + num-lanes = <1>; + phys = <&serdes0 PHY_TYPE_PCIE 1>; + phy-names = "pcie-phy0"; + reset-gpios = <&main_gpio1 15 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&pcie1_rc { + status = "okay"; +}; diff --git a/arch/arm/dts/k3-am6548-iot2050-advanced-m2-bkey-usb3-overlay.dts b/arch/arm/dts/k3-am6548-iot2050-advanced-m2-bkey-usb3-overlay.dts new file mode 100644 index 00000000000..72fc011bd54 --- /dev/null +++ b/arch/arm/dts/k3-am6548-iot2050-advanced-m2-bkey-usb3-overlay.dts @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IOT2050 M.2 variant, overlay for B-key USB3.0 + E-key PCIE1_LANE0 + * Copyright (c) Siemens AG, 2022 + * + * Authors: + * Chao Zeng + * Jan Kiszka + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&serdes0 { + assigned-clock-parents = <&k3_clks 153 7>, <&k3_clks 153 4>; +}; + +&pcie0_rc { + status = "disabled"; +}; + +&pcie1_rc { + pinctrl-names = "default"; + pinctrl-0 = <&minipcie_pins_default>; + + num-lanes = <1>; + phys = <&serdes1 PHY_TYPE_PCIE 0>; + phy-names = "pcie-phy0"; + reset-gpios = <&wkup_gpio0 27 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&dwc3_0 { + assigned-clock-parents = <&k3_clks 151 4>, /* set REF_CLK to 20MHz i.e. PER0_PLL/48 */ + <&k3_clks 151 8>; /* set PIPE3_TXB_CLK to WIZ8B2M4VSB */ + phys = <&serdes0 PHY_TYPE_USB3 0>; + phy-names = "usb3-phy"; +}; + +&usb0 { + maximum-speed = "super-speed"; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; +}; diff --git a/board/siemens/iot2050/board.c b/board/siemens/iot2050/board.c index 2735ae3fb74..df705b7c971 100644 --- a/board/siemens/iot2050/board.c +++ b/board/siemens/iot2050/board.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Board specific initialization for IOT2050 - * Copyright (c) Siemens AG, 2018-2021 + * Copyright (c) Siemens AG, 2018-2022 * * Authors: * Le Jin @@ -11,9 +11,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -47,6 +49,114 @@ struct iot2050_info { DECLARE_GLOBAL_DATA_PTR; +struct gpio_config { + const char *gpio_name; + const char *label; +}; + +enum m2_connector_mode { + BKEY_PCIEX2 = 0, + BKEY_PCIE_EKEY_PCIE, + BKEY_USB30_EKEY_PCIE, + CONNECTOR_MODE_INVALID +}; + +struct m2_config_pins { + int config[4]; +}; + +struct serdes_mux_control { + int ctrl_usb30_pcie0_lane0; + int ctrl_pcie1_pcie0; + int ctrl_usb30_pcie0_lane1; +}; + +struct m2_config_table { + struct m2_config_pins config_pins; + enum m2_connector_mode mode; +}; + +static const struct gpio_config serdes_mux_ctl_pin_info[] = { + {"gpio@600000_88", "CTRL_USB30_PCIE0_LANE0"}, + {"gpio@600000_82", "CTRL_PCIE1_PCIE0"}, + {"gpio@600000_89", "CTRL_USB30_PCIE0_LANE1"}, +}; + +static const struct gpio_config m2_bkey_cfg_pin_info[] = { + {"gpio@601000_18", "KEY_CONFIG_0"}, + {"gpio@601000_19", "KEY_CONFIG_1"}, + {"gpio@601000_88", "KEY_CONFIG_2"}, + {"gpio@601000_89", "KEY_CONFIG_3"}, +}; + +static const struct m2_config_table m2_config_table[] = { + {{{0, 1, 0, 0}}, BKEY_PCIEX2}, + {{{0, 0, 1, 0}}, BKEY_PCIE_EKEY_PCIE}, + {{{0, 1, 1, 0}}, BKEY_PCIE_EKEY_PCIE}, + {{{1, 0, 0, 1}}, BKEY_PCIE_EKEY_PCIE}, + {{{1, 1, 0, 1}}, BKEY_PCIE_EKEY_PCIE}, + {{{0, 0, 0, 1}}, BKEY_USB30_EKEY_PCIE}, + {{{0, 1, 0, 1}}, BKEY_USB30_EKEY_PCIE}, + {{{0, 0, 1, 1}}, BKEY_USB30_EKEY_PCIE}, + {{{0, 1, 1, 1}}, BKEY_USB30_EKEY_PCIE}, + {{{1, 0, 1, 1}}, BKEY_USB30_EKEY_PCIE}, +}; + +static const struct serdes_mux_control serdes_mux_ctrl[] = { + [BKEY_PCIEX2] = {0, 0, 1}, + [BKEY_PCIE_EKEY_PCIE] = {0, 1, 0}, + [BKEY_USB30_EKEY_PCIE] = {1, 1, 0}, +}; + +static const char *m2_connector_mode_name[] = { + [BKEY_PCIEX2] = "PCIe x2 (key B)", + [BKEY_PCIE_EKEY_PCIE] = "PCIe (key B) / PCIe (key E)", + [BKEY_USB30_EKEY_PCIE] = "USB 3.0 (key B) / PCIe (key E)", +}; + +static enum m2_connector_mode connector_mode; + +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) +static void *connector_overlay; +static u32 connector_overlay_size; +#endif + +static int get_pinvalue(const char *gpio_name, const char *label) +{ + struct gpio_desc gpio; + + if (dm_gpio_lookup_name(gpio_name, &gpio) < 0 || + dm_gpio_request(&gpio, label) < 0 || + dm_gpio_set_dir_flags(&gpio, GPIOD_IS_IN) < 0) { + pr_err("Cannot get pin %s for M.2 configuration\n", gpio_name); + return 0; + } + + return dm_gpio_get_value(&gpio); +} + +static void set_pinvalue(const char *gpio_name, const char *label, int value) +{ + struct gpio_desc gpio; + + if (dm_gpio_lookup_name(gpio_name, &gpio) < 0 || + dm_gpio_request(&gpio, label) < 0 || + dm_gpio_set_dir_flags(&gpio, GPIOD_IS_OUT) < 0) { + pr_err("Cannot set pin %s for M.2 configuration\n", gpio_name); + return; + } + dm_gpio_set_value(&gpio, value); +} + +static bool board_is_m2(void) +{ + struct iot2050_info *info = IOT2050_INFO_DATA; + + return IS_ENABLED(CONFIG_TARGET_IOT2050_A53_PG2) && + info->magic == IOT2050_INFO_MAGIC && + strcmp((char *)info->name, "IOT2050-ADVANCED-M2") == 0; +} + static bool board_is_advanced(void) { struct iot2050_info *info = IOT2050_INFO_DATA; @@ -103,6 +213,8 @@ void set_board_info_env(void) if (board_is_advanced()) { if (IS_ENABLED(CONFIG_TARGET_IOT2050_A53_PG1)) fdtfile = "ti/k3-am6548-iot2050-advanced.dtb"; + else if(board_is_m2()) + fdtfile = "ti/k3-am6548-iot2050-advanced-m2.dtb"; else fdtfile = "ti/k3-am6548-iot2050-advanced-pg2.dtb"; } else { @@ -118,6 +230,101 @@ void set_board_info_env(void) env_save(); } +static void m2_overlay_prepare(void) +{ +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) + const char *overlay_path; + void *overlay; + u64 loadaddr; + ofnode node; + int ret; + + if (connector_mode == BKEY_PCIEX2) + return; + + if (connector_mode == BKEY_PCIE_EKEY_PCIE) + overlay_path = "/fit-images/bkey-ekey-pcie-overlay"; + else + overlay_path = "/fit-images/bkey-usb3-overlay"; + + node = ofnode_path(overlay_path); + if (!ofnode_valid(node)) + goto fit_error; + + ret = ofnode_read_u64(node, "load", &loadaddr); + if (ret) + goto fit_error; + + ret = ofnode_read_u32(node, "size", &connector_overlay_size); + if (ret) + goto fit_error; + + overlay = map_sysmem(loadaddr, connector_overlay_size); + + connector_overlay = malloc(connector_overlay_size); + if (!connector_overlay) + goto fit_error; + + memcpy(connector_overlay, overlay, connector_overlay_size); + return; + +fit_error: + pr_err("M.2 device tree overlay %s not available,\n", overlay_path); +#endif +} + +static void m2_connector_setup(void) +{ + ulong m2_manual_config = env_get_ulong("m2_manual_config", 10, + CONNECTOR_MODE_INVALID); + const char *mode_info = ""; + struct m2_config_pins config_pins; + unsigned int n; + + /* enable M.2 connector power */ + set_pinvalue("gpio@601000_17", "P3V3_M2_EN", 1); + udelay(4 * 100); + + if (m2_manual_config < CONNECTOR_MODE_INVALID) { + mode_info = " [manual mode]"; + connector_mode = m2_manual_config; + } else { /* auto detection */ + for (n = 0; n < ARRAY_SIZE(config_pins.config); n++) + config_pins.config[n] = + get_pinvalue(m2_bkey_cfg_pin_info[n].gpio_name, + m2_bkey_cfg_pin_info[n].label); + connector_mode = CONNECTOR_MODE_INVALID; + for (n = 0; n < ARRAY_SIZE(m2_config_table); n++) { + if (!memcmp(config_pins.config, + m2_config_table[n].config_pins.config, + sizeof(config_pins.config))) { + connector_mode = m2_config_table[n].mode; + break; + } + } + if (connector_mode == CONNECTOR_MODE_INVALID) { + mode_info = " [fallback, card unknown/unsupported]"; + connector_mode = BKEY_USB30_EKEY_PCIE; + } + } + + printf("M.2: %s%s\n", m2_connector_mode_name[connector_mode], + mode_info); + + /* configure serdes mux */ + set_pinvalue(serdes_mux_ctl_pin_info[0].gpio_name, + serdes_mux_ctl_pin_info[0].label, + serdes_mux_ctrl[connector_mode].ctrl_usb30_pcie0_lane0); + set_pinvalue(serdes_mux_ctl_pin_info[1].gpio_name, + serdes_mux_ctl_pin_info[1].label, + serdes_mux_ctrl[connector_mode].ctrl_pcie1_pcie0); + set_pinvalue(serdes_mux_ctl_pin_info[2].gpio_name, + serdes_mux_ctl_pin_info[2].label, + serdes_mux_ctrl[connector_mode].ctrl_usb30_pcie0_lane1); + + m2_overlay_prepare(); +} + int board_init(void) { return 0; @@ -215,6 +422,9 @@ int board_late_init(void) /* change CTRL_MMR register to let serdes0 not output USB3.0 signals. */ writel(0x3, SERDES0_LANE_SELECT); + if (board_is_m2()) + m2_connector_setup(); + set_board_info_env(); /* remove the eMMC if requested via button */ @@ -226,6 +436,50 @@ int board_late_init(void) } #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) +static void m2_fdt_fixup(void *blob) +{ + void *overlay_copy = NULL; + void *fdt_copy = NULL; + u32 fdt_size; + int err; + + if (!connector_overlay) + return; + + /* + * We need to work with temporary copies here because fdt_overlay_apply + * is destructive to the overlay and also to the target blob, even if + * application fails. + */ + fdt_size = fdt_totalsize(blob); + fdt_copy = malloc(fdt_size); + if (!fdt_copy) + goto fixup_error; + + memcpy(fdt_copy, blob, fdt_size); + + overlay_copy = malloc(connector_overlay_size); + if (!overlay_copy) + goto fixup_error; + + memcpy(overlay_copy, connector_overlay, connector_overlay_size); + + err = fdt_overlay_apply_verbose(fdt_copy, overlay_copy); + if (err) + goto fixup_error; + + memcpy(blob, fdt_copy, fdt_size); + +cleanup: + free(fdt_copy); + free(overlay_copy); + return; + +fixup_error: + pr_err("Could not apply M.2 device tree overlay\n"); + goto cleanup; +} + int ft_board_setup(void *blob, struct bd_info *bd) { int ret; @@ -237,6 +491,9 @@ int ft_board_setup(void *blob, struct bd_info *bd) if (ret) pr_err("%s: fixing up msmc ram failed %d\n", __func__, ret); + if (board_is_m2()) + m2_fdt_fixup(blob); + return ret; } #endif diff --git a/doc/board/siemens/iot2050.rst b/doc/board/siemens/iot2050.rst index 442d2cac216..074d6aa15af 100644 --- a/doc/board/siemens/iot2050.rst +++ b/doc/board/siemens/iot2050.rst @@ -145,3 +145,21 @@ Flash signed flash.bin The signing has happen in-place in flash.bin, thus the flashing procedure described above. + +M.2 slot configuration +---------------------- + +The M.2 variant of the IOT2050 comes with one B-keyed and one E-keyed slot. +These are configured by U-Boot depending on the detected usage (auto +configuration). The device tree loaded later on for the OS will be fixed up +by U-Boot according to this configuration. + +For the case auto configuration does not work reliably, it is possible to set +the U-Boot environment variable "m2_manual_config" to select the mode manually: + +"0" - B-key: PCIe x2, USB 2.0 + E-key: USB 2.0 +"1" - B-key: PCIe, USB 2.0 + E-key: PCIe, USB 2.0 +"2" - B-key: USB 3.0, + E-key: PCIe, USB 2.0 diff --git a/include/configs/iot2050.h b/include/configs/iot2050.h index 217719472e5..82174b8678b 100644 --- a/include/configs/iot2050.h +++ b/include/configs/iot2050.h @@ -44,6 +44,7 @@ #define CFG_ENV_FLAGS_LIST_STATIC \ "board_uuid:sw,board_name:sw,board_serial:sw,board_a5e:sw," \ "mlfb:sw,fw_version:sw,seboot_version:sw," \ + "m2_manuel_config:sw," \ "eth1addr:mw,eth2addr:mw,watchdog_timeout_ms:dw,boot_targets:sw" #endif -- cgit v1.3.1