summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kconfig1
-rw-r--r--Makefile2
-rw-r--r--arch/arm/Makefile4
-rw-r--r--arch/arm/dts/armada-cp110-master.dtsi9
-rw-r--r--arch/arm/dts/armada-cp110-slave.dtsi9
-rw-r--r--arch/arm/dts/imx6sx-softing-vining-2000.dts17
-rw-r--r--arch/arm/dts/imx7ulp-evk.dts157
-rw-r--r--arch/arm/dts/imx7ulp-pinfunc.h1748
-rw-r--r--arch/arm/dts/imx7ulp.dtsi28
-rw-r--r--arch/arm/dts/k3-am654-base-board-u-boot.dtsi3
-rw-r--r--arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi238
-rw-r--r--arch/arm/dts/rk3308-roc-cc.dts9
-rw-r--r--arch/arm/dts/rk3308-u-boot.dtsi2
-rw-r--r--arch/arm/dts/rk3308.dtsi22
-rw-r--r--arch/arm/dts/rk3368-px5-evb-u-boot.dtsi2
-rw-r--r--arch/arm/include/asm/arch-mx6/sys_proto.h8
-rw-r--r--arch/arm/include/asm/arch-mx7ulp/scg.h1
-rw-r--r--arch/arm/include/asm/arch-rockchip/cru_px30.h19
-rw-r--r--arch/arm/include/asm/arch-rockchip/grf_px30.h16
-rw-r--r--arch/arm/include/asm/arch-rockchip/pwm.h17
-rw-r--r--arch/arm/include/asm/mach-imx/sys_proto.h2
-rw-r--r--arch/arm/mach-imx/imx8m/soc.c1
-rw-r--r--arch/arm/mach-imx/mx6/Kconfig1
-rw-r--r--arch/arm/mach-imx/mx6/soc.c43
-rw-r--r--arch/arm/mach-imx/mx7ulp/Kconfig5
-rw-r--r--arch/arm/mach-imx/mx7ulp/scg.c61
-rw-r--r--arch/arm/mach-imx/mx7ulp/soc.c78
-rw-r--r--arch/arm/mach-omap2/omap5/fdt.c12
-rw-r--r--arch/arm/mach-rockchip/misc.c13
-rw-r--r--arch/arm/mach-rockchip/px30/Kconfig6
-rw-r--r--arch/arm/mach-rockchip/px30/px30.c81
-rw-r--r--arch/arm/mach-rockchip/rk3308/rk3308.c37
-rw-r--r--arch/arm/mach-tegra/cboot.c2
-rw-r--r--arch/riscv/Kconfig2
-rw-r--r--arch/riscv/cpu/ax25/Kconfig4
-rw-r--r--arch/riscv/cpu/ax25/cache.c60
-rw-r--r--arch/riscv/cpu/start.S6
-rw-r--r--arch/riscv/cpu/u-boot-spl.lds2
-rw-r--r--arch/riscv/cpu/u-boot.lds2
-rw-r--r--arch/riscv/dts/Makefile1
-rw-r--r--arch/riscv/dts/ae350_32.dts61
-rw-r--r--arch/riscv/dts/ae350_64.dts61
-rw-r--r--arch/riscv/dts/fu540-c000.dtsi251
-rw-r--r--arch/riscv/dts/hifive-unleashed-a00.dts96
-rw-r--r--arch/riscv/include/asm/smp.h3
-rw-r--r--arch/riscv/lib/andes_plic.c22
-rw-r--r--arch/riscv/lib/bootm.c2
-rw-r--r--arch/riscv/lib/sbi_ipi.c11
-rw-r--r--arch/riscv/lib/sifive_clint.c9
-rw-r--r--arch/riscv/lib/smp.c43
-rw-r--r--arch/riscv/lib/spl.c2
-rw-r--r--arch/x86/cpu/start16.S10
-rw-r--r--board/AndesTech/ax25-ae350/Kconfig9
-rw-r--r--board/AndesTech/ax25-ae350/MAINTAINERS4
-rw-r--r--board/AndesTech/ax25-ae350/ax25-ae350.c48
-rw-r--r--board/renesas/sh7752evb/sh7752evb.c2
-rw-r--r--board/renesas/sh7753evb/sh7753evb.c2
-rw-r--r--board/renesas/sh7757lcr/sh7757lcr.c4
-rw-r--r--board/rockchip/evb_px30/MAINTAINERS1
-rw-r--r--board/softing/vining_2000/vining_2000.c256
-rw-r--r--board/solidrun/mx6cuboxi/MAINTAINERS1
-rw-r--r--board/toradex/colibri_imx7/colibri_imx7.c37
-rw-r--r--cmd/Kconfig23
-rw-r--r--cmd/Makefile7
-rw-r--r--cmd/ethsw.c2
-rw-r--r--cmd/nvedit.c19
-rw-r--r--cmd/pxe.c1580
-rw-r--r--cmd/pxe_utils.c1352
-rw-r--r--cmd/pxe_utils.h88
-rw-r--r--cmd/sysboot.c134
-rw-r--r--common/fdt_support.c35
-rw-r--r--common/spl/Kconfig7
-rw-r--r--common/spl/spl.c4
-rw-r--r--common/spl/spl_opensbi.c13
-rw-r--r--configs/ae350_rv32_spl_defconfig38
-rw-r--r--configs/ae350_rv32_spl_xip_defconfig40
-rw-r--r--configs/ae350_rv64_spl_defconfig39
-rw-r--r--configs/ae350_rv64_spl_xip_defconfig41
-rw-r--r--configs/evb-px5_defconfig2
-rw-r--r--configs/firefly-px30_defconfig113
-rw-r--r--configs/j721e_evm_a72_defconfig8
-rw-r--r--configs/rock64-rk3328_defconfig1
-rw-r--r--configs/sifive_fu540_defconfig3
-rw-r--r--configs/vining_2000_defconfig18
-rw-r--r--configs/warp7_defconfig2
-rw-r--r--doc/README.asn140
-rw-r--r--doc/README.enetaddr4
-rw-r--r--doc/README.rockchip1
-rw-r--r--doc/board/AndesTech/ax25-ae350.rst209
-rw-r--r--doc/board/sifive/fu540.rst5
-rw-r--r--doc/device-tree-bindings/net/aquantia-phy.txt25
-rw-r--r--doc/device-tree-bindings/net/phy.txt24
-rw-r--r--doc/device-tree-bindings/net/ti,dp83867.txt6
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/clk/imx/clk-imx8mm.c2
-rw-r--r--drivers/dma/dma-uclass.c12
-rw-r--r--drivers/dma/ti/k3-udma.c29
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/fsl_enetc.c86
-rw-r--r--drivers/net/fsl_enetc.h1
-rw-r--r--drivers/net/fsl_enetc_mdio.c7
-rw-r--r--drivers/net/ftgmac100.c16
-rw-r--r--drivers/net/gmac_rockchip.c65
-rw-r--r--drivers/net/macb.c39
-rw-r--r--drivers/net/mvpp2.c241
-rw-r--r--drivers/net/phy/Kconfig2
-rw-r--r--drivers/net/phy/Makefile2
-rw-r--r--drivers/net/phy/aquantia.c241
-rw-r--r--drivers/net/phy/dp83867.c (renamed from drivers/net/phy/ti.c)243
-rw-r--r--drivers/net/phy/micrel_ksz8xxx.c21
-rw-r--r--drivers/net/phy/mv88e61xx.c226
-rw-r--r--drivers/net/phy/phy.c6
-rw-r--r--drivers/net/rtl8169.c1
-rw-r--r--drivers/net/ti/am65-cpsw-nuss.c16
-rw-r--r--drivers/pinctrl/rockchip/Makefile1
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rk3308.c464
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rockchip-core.c3
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rockchip.h1
-rw-r--r--drivers/pwm/rk_pwm.c138
-rw-r--r--drivers/rtc/Kconfig1
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--fs/ubifs/ubifs.c19
-rw-r--r--include/configs/ax25-ae350.h17
-rw-r--r--include/configs/imx8qxp_mek.h5
-rw-r--r--include/configs/rk3328_common.h2
-rw-r--r--include/configs/rk3399_common.h2
-rw-r--r--include/configs/vining_2000.h6
-rw-r--r--include/configs/warp7.h13
-rw-r--r--include/crypto/internal/rsa.h57
-rw-r--r--include/crypto/pkcs7.h47
-rw-r--r--include/crypto/public_key.h90
-rw-r--r--include/dma-uclass.h11
-rw-r--r--include/dma.h12
-rw-r--r--include/dt-bindings/net/ti-dp83867.h3
-rw-r--r--include/env.h10
-rw-r--r--include/fdt_support.h1
-rw-r--r--include/keys/asymmetric-type.h88
-rw-r--r--include/linux/asn1.h65
-rw-r--r--include/linux/asn1_ber_bytecode.h89
-rw-r--r--include/linux/asn1_decoder.h20
-rw-r--r--include/linux/kernel.h2
-rw-r--r--include/linux/oid_registry.h117
-rw-r--r--include/linux/soc/ti/ti-udma.h19
-rw-r--r--include/linux/time.h11
-rw-r--r--include/linux/types.h2
-rw-r--r--include/miiphy.h18
-rw-r--r--include/net.h34
-rw-r--r--include/opensbi.h18
-rw-r--r--include/phy.h3
-rw-r--r--include/phy_interface.h4
-rw-r--r--include/rtc.h2
-rw-r--r--lib/Kconfig17
-rw-r--r--lib/Makefile20
-rw-r--r--lib/asn1_decoder.c527
-rw-r--r--lib/crypto/Kconfig52
-rw-r--r--lib/crypto/Makefile49
-rw-r--r--lib/crypto/asymmetric_type.c668
-rw-r--r--lib/crypto/pkcs7.asn1135
-rw-r--r--lib/crypto/pkcs7_parser.c693
-rw-r--r--lib/crypto/pkcs7_parser.h65
-rw-r--r--lib/crypto/public_key.c376
-rw-r--r--lib/crypto/rsa_helper.c198
-rw-r--r--lib/crypto/rsapubkey.asn14
-rw-r--r--lib/crypto/x509.asn160
-rw-r--r--lib/crypto/x509_akid.asn135
-rw-r--r--lib/crypto/x509_cert_parser.c697
-rw-r--r--lib/crypto/x509_parser.h57
-rw-r--r--lib/crypto/x509_public_key.c292
-rw-r--r--lib/date.c (renamed from drivers/rtc/date.c)23
-rw-r--r--lib/linux_compat.c19
-rw-r--r--lib/net_utils.c15
-rw-r--r--lib/oid_registry.c179
-rw-r--r--lib/vsprintf.c4
-rw-r--r--net/Kconfig2
-rw-r--r--net/eth-uclass.c19
-rw-r--r--net/eth_legacy.c2
-rw-r--r--net/mdio-uclass.c100
-rw-r--r--net/net.c36
-rw-r--r--net/tftp.c7
-rw-r--r--scripts/Makefile.build4
-rwxr-xr-xscripts/build_OID_registry203
-rw-r--r--test/Kconfig18
-rw-r--r--test/lib/Makefile1
-rw-r--r--test/lib/asn1.c392
-rw-r--r--tools/Makefile3
-rw-r--r--tools/asn1_compiler.c1611
186 files changed, 13462 insertions, 3325 deletions
diff --git a/Kconfig b/Kconfig
index e22417ec44..92fc4fc135 100644
--- a/Kconfig
+++ b/Kconfig
@@ -88,6 +88,7 @@ config DISTRO_DEFAULTS
select CMD_PART if PARTITIONS
select CMD_PING if CMD_NET
select CMD_PXE if NET
+ select CMD_SYSBOOT
select ENV_VARS_UBOOT_CONFIG
select HUSH_PARSER
select SUPPORT_RAW_INITRD
diff --git a/Makefile b/Makefile
index 0ee0c70102..0766f78dcb 100644
--- a/Makefile
+++ b/Makefile
@@ -1889,6 +1889,7 @@ checkarmreloc: u-boot
fi
tools/version.h: include/version.h
+ $(Q)mkdir -p $(dir $@)
$(call if_changed,copy)
envtools: scripts_basic $(version_h) $(timestamp_h) tools/version.h
@@ -1957,6 +1958,7 @@ clean: $(clean-dirs)
-o -name '*.ko.*' -o -name '*.su' -o -name '*.pyc' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
-o -name '*.lex.c' -o -name '*.tab.[ch]' \
+ -o -name '*.asn1.[ch]' \
-o -name '*.symtypes' -o -name 'modules.order' \
-o -name modules.builtin -o -name '.tmp_*.o.*' \
-o -name 'dsdt.aml' -o -name 'dsdt.asl.tmp' -o -name 'dsdt.c' \
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 60af7e3199..856f2d8608 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -12,8 +12,8 @@ arch-$(CONFIG_CPU_ARM926EJS) =-march=armv5te
arch-$(CONFIG_CPU_ARM946ES) =-march=armv5te
arch-$(CONFIG_CPU_SA1100) =-march=armv4
arch-$(CONFIG_CPU_PXA) =
-arch-$(CONFIG_CPU_ARM1136) =-march=armv6
-arch-$(CONFIG_CPU_ARM1176) =-march=armv6
+arch-$(CONFIG_CPU_ARM1136) =-march=armv5t
+arch-$(CONFIG_CPU_ARM1176) =-march=armv5t
arch-$(CONFIG_CPU_V7A) =$(call cc-option, -march=armv7-a, \
$(call cc-option, -march=armv7))
arch-$(CONFIG_CPU_V7M) =-march=armv7-m
diff --git a/arch/arm/dts/armada-cp110-master.dtsi b/arch/arm/dts/armada-cp110-master.dtsi
index e4c17e9f4b..cd5c974482 100644
--- a/arch/arm/dts/armada-cp110-master.dtsi
+++ b/arch/arm/dts/armada-cp110-master.dtsi
@@ -99,6 +99,15 @@
device-name = "cpm-mdio";
};
+ cpm_xmdio: mdio@12a600 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "marvell,xmdio";
+ reg = <0x12a600 0x16>;
+ status = "disabled";
+ device-name = "cpm-xmdio";
+ };
+
cpm_syscon0: system-controller@440000 {
compatible = "marvell,cp110-system-controller0",
"syscon";
diff --git a/arch/arm/dts/armada-cp110-slave.dtsi b/arch/arm/dts/armada-cp110-slave.dtsi
index 2fbd7b5514..b426a4eb69 100644
--- a/arch/arm/dts/armada-cp110-slave.dtsi
+++ b/arch/arm/dts/armada-cp110-slave.dtsi
@@ -99,6 +99,15 @@
device-name = "cps-mdio";
};
+ cps_xmdio: mdio@12a600 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "marvell,xmdio";
+ reg = <0x12a600 0x16>;
+ status = "disabled";
+ device-name = "cps-xmdio";
+ };
+
cps_syscon0: system-controller@440000 {
compatible = "marvell,cp110-system-controller0",
"syscon";
diff --git a/arch/arm/dts/imx6sx-softing-vining-2000.dts b/arch/arm/dts/imx6sx-softing-vining-2000.dts
index 371890ff60..78dd5755a3 100644
--- a/arch/arm/dts/imx6sx-softing-vining-2000.dts
+++ b/arch/arm/dts/imx6sx-softing-vining-2000.dts
@@ -270,6 +270,17 @@
status = "okay";
};
+&reg_pcie {
+ regulator-always-on;
+};
+
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie>;
+ reset-gpio = <&gpio4 6 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpios>;
@@ -360,6 +371,12 @@
>;
};
+ pinctrl_pcie: pciegrp {
+ fsl,pins = <
+ MX6SX_PAD_NAND_DATA02__GPIO4_IO_6 0x10b0
+ >;
+ };
+
pinctrl_pwm1: pwm1grp-1 {
fsl,pins = <
/* blue LED */
diff --git a/arch/arm/dts/imx7ulp-evk.dts b/arch/arm/dts/imx7ulp-evk.dts
index e56b7226e6..08a682f314 100644
--- a/arch/arm/dts/imx7ulp-evk.dts
+++ b/arch/arm/dts/imx7ulp-evk.dts
@@ -15,7 +15,7 @@
compatible = "fsl,imx7ulp-evk", "fsl,imx7ulp", "Generic DT based system";
chosen {
- bootargs = "console=ttyLP0,115200 earlycon=lpuart32,0x402D0010,115200";
+ bootargs = "console=ttyLP0,115200 earlycon=lpuart32,0x402D0000,115200";
stdout-path = &lpuart4;
};
@@ -66,7 +66,7 @@
compatible = "regulator-fixed";
reg = <0>;
pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb_otg1>;
+ pinctrl-0 = <&pinctrl_usbotg1_vbus>;
regulator-name = "usb_otg1_vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
@@ -84,22 +84,6 @@
enable-active-high;
};
- reg_vsd_3v3b: regulator@2 {
- compatible = "regulator-fixed";
- reg = <2>;
- regulator-name = "VSD_3V3B";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- };
- };
-
- extcon_usb1: extcon_usb1 {
- compatible = "linux,extcon-usb-gpio";
- id-gpio = <&gpio0 8 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_extcon_usb1>;
};
pf1550-rpmsg {
@@ -166,134 +150,135 @@
imx7ulp-evk {
pinctrl_hog_1: hoggrp-1 {
fsl,pins = <
- ULP1_PAD_PTC10__PTC10 0x30100 /* USDHC0 CD */
- ULP1_PAD_PTC1__PTC1 0x20100
- ULP1_PAD_PTD0__PTD0 0x30100 /* USDHC0 RST */
- ULP1_PAD_PTE13__PTE13 0x30103 /* USDHC1 CD */
- ULP1_PAD_PTE12__PTE12 0x30103 /* USDHC1 WP */
- ULP1_PAD_PTE14__SDHC1_VS 0x843 /* USDHC1 VSEL */
+ IMX7ULP_PAD_PTC1__PTC1 0x20000
>;
};
pinctrl_backlight: backlight_grp {
fsl,pins = <
- ULP1_PAD_PTF2__PTF2 0x20100
+ IMX7ULP_PAD_PTF2__PTF2 0x20100
>;
};
pinctrl_lpi2c5: lpi2c5grp {
fsl,pins = <
- ULP1_PAD_PTC4__LPI2C5_SCL 0x527
- ULP1_PAD_PTC5__LPI2C5_SDA 0x527
+ IMX7ULP_PAD_PTC4__LPI2C5_SCL 0x27
+ IMX7ULP_PAD_PTC5__LPI2C5_SDA 0x27
>;
};
pinctrl_mipi_dsi_reset: mipi_dsi_reset_grp {
fsl,pins = <
- ULP1_PAD_PTC19__PTC19 0x20103
+ IMX7ULP_PAD_PTC19__PTC19 0x20003
>;
};
pinctrl_lpuart4: lpuart4grp {
fsl,pins = <
- ULP1_PAD_PTC3__LPUART4_RX 0x400
- ULP1_PAD_PTC2__LPUART4_TX 0x400
+ IMX7ULP_PAD_PTC3__LPUART4_RX 0x3
+ IMX7ULP_PAD_PTC2__LPUART4_TX 0x3
>;
};
pinctrl_lpuart6: lpuart6grp {
fsl,pins = <
- ULP1_PAD_PTE10__LPUART6_TX 0x400
- ULP1_PAD_PTE11__LPUART6_RX 0x400
- ULP1_PAD_PTE9__LPUART6_RTS_B 0x400
- ULP1_PAD_PTE8__LPUART6_CTS_B 0x400
- ULP1_PAD_PTE7__PTE7 0x00 /* BT_REG_ON */
+ IMX7ULP_PAD_PTE10__LPUART6_TX 0x3
+ IMX7ULP_PAD_PTE11__LPUART6_RX 0x3
+ IMX7ULP_PAD_PTE9__LPUART6_RTS_B 0x3
+ IMX7ULP_PAD_PTE8__LPUART6_CTS_B 0x3
+ IMX7ULP_PAD_PTE7__PTE7 0x20000 /* BT_REG_ON */
>;
};
pinctrl_lpuart7: lpuart7grp {
fsl,pins = <
- ULP1_PAD_PTF14__LPUART7_TX 0x400
- ULP1_PAD_PTF15__LPUART7_RX 0x400
- ULP1_PAD_PTF13__LPUART7_RTS_B 0x400
- ULP1_PAD_PTF12__LPUART7_CTS_B 0x400
+ IMX7ULP_PAD_PTF14__LPUART7_TX 0x3
+ IMX7ULP_PAD_PTF15__LPUART7_RX 0x3
+ IMX7ULP_PAD_PTF13__LPUART7_RTS_B 0x3
+ IMX7ULP_PAD_PTF12__LPUART7_CTS_B 0x3
>;
};
pinctrl_usdhc0: usdhc0grp {
fsl,pins = <
- ULP1_PAD_PTD1__SDHC0_CMD 0x843
- ULP1_PAD_PTD2__SDHC0_CLK 0x10843
- ULP1_PAD_PTD7__SDHC0_D3 0x843
- ULP1_PAD_PTD8__SDHC0_D2 0x843
- ULP1_PAD_PTD9__SDHC0_D1 0x843
- ULP1_PAD_PTD10__SDHC0_D0 0x843
+ IMX7ULP_PAD_PTD1__SDHC0_CMD 0x43
+ IMX7ULP_PAD_PTD2__SDHC0_CLK 0x10042
+ IMX7ULP_PAD_PTD7__SDHC0_D3 0x43
+ IMX7ULP_PAD_PTD8__SDHC0_D2 0x43
+ IMX7ULP_PAD_PTD9__SDHC0_D1 0x43
+ IMX7ULP_PAD_PTD10__SDHC0_D0 0x43
+ IMX7ULP_PAD_PTC10__PTC10 0x10000 /* USDHC0 CD */
+ IMX7ULP_PAD_PTD0__PTD0 0x20000 /* USDHC0 RST */
>;
};
pinctrl_usdhc0_8bit: usdhc0grp_8bit {
fsl,pins = <
- ULP1_PAD_PTD1__SDHC0_CMD 0x843
- ULP1_PAD_PTD2__SDHC0_CLK 0x843
- ULP1_PAD_PTD3__SDHC0_D7 0x843
- ULP1_PAD_PTD4__SDHC0_D6 0x843
- ULP1_PAD_PTD5__SDHC0_D5 0x843
- ULP1_PAD_PTD6__SDHC0_D4 0x843
- ULP1_PAD_PTD7__SDHC0_D3 0x843
- ULP1_PAD_PTD8__SDHC0_D2 0x843
- ULP1_PAD_PTD9__SDHC0_D1 0x843
- ULP1_PAD_PTD10__SDHC0_D0 0x843
+ IMX7ULP_PAD_PTD1__SDHC0_CMD 0x43
+ IMX7ULP_PAD_PTD2__SDHC0_CLK 0x10042
+ IMX7ULP_PAD_PTD3__SDHC0_D7 0x43
+ IMX7ULP_PAD_PTD4__SDHC0_D6 0x43
+ IMX7ULP_PAD_PTD5__SDHC0_D5 0x43
+ IMX7ULP_PAD_PTD6__SDHC0_D4 0x43
+ IMX7ULP_PAD_PTD7__SDHC0_D3 0x43
+ IMX7ULP_PAD_PTD8__SDHC0_D2 0x43
+ IMX7ULP_PAD_PTD9__SDHC0_D1 0x43
+ IMX7ULP_PAD_PTD10__SDHC0_D0 0x43
+ IMX7ULP_PAD_PTD11__SDHC0_DQS 0x42
>;
};
pinctrl_lpi2c7: lpi2c7grp {
fsl,pins = <
- ULP1_PAD_PTF12__LPI2C7_SCL 0x527
- ULP1_PAD_PTF13__LPI2C7_SDA 0x527
+ IMX7ULP_PAD_PTF12__LPI2C7_SCL 0x27
+ IMX7ULP_PAD_PTF13__LPI2C7_SDA 0x27
>;
};
pinctrl_lpspi3: lpspi3grp {
fsl,pins = <
- ULP1_PAD_PTF16__LPSPI3_SIN 0x300
- ULP1_PAD_PTF17__LPSPI3_SOUT 0x300
- ULP1_PAD_PTF18__LPSPI3_SCK 0x300
- ULP1_PAD_PTF19__LPSPI3_PCS0 0x300
+ IMX7ULP_PAD_PTF16__LPSPI3_SIN 0x0
+ IMX7ULP_PAD_PTF17__LPSPI3_SOUT 0x0
+ IMX7ULP_PAD_PTF18__LPSPI3_SCK 0x0
+ IMX7ULP_PAD_PTF19__LPSPI3_PCS0 0x0
>;
};
- pinctrl_usb_otg1: usbotg1grp {
+ pinctrl_usbotg1_vbus: otg1vbusgrp {
fsl,pins = <
- ULP1_PAD_PTC0__PTC0 0x30100
+ IMX7ULP_PAD_PTC0__PTC0 0x20000
>;
};
- pinctrl_extcon_usb1: extcon1grp {
+ pinctrl_usbotg1_id: otg1idgrp {
fsl,pins = <
- ULP1_PAD_PTC8__PTC8 0x30103
+ IMX7ULP_PAD_PTC13__USB0_ID 0x10003
>;
};
pinctrl_usdhc1: usdhc1grp {
fsl,pins = <
- ULP1_PAD_PTE3__SDHC1_CMD 0x843
- ULP1_PAD_PTE2__SDHC1_CLK 0x843
- ULP1_PAD_PTE1__SDHC1_D0 0x843
- ULP1_PAD_PTE0__SDHC1_D1 0x843
- ULP1_PAD_PTE5__SDHC1_D2 0x843
- ULP1_PAD_PTE4__SDHC1_D3 0x843
+ IMX7ULP_PAD_PTE3__SDHC1_CMD 0x43
+ IMX7ULP_PAD_PTE2__SDHC1_CLK 0x10042
+ IMX7ULP_PAD_PTE1__SDHC1_D0 0x43
+ IMX7ULP_PAD_PTE0__SDHC1_D1 0x43
+ IMX7ULP_PAD_PTE5__SDHC1_D2 0x43
+ IMX7ULP_PAD_PTE4__SDHC1_D3 0x43
>;
};
pinctrl_usdhc1_rst: usdhc1grp_rst {
fsl,pins = <
- ULP1_PAD_PTE11__PTE11 0x30100 /* USDHC1 RST */
+ IMX7ULP_PAD_PTE11__PTE11 0x20000 /* USDHC1 RST */
+ IMX7ULP_PAD_PTE13__PTE13 0x10003 /* USDHC1 CD */
+ IMX7ULP_PAD_PTE12__PTE12 0x10003 /* USDHC1 WP */
+ IMX7ULP_PAD_PTE14__SDHC1_VS 0x43 /* USDHC1 VSEL */
>;
};
- pinctrl_wifi: wifigrp {
+ pinctrl_dsi_hdmi: dsi_hdmi_grp {
fsl,pins = <
- ULP1_PAD_PTE6__PTE6 0x43 /* WL_REG_ON */
+ IMX7ULP_PAD_PTC18__PTC18 0x10003 /* DSI_HDMI_INT */
>;
};
};
@@ -304,7 +289,7 @@
disp-dev = "mipi_dsi_northwest";
display = <&display0>;
- display0: display {
+ display0: display@0 {
bits-per-pixel = <16>;
bus-width = <24>;
@@ -343,21 +328,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpi2c5>;
status = "okay";
-
- fxas2100x@20 {
- compatible = "fsl,fxas2100x";
- reg = <0x20>;
- };
-
- fxos8700@1e {
- compatible = "fsl,fxos8700";
- reg = <0x1e>;
- };
-
- mpl3115@60 {
- compatible = "fsl,mpl3115";
- reg = <0x60>;
- };
};
&lpspi3 {
@@ -406,13 +376,18 @@
&usbotg1 {
vbus-supply = <&reg_usb_otg1_vbus>;
- extcon = <0>, <&extcon_usb1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg1_id>;
srp-disable;
hnp-disable;
adp-disable;
status = "okay";
};
+&usbphy1 {
+ fsl,tx-d-cal = <88>;
+};
+
&usdhc0 {
pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
pinctrl-0 = <&pinctrl_usdhc0>;
diff --git a/arch/arm/dts/imx7ulp-pinfunc.h b/arch/arm/dts/imx7ulp-pinfunc.h
index b1b6a71f2c..777d7f0947 100644
--- a/arch/arm/dts/imx7ulp-pinfunc.h
+++ b/arch/arm/dts/imx7ulp-pinfunc.h
@@ -1,5 +1,6 @@
/*
- * Copyright 2014 - 2015 Freescale Semiconductor, Inc.
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 - 2018 NXP
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -7,876 +8,885 @@
*
*/
-#ifndef __DTS_ULP1_PINFUNC_H
-#define __DTS_ULP1_PINFUNC_H
+#ifndef __DTS_IMX7ULP_PINFUNC_H
+#define __DTS_IMX7ULP_PINFUNC_H
/*
* The pin function ID is a tuple of
- * <mux_conf_reg mux2_reg mux_mode mux2_val>
- *
- * !!! IMPORTANT NOTE !!!
- *
- * There's common mux_reg & conf_reg register for each pad on ULP1 device, so the first
- * two values are defined as same value. Extra non-zero mux2_reg value within the tuple
- * means that there's additional mux2 control register that must be configured to
- * mux2_val accordingly to fetch desired pin functionality on ULP1 device.
- *
+ * <mux_conf_reg input_reg mux_mode input_val>
*/
+#define IMX7ULP_PAD_PTA0__CMP0_IN1_3V 0x0000 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA0__PTA0 0x0000 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA0__LPSPI0_PCS1 0x0000 0x0104 0x3 0x2
+#define IMX7ULP_PAD_PTA0__LPUART0_CTS_B 0x0000 0x01F8 0x4 0x2
+#define IMX7ULP_PAD_PTA0__LPI2C0_SCL 0x0000 0x017C 0x5 0x2
+#define IMX7ULP_PAD_PTA0__TPM0_CLKIN 0x0000 0x01A8 0x6 0x2
+#define IMX7ULP_PAD_PTA0__I2S0_RX_BCLK 0x0000 0x01B8 0x7 0x2
+#define IMX7ULP_PAD_PTA0__LLWU0_P0 0x0000 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTA1__CMP0_IN2_3V 0x0004 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA1__PTA1 0x0004 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA1__LPSPI0_PCS2 0x0004 0x0108 0x3 0x1
+#define IMX7ULP_PAD_PTA1__LPUART0_RTS_B 0x0004 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTA1__LPI2C0_SDA 0x0004 0x0180 0x5 0x1
+#define IMX7ULP_PAD_PTA1__TPM0_CH0 0x0004 0x0138 0x6 0x1
+#define IMX7ULP_PAD_PTA1__I2S0_RX_FS 0x0004 0x01BC 0x7 0x1
+#define IMX7ULP_PAD_PTA2__CMP1_IN2_3V 0x0008 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA2__PTA2 0x0008 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA2__LPSPI0_PCS3 0x0008 0x010C 0x3 0x1
+#define IMX7ULP_PAD_PTA2__LPUART0_TX 0x0008 0x0200 0x4 0x1
+#define IMX7ULP_PAD_PTA2__LPI2C0_HREQ 0x0008 0x0178 0x5 0x1
+#define IMX7ULP_PAD_PTA2__TPM0_CH1 0x0008 0x013C 0x6 0x1
+#define IMX7ULP_PAD_PTA2__I2S0_RXD0 0x0008 0x01DC 0x7 0x1
+#define IMX7ULP_PAD_PTA3__CMP1_IN4_3V 0x000C 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA3__PTA3 0x000C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA3__LPSPI0_PCS0 0x000C 0x0100 0x3 0x1
+#define IMX7ULP_PAD_PTA3__LPUART0_RX 0x000C 0x01FC 0x4 0x1
+#define IMX7ULP_PAD_PTA3__TPM0_CH2 0x000C 0x0140 0x6 0x1
+#define IMX7ULP_PAD_PTA3__I2S0_RXD1 0x000C 0x01E0 0x7 0x1
+#define IMX7ULP_PAD_PTA3__CMP0_OUT 0x000C 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTA3__LLWU0_P1 0x000C 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTA4__ADC1_CH3A 0x0010 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA4__PTA4 0x0010 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA4__LPSPI0_SIN 0x0010 0x0114 0x3 0x1
+#define IMX7ULP_PAD_PTA4__LPUART1_CTS_B 0x0010 0x0204 0x4 0x1
+#define IMX7ULP_PAD_PTA4__LPI2C1_SCL 0x0010 0x0188 0x5 0x1
+#define IMX7ULP_PAD_PTA4__TPM0_CH3 0x0010 0x0144 0x6 0x1
+#define IMX7ULP_PAD_PTA4__I2S0_MCLK 0x0010 0x01B4 0x7 0x1
+#define IMX7ULP_PAD_PTA5__ADC1_CH3B 0x0014 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA5__PTA5 0x0014 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA5__LPSPI0_SOUT 0x0014 0x0118 0x3 0x1
+#define IMX7ULP_PAD_PTA5__LPUART1_RTS_B 0x0014 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTA5__LPI2C1_SDA 0x0014 0x018C 0x5 0x1
+#define IMX7ULP_PAD_PTA5__TPM0_CH4 0x0014 0x0148 0x6 0x1
+#define IMX7ULP_PAD_PTA5__I2S0_TX_BCLK 0x0014 0x01C0 0x7 0x1
+#define IMX7ULP_PAD_PTA6__ADC1_CH4A 0x0018 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA6__PTA6 0x0018 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA6__LPSPI0_SCK 0x0018 0x0110 0x3 0x1
+#define IMX7ULP_PAD_PTA6__LPUART1_TX 0x0018 0x020C 0x4 0x1
+#define IMX7ULP_PAD_PTA6__LPI2C1_HREQ 0x0018 0x0184 0x5 0x1
+#define IMX7ULP_PAD_PTA6__TPM0_CH5 0x0018 0x014C 0x6 0x1
+#define IMX7ULP_PAD_PTA6__I2S0_TX_FS 0x0018 0x01C4 0x7 0x1
+#define IMX7ULP_PAD_PTA7__ADC1_CH4B 0x001C 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA7__PTA7 0x001C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA7__LPUART1_RX 0x001C 0x0208 0x4 0x1
+#define IMX7ULP_PAD_PTA7__TPM1_CH1 0x001C 0x0154 0x6 0x1
+#define IMX7ULP_PAD_PTA7__I2S0_TXD0 0x001C 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTA8__ADC1_CH5A 0x0020 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA8__PTA8 0x0020 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA8__LPSPI1_PCS1 0x0020 0x0120 0x3 0x1
+#define IMX7ULP_PAD_PTA8__LPUART2_CTS_B 0x0020 0x0210 0x4 0x1
+#define IMX7ULP_PAD_PTA8__LPI2C2_SCL 0x0020 0x0194 0x5 0x1
+#define IMX7ULP_PAD_PTA8__TPM1_CLKIN 0x0020 0x01AC 0x6 0x1
+#define IMX7ULP_PAD_PTA8__I2S0_TXD1 0x0020 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTA9__ADC1_CH5B 0x0024 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA9__PTA9 0x0024 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA9__LPSPI1_PCS2 0x0024 0x0124 0x3 0x1
+#define IMX7ULP_PAD_PTA9__LPUART2_RTS_B 0x0024 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTA9__LPI2C2_SDA 0x0024 0x0198 0x5 0x1
+#define IMX7ULP_PAD_PTA9__TPM1_CH0 0x0024 0x0150 0x6 0x1
+#define IMX7ULP_PAD_PTA9__NMI0_B 0x0024 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTA10__ADC1_CH6A 0x0028 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA10__PTA10 0x0028 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA10__LPSPI1_PCS3 0x0028 0x0128 0x3 0x1
+#define IMX7ULP_PAD_PTA10__LPUART2_TX 0x0028 0x0218 0x4 0x1
+#define IMX7ULP_PAD_PTA10__LPI2C2_HREQ 0x0028 0x0190 0x5 0x1
+#define IMX7ULP_PAD_PTA10__TPM2_CLKIN 0x0028 0x01F4 0x6 0x1
+#define IMX7ULP_PAD_PTA10__I2S0_RX_BCLK 0x0028 0x01B8 0x7 0x1
+#define IMX7ULP_PAD_PTA11__ADC1_CH6B 0x002C 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA11__PTA11 0x002C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA11__LPUART2_RX 0x002C 0x0214 0x4 0x1
+#define IMX7ULP_PAD_PTA11__TPM2_CH0 0x002C 0x0158 0x6 0x1
+#define IMX7ULP_PAD_PTA11__I2S0_RX_FS 0x002C 0x01BC 0x7 0x2
+#define IMX7ULP_PAD_PTA12__ADC1_CH7A 0x0030 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA12__PTA12 0x0030 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA12__LPSPI1_SIN 0x0030 0x0130 0x3 0x1
+#define IMX7ULP_PAD_PTA12__LPUART3_CTS_B 0x0030 0x021C 0x4 0x1
+#define IMX7ULP_PAD_PTA12__LPI2C3_SCL 0x0030 0x01A0 0x5 0x1
+#define IMX7ULP_PAD_PTA12__TPM2_CH1 0x0030 0x015C 0x6 0x1
+#define IMX7ULP_PAD_PTA12__I2S0_RXD0 0x0030 0x01DC 0x7 0x2
+#define IMX7ULP_PAD_PTA13__ADC1_CH7B 0x0034 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA13__PTA13 0x0034 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA13__LPSPI1_SOUT 0x0034 0x0134 0x3 0x2
+#define IMX7ULP_PAD_PTA13__LPUART3_RTS_B 0x0034 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTA13__LPI2C3_SDA 0x0034 0x01A4 0x5 0x2
+#define IMX7ULP_PAD_PTA13__TPM3_CLKIN 0x0034 0x01B0 0x6 0x1
+#define IMX7ULP_PAD_PTA13__I2S0_RXD1 0x0034 0x01E0 0x7 0x2
+#define IMX7ULP_PAD_PTA13__CMP0_OUT 0x0034 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTA13__LLWU0_P2 0x0034 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTA14__ADC1_CH8A 0x0038 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA14__PTA14 0x0038 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA14__LPSPI1_SCK 0x0038 0x012C 0x3 0x2
+#define IMX7ULP_PAD_PTA14__LPUART3_TX 0x0038 0x0224 0x4 0x2
+#define IMX7ULP_PAD_PTA14__LPI2C3_HREQ 0x0038 0x019C 0x5 0x2
+#define IMX7ULP_PAD_PTA14__TPM3_CH0 0x0038 0x0160 0x6 0x1
+#define IMX7ULP_PAD_PTA14__I2S0_MCLK 0x0038 0x01B4 0x7 0x2
+#define IMX7ULP_PAD_PTA14__LLWU0_P3 0x0038 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTA15__ADC1_CH8B 0x003C 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA15__PTA15 0x003C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA15__LPSPI1_PCS0 0x003C 0x011C 0x3 0x1
+#define IMX7ULP_PAD_PTA15__LPUART3_RX 0x003C 0x0220 0x4 0x1
+#define IMX7ULP_PAD_PTA15__TPM3_CH1 0x003C 0x0164 0x6 0x1
+#define IMX7ULP_PAD_PTA15__I2S0_TX_BCLK 0x003C 0x01C0 0x7 0x2
+#define IMX7ULP_PAD_PTA16__CMP1_IN5_3V 0x0040 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA16__PTA16 0x0040 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA16__FXIO0_D0 0x0040 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA16__LPSPI0_SOUT 0x0040 0x0118 0x3 0x2
+#define IMX7ULP_PAD_PTA16__LPUART0_CTS_B 0x0040 0x01F8 0x4 0x1
+#define IMX7ULP_PAD_PTA16__LPI2C0_SCL 0x0040 0x017C 0x5 0x1
+#define IMX7ULP_PAD_PTA16__TPM3_CH2 0x0040 0x0168 0x6 0x1
+#define IMX7ULP_PAD_PTA16__I2S0_TX_FS 0x0040 0x01C4 0x7 0x2
+#define IMX7ULP_PAD_PTA17__CMP1_IN6_3V 0x0044 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA17__PTA17 0x0044 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA17__FXIO0_D1 0x0044 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA17__LPSPI0_SCK 0x0044 0x0110 0x3 0x2
+#define IMX7ULP_PAD_PTA17__LPUART0_RTS_B 0x0044 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTA17__LPI2C0_SDA 0x0044 0x0180 0x5 0x2
+#define IMX7ULP_PAD_PTA17__TPM3_CH3 0x0044 0x016C 0x6 0x1
+#define IMX7ULP_PAD_PTA17__I2S0_TXD0 0x0044 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTA18__CMP1_IN1_3V 0x0048 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA18__PTA18 0x0048 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA18__FXIO0_D2 0x0048 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA18__LPSPI0_PCS0 0x0048 0x0100 0x3 0x2
+#define IMX7ULP_PAD_PTA18__LPUART0_TX 0x0048 0x0200 0x4 0x2
+#define IMX7ULP_PAD_PTA18__LPI2C0_HREQ 0x0048 0x0178 0x5 0x2
+#define IMX7ULP_PAD_PTA18__TPM3_CH4 0x0048 0x0170 0x6 0x1
+#define IMX7ULP_PAD_PTA18__I2S0_TXD1 0x0048 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTA18__LLWU0_P4 0x0048 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTA19__CMP1_IN3_3V 0x004C 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA19__PTA19 0x004C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA19__FXIO0_D3 0x004C 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA19__LPUART0_RX 0x004C 0x01FC 0x4 0x2
+#define IMX7ULP_PAD_PTA19__TPM3_CH5 0x004C 0x0174 0x6 0x1
+#define IMX7ULP_PAD_PTA19__I2S1_RX_BCLK 0x004C 0x01CC 0x7 0x1
+#define IMX7ULP_PAD_PTA19__LPTMR0_ALT3 0x004C 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTA19__LLWU0_P5 0x004C 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTA20__ADC0_CH10A 0x0050 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA20__PTA20 0x0050 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA20__FXIO0_D4 0x0050 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA20__LPSPI0_SIN 0x0050 0x0114 0x3 0x2
+#define IMX7ULP_PAD_PTA20__LPUART1_CTS_B 0x0050 0x0204 0x4 0x2
+#define IMX7ULP_PAD_PTA20__LPI2C1_SCL 0x0050 0x0188 0x5 0x2
+#define IMX7ULP_PAD_PTA20__TPM0_CLKIN 0x0050 0x01A8 0x6 0x1
+#define IMX7ULP_PAD_PTA20__I2S1_RX_FS 0x0050 0x01D0 0x7 0x1
+#define IMX7ULP_PAD_PTA21__ADC0_CH10B 0x0054 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA21__PTA21 0x0054 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA21__FXIO0_D5 0x0054 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA21__LPSPI0_PCS1 0x0054 0x0104 0x3 0x1
+#define IMX7ULP_PAD_PTA21__LPUART1_RTS_B 0x0054 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTA21__LPI2C1_SDA 0x0054 0x018C 0x5 0x2
+#define IMX7ULP_PAD_PTA21__TPM0_CH0 0x0054 0x0138 0x6 0x2
+#define IMX7ULP_PAD_PTA21__I2S1_RXD0 0x0054 0x01E4 0x7 0x1
+#define IMX7ULP_PAD_PTA22__ADC0_CH9A 0x0058 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA22__PTA22 0x0058 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA22__FXIO0_D6 0x0058 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA22__LPSPI0_PCS2 0x0058 0x0108 0x3 0x2
+#define IMX7ULP_PAD_PTA22__LPUART1_TX 0x0058 0x020C 0x4 0x2
+#define IMX7ULP_PAD_PTA22__LPI2C1_HREQ 0x0058 0x0184 0x5 0x2
+#define IMX7ULP_PAD_PTA22__TPM0_CH1 0x0058 0x013C 0x6 0x2
+#define IMX7ULP_PAD_PTA22__I2S1_RXD1 0x0058 0x01E8 0x7 0x1
+#define IMX7ULP_PAD_PTA22__LPTMR0_ALT2 0x0058 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTA22__EWM_OUT_B 0x0058 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTA23__ADC0_CH9B 0x005C 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA23__PTA23 0x005C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA23__FXIO0_D7 0x005C 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA23__LPSPI0_PCS3 0x005C 0x010C 0x3 0x2
+#define IMX7ULP_PAD_PTA23__LPUART1_RX 0x005C 0x0208 0x4 0x2
+#define IMX7ULP_PAD_PTA23__TPM0_CH2 0x005C 0x0140 0x6 0x2
+#define IMX7ULP_PAD_PTA23__I2S1_MCLK 0x005C 0x01C8 0x7 0x1
+#define IMX7ULP_PAD_PTA23__LLWU0_P6 0x005C 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTA24__ADC0_CH8A 0x0060 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA24__PTA24 0x0060 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA24__FXIO0_D8 0x0060 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA24__LPSPI1_PCS1 0x0060 0x0120 0x3 0x2
+#define IMX7ULP_PAD_PTA24__LPUART2_CTS_B 0x0060 0x0210 0x4 0x2
+#define IMX7ULP_PAD_PTA24__LPI2C2_SCL 0x0060 0x0194 0x5 0x2
+#define IMX7ULP_PAD_PTA24__TPM0_CH3 0x0060 0x0144 0x6 0x2
+#define IMX7ULP_PAD_PTA24__I2S1_TX_BCLK 0x0060 0x01D4 0x7 0x1
+#define IMX7ULP_PAD_PTA25__ADC0_CH8B 0x0064 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA25__PTA25 0x0064 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA25__FXIO0_D9 0x0064 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA25__LPSPI1_PCS2 0x0064 0x0124 0x3 0x2
+#define IMX7ULP_PAD_PTA25__LPUART2_RTS_B 0x0064 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTA25__LPI2C2_SDA 0x0064 0x0198 0x5 0x2
+#define IMX7ULP_PAD_PTA25__TPM0_CH4 0x0064 0x0148 0x6 0x2
+#define IMX7ULP_PAD_PTA25__I2S1_TX_FS 0x0064 0x01D8 0x7 0x1
+#define IMX7ULP_PAD_PTA26__PTA26 0x0068 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA26__JTAG_TMS_SWD_DIO 0x0068 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTA26__FXIO0_D10 0x0068 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA26__LPSPI1_PCS3 0x0068 0x0128 0x3 0x2
+#define IMX7ULP_PAD_PTA26__LPUART2_TX 0x0068 0x0218 0x4 0x2
+#define IMX7ULP_PAD_PTA26__LPI2C2_HREQ 0x0068 0x0190 0x5 0x2
+#define IMX7ULP_PAD_PTA26__TPM0_CH5 0x0068 0x014C 0x6 0x2
+#define IMX7ULP_PAD_PTA26__I2S1_RXD2 0x0068 0x01EC 0x7 0x1
+#define IMX7ULP_PAD_PTA27__PTA27 0x006C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA27__JTAG_TDO 0x006C 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTA27__FXIO0_D11 0x006C 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA27__LPUART2_RX 0x006C 0x0214 0x4 0x2
+#define IMX7ULP_PAD_PTA27__TPM1_CH1 0x006C 0x0154 0x6 0x2
+#define IMX7ULP_PAD_PTA27__I2S1_RXD3 0x006C 0x01F0 0x7 0x1
+#define IMX7ULP_PAD_PTA28__PTA28 0x0070 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA28__JTAG_TDI 0x0070 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTA28__FXIO0_D12 0x0070 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA28__LPSPI1_SIN 0x0070 0x0130 0x3 0x2
+#define IMX7ULP_PAD_PTA28__LPUART3_CTS_B 0x0070 0x021C 0x4 0x2
+#define IMX7ULP_PAD_PTA28__LPI2C3_SCL 0x0070 0x01A0 0x5 0x2
+#define IMX7ULP_PAD_PTA28__TPM1_CLKIN 0x0070 0x01AC 0x6 0x2
+#define IMX7ULP_PAD_PTA28__I2S1_TXD2 0x0070 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTA29__PTA29 0x0074 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA29__JTAG_TCLK_SWD_CLK 0x0074 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTA29__FXIO0_D13 0x0074 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA29__LPSPI1_SOUT 0x0074 0x0134 0x3 0x1
+#define IMX7ULP_PAD_PTA29__LPUART3_RTS_B 0x0074 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTA29__LPI2C3_SDA 0x0074 0x01A4 0x5 0x1
+#define IMX7ULP_PAD_PTA29__TPM1_CH0 0x0074 0x0150 0x6 0x2
+#define IMX7ULP_PAD_PTA29__I2S1_TXD3 0x0074 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTA30__ADC0_CH1A 0x0078 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA30__PTA30 0x0078 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA30__FXIO0_D14 0x0078 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA30__LPSPI1_SCK 0x0078 0x012C 0x3 0x1
+#define IMX7ULP_PAD_PTA30__LPUART3_TX 0x0078 0x0224 0x4 0x1
+#define IMX7ULP_PAD_PTA30__LPI2C3_HREQ 0x0078 0x019C 0x5 0x1
+#define IMX7ULP_PAD_PTA30__TPM2_CLKIN 0x0078 0x01F4 0x6 0x2
+#define IMX7ULP_PAD_PTA30__I2S1_TXD0 0x0078 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTA30__JTAG_TRST_B 0x0078 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTA31__ADC0_CH1B 0x007C 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTA31__PTA31 0x007C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTA31__FXIO0_D15 0x007C 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTA31__LPSPI1_PCS0 0x007C 0x011C 0x3 0x2
+#define IMX7ULP_PAD_PTA31__LPUART3_RX 0x007C 0x0220 0x4 0x2
+#define IMX7ULP_PAD_PTA31__TPM2_CH0 0x007C 0x0158 0x6 0x2
+#define IMX7ULP_PAD_PTA31__I2S1_TXD1 0x007C 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTA31__LPTMR0_ALT1 0x007C 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTA31__EWM_IN 0x007C 0x0228 0xc 0x1
+#define IMX7ULP_PAD_PTA31__LLWU0_P7 0x007C 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTB0__ADC0_CH0A 0x0080 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB0__PTB0 0x0080 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB0__FXIO0_D16 0x0080 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB0__LPSPI0_SIN 0x0080 0x0114 0x3 0x3
+#define IMX7ULP_PAD_PTB0__LPUART0_TX 0x0080 0x0200 0x4 0x3
+#define IMX7ULP_PAD_PTB0__TPM2_CH1 0x0080 0x015C 0x6 0x2
+#define IMX7ULP_PAD_PTB0__CLKOUT0 0x0080 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTB0__CMP1_OUT 0x0080 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTB0__EWM_OUT_B 0x0080 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTB1__ADC0_CH0B 0x0084 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB1__PTB1 0x0084 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB1__FXIO0_D17 0x0084 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB1__LPSPI0_SOUT 0x0084 0x0118 0x3 0x3
+#define IMX7ULP_PAD_PTB1__LPUART0_RX 0x0084 0x01FC 0x4 0x3
+#define IMX7ULP_PAD_PTB1__TPM3_CLKIN 0x0084 0x01B0 0x6 0x3
+#define IMX7ULP_PAD_PTB1__I2S1_TX_BCLK 0x0084 0x01D4 0x7 0x2
+#define IMX7ULP_PAD_PTB1__RTC_CLKOUT 0x0084 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTB1__EWM_IN 0x0084 0x0228 0xc 0x2
+#define IMX7ULP_PAD_PTB1__LLWU0_P8 0x0084 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTB2__ADC0_CH6A 0x0088 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB2__PTB2 0x0088 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB2__FXIO0_D18 0x0088 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB2__LPSPI0_SCK 0x0088 0x0110 0x3 0x3
+#define IMX7ULP_PAD_PTB2__LPUART1_TX 0x0088 0x020C 0x4 0x3
+#define IMX7ULP_PAD_PTB2__TPM3_CH0 0x0088 0x0160 0x6 0x2
+#define IMX7ULP_PAD_PTB2__I2S1_TX_FS 0x0088 0x01D8 0x7 0x2
+#define IMX7ULP_PAD_PTB2__TRACE_CLKOUT 0x0088 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTB3__ADC0_CH6B 0x008C 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB3__PTB3 0x008C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB3__FXIO0_D19 0x008C 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB3__LPSPI0_PCS0 0x008C 0x0100 0x3 0x3
+#define IMX7ULP_PAD_PTB3__LPUART1_RX 0x008C 0x0208 0x4 0x3
+#define IMX7ULP_PAD_PTB3__TPM3_CH1 0x008C 0x0164 0x6 0x2
+#define IMX7ULP_PAD_PTB3__I2S1_TXD0 0x008C 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTB3__TRACE_D0 0x008C 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTB3__LPTMR1_ALT2 0x008C 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTB3__LLWU0_P9 0x008C 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTB4__PTB4 0x0090 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB4__FXIO0_D20 0x0090 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB4__LPSPI0_PCS1 0x0090 0x0104 0x3 0x3
+#define IMX7ULP_PAD_PTB4__LPUART2_TX 0x0090 0x0218 0x4 0x3
+#define IMX7ULP_PAD_PTB4__LPI2C0_HREQ 0x0090 0x0178 0x5 0x3
+#define IMX7ULP_PAD_PTB4__TPM3_CH2 0x0090 0x0168 0x6 0x2
+#define IMX7ULP_PAD_PTB4__I2S1_TXD1 0x0090 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTB4__QSPIA_DATA7 0x0090 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB4__TRACE_D1 0x0090 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTB4__SEC_VIO_B 0x0090 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTB5__PTB5 0x0094 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB5__FXIO0_D21 0x0094 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB5__LPSPI0_PCS2 0x0094 0x0108 0x3 0x3
+#define IMX7ULP_PAD_PTB5__LPUART2_RX 0x0094 0x0214 0x4 0x3
+#define IMX7ULP_PAD_PTB5__LPI2C1_HREQ 0x0094 0x0184 0x5 0x3
+#define IMX7ULP_PAD_PTB5__TPM3_CH3 0x0094 0x016C 0x6 0x2
+#define IMX7ULP_PAD_PTB5__I2S1_TXD2 0x0094 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTB5__QSPIA_DATA6 0x0094 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB5__TRACE_D2 0x0094 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTB5__RTC_CLKOUT 0x0094 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTB6__ADC1_CH1A 0x0098 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB6__PTB6 0x0098 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB6__FXIO0_D22 0x0098 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB6__LPSPI0_PCS3 0x0098 0x010C 0x3 0x3
+#define IMX7ULP_PAD_PTB6__LPUART3_TX 0x0098 0x0224 0x4 0x3
+#define IMX7ULP_PAD_PTB6__LPI2C0_SCL 0x0098 0x017C 0x5 0x3
+#define IMX7ULP_PAD_PTB6__TPM3_CH4 0x0098 0x0170 0x6 0x2
+#define IMX7ULP_PAD_PTB6__I2S1_TXD3 0x0098 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTB6__QSPIA_DATA5 0x0098 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB6__TRACE_D3 0x0098 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTB6__LPTMR1_ALT3 0x0098 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTB6__LLWU0_P10 0x0098 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTB7__ADC1_CH1B 0x009C 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB7__PTB7 0x009C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB7__FXIO0_D23 0x009C 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB7__LPSPI1_SIN 0x009C 0x0130 0x3 0x3
+#define IMX7ULP_PAD_PTB7__LPUART3_RX 0x009C 0x0220 0x4 0x3
+#define IMX7ULP_PAD_PTB7__LPI2C0_SDA 0x009C 0x0180 0x5 0x3
+#define IMX7ULP_PAD_PTB7__TPM3_CH5 0x009C 0x0174 0x6 0x2
+#define IMX7ULP_PAD_PTB7__I2S1_MCLK 0x009C 0x01C8 0x7 0x2
+#define IMX7ULP_PAD_PTB7__QSPIA_SS1_B 0x009C 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB7__CMP1_OUT 0x009C 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTB7__LLWU0_P11 0x009C 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTB8__ADC0_CH14A_CMP0_IN0 0x00A0 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB8__PTB8 0x00A0 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB8__FXIO0_D24 0x00A0 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB8__LPSPI1_SOUT 0x00A0 0x0134 0x3 0x3
+#define IMX7ULP_PAD_PTB8__LPI2C1_SCL 0x00A0 0x0188 0x5 0x3
+#define IMX7ULP_PAD_PTB8__TPM0_CLKIN 0x00A0 0x01A8 0x6 0x3
+#define IMX7ULP_PAD_PTB8__I2S1_RX_BCLK 0x00A0 0x01CC 0x7 0x2
+#define IMX7ULP_PAD_PTB8__QSPIA_SS0_B 0x00A0 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB8__RTC_CLKOUT 0x00A0 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTB9__ADC0_CH14B_CMP0_IN2 0x00A4 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB9__PTB9 0x00A4 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB9__FXIO0_D25 0x00A4 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB9__LPSPI1_SCK 0x00A4 0x012C 0x3 0x3
+#define IMX7ULP_PAD_PTB9__LPI2C1_SDA 0x00A4 0x018C 0x5 0x3
+#define IMX7ULP_PAD_PTB9__TPM0_CH0 0x00A4 0x0138 0x6 0x3
+#define IMX7ULP_PAD_PTB9__I2S1_RX_FS 0x00A4 0x01D0 0x7 0x2
+#define IMX7ULP_PAD_PTB9__QSPIA_DQS 0x00A4 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB9__LLWU0_P12 0x00A4 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTB10__CMP0_IN1 0x00A8 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB10__PTB10 0x00A8 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB10__FXIO0_D26 0x00A8 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB10__LPSPI1_PCS0 0x00A8 0x011C 0x3 0x3
+#define IMX7ULP_PAD_PTB10__LPI2C2_SCL 0x00A8 0x0194 0x5 0x3
+#define IMX7ULP_PAD_PTB10__TPM0_CH1 0x00A8 0x013C 0x6 0x3
+#define IMX7ULP_PAD_PTB10__I2S1_RXD0 0x00A8 0x01E4 0x7 0x2
+#define IMX7ULP_PAD_PTB10__TRACE_D4 0x00A8 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTB11__CMP0_IN3 0x00AC 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB11__PTB11 0x00AC 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB11__FXIO0_D27 0x00AC 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB11__LPSPI1_PCS1 0x00AC 0x0120 0x3 0x3
+#define IMX7ULP_PAD_PTB11__LPI2C2_SDA 0x00AC 0x0198 0x5 0x3
+#define IMX7ULP_PAD_PTB11__TPM1_CLKIN 0x00AC 0x01AC 0x6 0x3
+#define IMX7ULP_PAD_PTB11__I2S1_RXD1 0x00AC 0x01E8 0x7 0x2
+#define IMX7ULP_PAD_PTB11__TRACE_D5 0x00AC 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTB12__ADC1_CH13A_CMP1_IN0 0x00B0 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB12__PTB12 0x00B0 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB12__FXIO0_D28 0x00B0 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB12__LPSPI1_PCS2 0x00B0 0x0124 0x3 0x3
+#define IMX7ULP_PAD_PTB12__LPUART2_TX 0x00B0 0x0218 0x4 0x4
+#define IMX7ULP_PAD_PTB12__LPI2C3_SCL 0x00B0 0x01A0 0x5 0x3
+#define IMX7ULP_PAD_PTB12__TPM1_CH0 0x00B0 0x0150 0x6 0x3
+#define IMX7ULP_PAD_PTB12__I2S1_RXD2 0x00B0 0x01EC 0x7 0x2
+#define IMX7ULP_PAD_PTB12__TRACE_D6 0x00B0 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTB13__ADC1_CH13B_CMP1_IN1 0x00B4 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB13__PTB13 0x00B4 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB13__FXIO0_D29 0x00B4 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB13__LPSPI1_PCS3 0x00B4 0x0128 0x3 0x3
+#define IMX7ULP_PAD_PTB13__LPUART2_RX 0x00B4 0x0214 0x4 0x4
+#define IMX7ULP_PAD_PTB13__LPI2C3_SDA 0x00B4 0x01A4 0x5 0x3
+#define IMX7ULP_PAD_PTB13__TPM1_CH1 0x00B4 0x0154 0x6 0x3
+#define IMX7ULP_PAD_PTB13__I2S1_RXD3 0x00B4 0x01F0 0x7 0x2
+#define IMX7ULP_PAD_PTB13__QSPIA_DATA4 0x00B4 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB13__TRACE_D7 0x00B4 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTB14__ADC1_CH2A 0x00B8 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB14__PTB14 0x00B8 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB14__FXIO0_D30 0x00B8 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB14__LPI2C2_HREQ 0x00B8 0x0190 0x5 0x3
+#define IMX7ULP_PAD_PTB14__TPM2_CLKIN 0x00B8 0x01F4 0x6 0x3
+#define IMX7ULP_PAD_PTB14__QSPIA_SS1_B 0x00B8 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB14__QSPIA_SCLK_B 0x00B8 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTB14__RTC_CLKOUT 0x00B8 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTB14__LLWU0_P13 0x00B8 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTB15__ADC1_CH2B 0x00BC 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB15__PTB15 0x00BC 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB15__FXIO0_D31 0x00BC 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTB15__LPI2C3_HREQ 0x00BC 0x019C 0x5 0x3
+#define IMX7ULP_PAD_PTB15__TPM2_CH0 0x00BC 0x0158 0x6 0x3
+#define IMX7ULP_PAD_PTB15__QSPIA_SCLK 0x00BC 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB16__ADC0_CH4A 0x00C0 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB16__PTB16 0x00C0 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB16__TPM2_CH1 0x00C0 0x015C 0x6 0x3
+#define IMX7ULP_PAD_PTB16__QSPIA_DATA3 0x00C0 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB16__LLWU0_P14 0x00C0 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTB17__ADC0_CH4B 0x00C4 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB17__PTB17 0x00C4 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB17__TPM3_CLKIN 0x00C4 0x01B0 0x6 0x2
+#define IMX7ULP_PAD_PTB17__QSPIA_DATA2 0x00C4 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB18__ADC0_CH5A 0x00C8 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB18__PTB18 0x00C8 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB18__TPM3_CH0 0x00C8 0x0160 0x6 0x3
+#define IMX7ULP_PAD_PTB18__QSPIA_DATA1 0x00C8 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB19__ADC0_CH5B 0x00CC 0x0000 0x0 0x0
+#define IMX7ULP_PAD_PTB19__PTB19 0x00CC 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTB19__TPM3_CH1 0x00CC 0x0164 0x6 0x3
+#define IMX7ULP_PAD_PTB19__QSPIA_DATA0 0x00CC 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTB19__USB0_ID 0x00CC 0x0338 0xa 0x0
+#define IMX7ULP_PAD_PTB19__LLWU0_P15 0x00CC 0x0000 0xd 0x0
+#define IMX7ULP_PAD_PTC0__PTC0 0x0000 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC0__LPUART4_CTS_B 0x0000 0x0244 0x4 0x1
+#define IMX7ULP_PAD_PTC0__LPI2C4_SCL 0x0000 0x0278 0x5 0x1
+#define IMX7ULP_PAD_PTC0__TPM4_CLKIN 0x0000 0x0298 0x6 0x1
+#define IMX7ULP_PAD_PTC0__FB_AD0 0x0000 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC0__TRACE_D15 0x0000 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC1__PTC1 0x0004 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC1__LPUART4_RTS_B 0x0004 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTC1__LPI2C4_SDA 0x0004 0x027C 0x5 0x1
+#define IMX7ULP_PAD_PTC1__TPM4_CH0 0x0004 0x0280 0x6 0x1
+#define IMX7ULP_PAD_PTC1__FB_AD1 0x0004 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC1__TRACE_D14 0x0004 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC2__PTC2 0x0008 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC2__LPUART4_TX 0x0008 0x024C 0x4 0x1
+#define IMX7ULP_PAD_PTC2__LPI2C4_HREQ 0x0008 0x0274 0x5 0x1
+#define IMX7ULP_PAD_PTC2__TPM4_CH1 0x0008 0x0284 0x6 0x1
+#define IMX7ULP_PAD_PTC2__FB_AD2 0x0008 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC2__TRACE_D13 0x0008 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC3__PTC3 0x000C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC3__LPUART4_RX 0x000C 0x0248 0x4 0x1
+#define IMX7ULP_PAD_PTC3__TPM4_CH2 0x000C 0x0288 0x6 0x1
+#define IMX7ULP_PAD_PTC3__FB_AD3 0x000C 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC3__TRACE_D12 0x000C 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC4__PTC4 0x0010 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC4__FXIO1_D0 0x0010 0x0204 0x2 0x1
+#define IMX7ULP_PAD_PTC4__LPSPI2_PCS1 0x0010 0x02A0 0x3 0x1
+#define IMX7ULP_PAD_PTC4__LPUART5_CTS_B 0x0010 0x0250 0x4 0x1
+#define IMX7ULP_PAD_PTC4__LPI2C5_SCL 0x0010 0x02BC 0x5 0x1
+#define IMX7ULP_PAD_PTC4__TPM4_CH3 0x0010 0x028C 0x6 0x1
+#define IMX7ULP_PAD_PTC4__FB_AD4 0x0010 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC4__TRACE_D11 0x0010 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC5__PTC5 0x0014 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC5__FXIO1_D1 0x0014 0x0208 0x2 0x1
+#define IMX7ULP_PAD_PTC5__LPSPI2_PCS2 0x0014 0x02A4 0x3 0x1
+#define IMX7ULP_PAD_PTC5__LPUART5_RTS_B 0x0014 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTC5__LPI2C5_SDA 0x0014 0x02C0 0x5 0x1
+#define IMX7ULP_PAD_PTC5__TPM4_CH4 0x0014 0x0290 0x6 0x1
+#define IMX7ULP_PAD_PTC5__FB_AD5 0x0014 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC5__TRACE_D10 0x0014 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC6__PTC6 0x0018 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC6__FXIO1_D2 0x0018 0x020C 0x2 0x1
+#define IMX7ULP_PAD_PTC6__LPSPI2_PCS3 0x0018 0x02A8 0x3 0x1
+#define IMX7ULP_PAD_PTC6__LPUART5_TX 0x0018 0x0258 0x4 0x1
+#define IMX7ULP_PAD_PTC6__LPI2C5_HREQ 0x0018 0x02B8 0x5 0x1
+#define IMX7ULP_PAD_PTC6__TPM4_CH5 0x0018 0x0294 0x6 0x1
+#define IMX7ULP_PAD_PTC6__FB_AD6 0x0018 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC6__TRACE_D9 0x0018 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC7__PTC7 0x001C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC7__FXIO1_D3 0x001C 0x0210 0x2 0x1
+#define IMX7ULP_PAD_PTC7__LPUART5_RX 0x001C 0x0254 0x4 0x1
+#define IMX7ULP_PAD_PTC7__TPM5_CH1 0x001C 0x02C8 0x6 0x1
+#define IMX7ULP_PAD_PTC7__FB_AD7 0x001C 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC7__TRACE_D8 0x001C 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC8__PTC8 0x0020 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC8__FXIO1_D4 0x0020 0x0214 0x2 0x1
+#define IMX7ULP_PAD_PTC8__LPSPI2_SIN 0x0020 0x02B0 0x3 0x1
+#define IMX7ULP_PAD_PTC8__LPUART6_CTS_B 0x0020 0x025C 0x4 0x1
+#define IMX7ULP_PAD_PTC8__LPI2C6_SCL 0x0020 0x02FC 0x5 0x1
+#define IMX7ULP_PAD_PTC8__TPM5_CLKIN 0x0020 0x02CC 0x6 0x1
+#define IMX7ULP_PAD_PTC8__FB_AD8 0x0020 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC8__TRACE_D7 0x0020 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC9__PTC9 0x0024 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC9__FXIO1_D5 0x0024 0x0218 0x2 0x1
+#define IMX7ULP_PAD_PTC9__LPSPI2_SOUT 0x0024 0x02B4 0x3 0x1
+#define IMX7ULP_PAD_PTC9__LPUART6_RTS_B 0x0024 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTC9__LPI2C6_SDA 0x0024 0x0300 0x5 0x1
+#define IMX7ULP_PAD_PTC9__TPM5_CH0 0x0024 0x02C4 0x6 0x1
+#define IMX7ULP_PAD_PTC9__FB_AD9 0x0024 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC9__TRACE_D6 0x0024 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC10__PTC10 0x0028 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC10__FXIO1_D6 0x0028 0x021C 0x2 0x1
+#define IMX7ULP_PAD_PTC10__LPSPI2_SCK 0x0028 0x02AC 0x3 0x1
+#define IMX7ULP_PAD_PTC10__LPUART6_TX 0x0028 0x0264 0x4 0x1
+#define IMX7ULP_PAD_PTC10__LPI2C6_HREQ 0x0028 0x02F8 0x5 0x1
+#define IMX7ULP_PAD_PTC10__TPM7_CH3 0x0028 0x02E8 0x6 0x1
+#define IMX7ULP_PAD_PTC10__FB_AD10 0x0028 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC10__TRACE_D5 0x0028 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC11__PTC11 0x002C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC11__FXIO1_D7 0x002C 0x0220 0x2 0x1
+#define IMX7ULP_PAD_PTC11__LPSPI2_PCS0 0x002C 0x029C 0x3 0x1
+#define IMX7ULP_PAD_PTC11__LPUART6_RX 0x002C 0x0260 0x4 0x1
+#define IMX7ULP_PAD_PTC11__TPM7_CH4 0x002C 0x02EC 0x6 0x1
+#define IMX7ULP_PAD_PTC11__FB_AD11 0x002C 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC11__TRACE_D4 0x002C 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC12__PTC12 0x0030 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC12__FXIO1_D8 0x0030 0x0224 0x2 0x1
+#define IMX7ULP_PAD_PTC12__LPSPI3_PCS1 0x0030 0x0314 0x3 0x1
+#define IMX7ULP_PAD_PTC12__LPUART7_CTS_B 0x0030 0x0268 0x4 0x1
+#define IMX7ULP_PAD_PTC12__LPI2C7_SCL 0x0030 0x0308 0x5 0x1
+#define IMX7ULP_PAD_PTC12__TPM7_CH5 0x0030 0x02F0 0x6 0x1
+#define IMX7ULP_PAD_PTC12__FB_AD12 0x0030 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC12__TRACE_D3 0x0030 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC13__PTC13 0x0034 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC13__FXIO1_D9 0x0034 0x0228 0x2 0x1
+#define IMX7ULP_PAD_PTC13__LPSPI3_PCS2 0x0034 0x0318 0x3 0x1
+#define IMX7ULP_PAD_PTC13__LPUART7_RTS_B 0x0034 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTC13__LPI2C7_SDA 0x0034 0x030C 0x5 0x1
+#define IMX7ULP_PAD_PTC13__TPM7_CLKIN 0x0034 0x02F4 0x6 0x1
+#define IMX7ULP_PAD_PTC13__FB_AD13 0x0034 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC13__TRACE_D2 0x0034 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC13__USB0_ID 0x0034 0x0338 0xb 0x1
+#define IMX7ULP_PAD_PTC14__PTC14 0x0038 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC14__FXIO1_D10 0x0038 0x022C 0x2 0x1
+#define IMX7ULP_PAD_PTC14__LPSPI3_PCS3 0x0038 0x031C 0x3 0x1
+#define IMX7ULP_PAD_PTC14__LPUART7_TX 0x0038 0x0270 0x4 0x1
+#define IMX7ULP_PAD_PTC14__LPI2C7_HREQ 0x0038 0x0304 0x5 0x1
+#define IMX7ULP_PAD_PTC14__TPM7_CH0 0x0038 0x02DC 0x6 0x1
+#define IMX7ULP_PAD_PTC14__FB_AD14 0x0038 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC14__TRACE_D1 0x0038 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC15__PTC15 0x003C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC15__FXIO1_D11 0x003C 0x0230 0x2 0x1
+#define IMX7ULP_PAD_PTC15__LPUART7_RX 0x003C 0x026C 0x4 0x1
+#define IMX7ULP_PAD_PTC15__TPM7_CH1 0x003C 0x02E0 0x6 0x1
+#define IMX7ULP_PAD_PTC15__FB_AD15 0x003C 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC15__TRACE_D0 0x003C 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC16__PTC16 0x0040 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC16__FXIO1_D12 0x0040 0x0234 0x2 0x1
+#define IMX7ULP_PAD_PTC16__LPSPI3_SIN 0x0040 0x0324 0x3 0x1
+#define IMX7ULP_PAD_PTC16__TPM7_CH2 0x0040 0x02E4 0x6 0x1
+#define IMX7ULP_PAD_PTC16__FB_ALE_FB_CS1_B_FB_TS_B 0x0040 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC16__TRACE_CLKOUT 0x0040 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTC16__USB1_OC2 0x0040 0x0334 0xb 0x1
+#define IMX7ULP_PAD_PTC17__PTC17 0x0044 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC17__FXIO1_D13 0x0044 0x0238 0x2 0x1
+#define IMX7ULP_PAD_PTC17__LPSPI3_SOUT 0x0044 0x0328 0x3 0x1
+#define IMX7ULP_PAD_PTC17__TPM6_CLKIN 0x0044 0x02D8 0x6 0x1
+#define IMX7ULP_PAD_PTC17__FB_CS0_B 0x0044 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC18__PTC18 0x0048 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC18__FXIO1_D14 0x0048 0x023C 0x2 0x1
+#define IMX7ULP_PAD_PTC18__LPSPI3_SCK 0x0048 0x0320 0x3 0x1
+#define IMX7ULP_PAD_PTC18__TPM6_CH0 0x0048 0x02D0 0x6 0x1
+#define IMX7ULP_PAD_PTC18__FB_OE_B 0x0048 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC18__USB0_ID 0x0048 0x0338 0xb 0x2
+#define IMX7ULP_PAD_PTC18__VIU_DE 0x0048 0x033C 0xc 0x1
+#define IMX7ULP_PAD_PTC19__PTC19 0x004C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTC19__FXIO1_D15 0x004C 0x0240 0x2 0x1
+#define IMX7ULP_PAD_PTC19__LPSPI3_PCS0 0x004C 0x0310 0x3 0x1
+#define IMX7ULP_PAD_PTC19__TPM6_CH1 0x004C 0x02D4 0x6 0x1
+#define IMX7ULP_PAD_PTC19__FB_A16 0x004C 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTC19__USB0_ID 0x004C 0x0338 0xa 0x3
+#define IMX7ULP_PAD_PTC19__USB1_PWR2 0x004C 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTC19__VIU_DE 0x004C 0x033C 0xc 0x3
+#define IMX7ULP_PAD_PTD0__PTD0 0x0080 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD0__SDHC0_RESET_B 0x0080 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD1__PTD1 0x0084 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD1__SDHC0_CMD 0x0084 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD2__PTD2 0x0088 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD2__SDHC0_CLK 0x0088 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD3__PTD3 0x008C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD3__SDHC0_D7 0x008C 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD4__PTD4 0x0090 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD4__SDHC0_D6 0x0090 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD5__PTD5 0x0094 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD5__SDHC0_D5 0x0094 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD6__PTD6 0x0098 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD6__SDHC0_D4 0x0098 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD7__PTD7 0x009C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD7__SDHC0_D3 0x009C 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD8__PTD8 0x00A0 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD8__TPM4_CLKIN 0x00A0 0x0298 0x6 0x2
+#define IMX7ULP_PAD_PTD8__SDHC0_D2 0x00A0 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD9__PTD9 0x00A4 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD9__TPM4_CH0 0x00A4 0x0280 0x6 0x2
+#define IMX7ULP_PAD_PTD9__SDHC0_D1 0x00A4 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD10__PTD10 0x00A8 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD10__TPM4_CH1 0x00A8 0x0284 0x6 0x2
+#define IMX7ULP_PAD_PTD10__SDHC0_D0 0x00A8 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTD11__PTD11 0x00AC 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTD11__TPM4_CH2 0x00AC 0x0288 0x6 0x2
+#define IMX7ULP_PAD_PTD11__SDHC0_DQS 0x00AC 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE0__PTE0 0x0100 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE0__FXIO1_D31 0x0100 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE0__LPSPI2_PCS1 0x0100 0x02A0 0x3 0x2
+#define IMX7ULP_PAD_PTE0__LPUART4_CTS_B 0x0100 0x0244 0x4 0x2
+#define IMX7ULP_PAD_PTE0__LPI2C4_SCL 0x0100 0x0278 0x5 0x2
+#define IMX7ULP_PAD_PTE0__SDHC1_D1 0x0100 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE0__FB_A25 0x0100 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE1__PTE1 0x0104 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE1__FXIO1_D30 0x0104 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE1__LPSPI2_PCS2 0x0104 0x02A4 0x3 0x2
+#define IMX7ULP_PAD_PTE1__LPUART4_RTS_B 0x0104 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTE1__LPI2C4_SDA 0x0104 0x027C 0x5 0x2
+#define IMX7ULP_PAD_PTE1__SDHC1_D0 0x0104 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE1__FB_A26 0x0104 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE2__PTE2 0x0108 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE2__FXIO1_D29 0x0108 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE2__LPSPI2_PCS3 0x0108 0x02A8 0x3 0x2
+#define IMX7ULP_PAD_PTE2__LPUART4_TX 0x0108 0x024C 0x4 0x2
+#define IMX7ULP_PAD_PTE2__LPI2C4_HREQ 0x0108 0x0274 0x5 0x2
+#define IMX7ULP_PAD_PTE2__SDHC1_CLK 0x0108 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE3__PTE3 0x010C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE3__FXIO1_D28 0x010C 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE3__LPUART4_RX 0x010C 0x0248 0x4 0x2
+#define IMX7ULP_PAD_PTE3__TPM5_CH1 0x010C 0x02C8 0x6 0x2
+#define IMX7ULP_PAD_PTE3__SDHC1_CMD 0x010C 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE4__PTE4 0x0110 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE4__FXIO1_D27 0x0110 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE4__LPSPI2_SIN 0x0110 0x02B0 0x3 0x2
+#define IMX7ULP_PAD_PTE4__LPUART5_CTS_B 0x0110 0x0250 0x4 0x2
+#define IMX7ULP_PAD_PTE4__LPI2C5_SCL 0x0110 0x02BC 0x5 0x2
+#define IMX7ULP_PAD_PTE4__TPM5_CLKIN 0x0110 0x02CC 0x6 0x2
+#define IMX7ULP_PAD_PTE4__SDHC1_D3 0x0110 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE5__PTE5 0x0114 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE5__FXIO1_D26 0x0114 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE5__LPSPI2_SOUT 0x0114 0x02B4 0x3 0x2
+#define IMX7ULP_PAD_PTE5__LPUART5_RTS_B 0x0114 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTE5__LPI2C5_SDA 0x0114 0x02C0 0x5 0x2
+#define IMX7ULP_PAD_PTE5__TPM5_CH0 0x0114 0x02C4 0x6 0x2
+#define IMX7ULP_PAD_PTE5__SDHC1_D2 0x0114 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE5__VIU_DE 0x0114 0x033C 0xc 0x2
+#define IMX7ULP_PAD_PTE6__PTE6 0x0118 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE6__FXIO1_D25 0x0118 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE6__LPSPI2_SCK 0x0118 0x02AC 0x3 0x2
+#define IMX7ULP_PAD_PTE6__LPUART5_TX 0x0118 0x0258 0x4 0x2
+#define IMX7ULP_PAD_PTE6__LPI2C5_HREQ 0x0118 0x02B8 0x5 0x2
+#define IMX7ULP_PAD_PTE6__TPM7_CH3 0x0118 0x02E8 0x6 0x2
+#define IMX7ULP_PAD_PTE6__SDHC1_D4 0x0118 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE6__FB_A17 0x0118 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE6__USB0_OC 0x0118 0x0330 0xb 0x1
+#define IMX7ULP_PAD_PTE7__PTE7 0x011C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE7__FXIO1_D24 0x011C 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE7__LPSPI2_PCS0 0x011C 0x029C 0x3 0x2
+#define IMX7ULP_PAD_PTE7__LPUART5_RX 0x011C 0x0254 0x4 0x2
+#define IMX7ULP_PAD_PTE7__TPM7_CH4 0x011C 0x02EC 0x6 0x2
+#define IMX7ULP_PAD_PTE7__SDHC1_D5 0x011C 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE7__FB_A18 0x011C 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE7__TRACE_D7 0x011C 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTE7__USB0_PWR 0x011C 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTE7__VIU_FID 0x011C 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTE8__PTE8 0x0120 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE8__TRACE_D6 0x0120 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTE8__VIU_D16 0x0120 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTE8__FXIO1_D23 0x0120 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE8__LPSPI3_PCS1 0x0120 0x0314 0x3 0x2
+#define IMX7ULP_PAD_PTE8__LPUART6_CTS_B 0x0120 0x025C 0x4 0x2
+#define IMX7ULP_PAD_PTE8__LPI2C6_SCL 0x0120 0x02FC 0x5 0x2
+#define IMX7ULP_PAD_PTE8__TPM7_CH5 0x0120 0x02F0 0x6 0x2
+#define IMX7ULP_PAD_PTE8__SDHC1_WP 0x0120 0x0200 0x7 0x1
+#define IMX7ULP_PAD_PTE8__SDHC1_D6 0x0120 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE8__FB_CS3_B_FB_BE7_0_BLS31_24_B 0x0120 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE9__PTE9 0x0124 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE9__TRACE_D5 0x0124 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTE9__VIU_D17 0x0124 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTE9__FXIO1_D22 0x0124 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE9__LPSPI3_PCS2 0x0124 0x0318 0x3 0x2
+#define IMX7ULP_PAD_PTE9__LPUART6_RTS_B 0x0124 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTE9__LPI2C6_SDA 0x0124 0x0300 0x5 0x2
+#define IMX7ULP_PAD_PTE9__TPM7_CLKIN 0x0124 0x02F4 0x6 0x2
+#define IMX7ULP_PAD_PTE9__SDHC1_CD 0x0124 0x032C 0x7 0x1
+#define IMX7ULP_PAD_PTE9__SDHC1_D7 0x0124 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE9__FB_TBST_B_FB_CS2_B_FB_BE15_8_BLS23_16_B 0x0124 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE10__PTE10 0x0128 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE10__TRACE_D4 0x0128 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTE10__VIU_D18 0x0128 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTE10__FXIO1_D21 0x0128 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE10__LPSPI3_PCS3 0x0128 0x031C 0x3 0x2
+#define IMX7ULP_PAD_PTE10__LPUART6_TX 0x0128 0x0264 0x4 0x2
+#define IMX7ULP_PAD_PTE10__LPI2C6_HREQ 0x0128 0x02F8 0x5 0x2
+#define IMX7ULP_PAD_PTE10__TPM7_CH0 0x0128 0x02DC 0x6 0x2
+#define IMX7ULP_PAD_PTE10__SDHC1_VS 0x0128 0x0000 0x7 0x0
+#define IMX7ULP_PAD_PTE10__SDHC1_DQS 0x0128 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE10__FB_A19 0x0128 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE11__PTE11 0x012C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE11__TRACE_D3 0x012C 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTE11__VIU_D19 0x012C 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTE11__FXIO1_D20 0x012C 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE11__LPUART6_RX 0x012C 0x0260 0x4 0x2
+#define IMX7ULP_PAD_PTE11__TPM7_CH1 0x012C 0x02E0 0x6 0x2
+#define IMX7ULP_PAD_PTE11__SDHC1_RESET_B 0x012C 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE11__FB_A20 0x012C 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE12__PTE12 0x0130 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE12__FXIO1_D19 0x0130 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE12__LPSPI3_SIN 0x0130 0x0324 0x3 0x2
+#define IMX7ULP_PAD_PTE12__LPUART7_CTS_B 0x0130 0x0268 0x4 0x2
+#define IMX7ULP_PAD_PTE12__LPI2C7_SCL 0x0130 0x0308 0x5 0x2
+#define IMX7ULP_PAD_PTE12__TPM7_CH2 0x0130 0x02E4 0x6 0x2
+#define IMX7ULP_PAD_PTE12__SDHC1_WP 0x0130 0x0200 0x8 0x2
+#define IMX7ULP_PAD_PTE12__FB_A21 0x0130 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE12__TRACE_D2 0x0130 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTE12__USB1_OC2 0x0130 0x0334 0xb 0x2
+#define IMX7ULP_PAD_PTE12__VIU_D20 0x0130 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTE13__PTE13 0x0134 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE13__FXIO1_D18 0x0134 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE13__LPSPI3_SOUT 0x0134 0x0328 0x3 0x2
+#define IMX7ULP_PAD_PTE13__LPUART7_RTS_B 0x0134 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTE13__LPI2C7_SDA 0x0134 0x030C 0x5 0x2
+#define IMX7ULP_PAD_PTE13__TPM6_CLKIN 0x0134 0x02D8 0x6 0x2
+#define IMX7ULP_PAD_PTE13__SDHC1_CD 0x0134 0x032C 0x8 0x2
+#define IMX7ULP_PAD_PTE13__FB_A22 0x0134 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE13__TRACE_D1 0x0134 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTE13__USB1_PWR2 0x0134 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTE13__VIU_D21 0x0134 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTE14__PTE14 0x0138 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE14__FXIO1_D17 0x0138 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE14__LPSPI3_SCK 0x0138 0x0320 0x3 0x2
+#define IMX7ULP_PAD_PTE14__LPUART7_TX 0x0138 0x0270 0x4 0x2
+#define IMX7ULP_PAD_PTE14__LPI2C7_HREQ 0x0138 0x0304 0x5 0x2
+#define IMX7ULP_PAD_PTE14__TPM6_CH0 0x0138 0x02D0 0x6 0x2
+#define IMX7ULP_PAD_PTE14__SDHC1_VS 0x0138 0x0000 0x8 0x0
+#define IMX7ULP_PAD_PTE14__FB_A23 0x0138 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE14__TRACE_D0 0x0138 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTE14__USB0_OC 0x0138 0x0330 0xb 0x2
+#define IMX7ULP_PAD_PTE14__VIU_D22 0x0138 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTE15__PTE15 0x013C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTE15__FXIO1_D16 0x013C 0x0000 0x2 0x0
+#define IMX7ULP_PAD_PTE15__LPSPI3_PCS0 0x013C 0x0310 0x3 0x2
+#define IMX7ULP_PAD_PTE15__LPUART7_RX 0x013C 0x026C 0x4 0x2
+#define IMX7ULP_PAD_PTE15__TPM6_CH1 0x013C 0x02D4 0x6 0x2
+#define IMX7ULP_PAD_PTE15__FB_A24 0x013C 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTE15__TRACE_CLKOUT 0x013C 0x0000 0xa 0x0
+#define IMX7ULP_PAD_PTE15__USB0_PWR 0x013C 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTE15__VIU_D23 0x013C 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF0__PTF0 0x0180 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF0__LPUART4_CTS_B 0x0180 0x0244 0x4 0x3
+#define IMX7ULP_PAD_PTF0__LPI2C4_SCL 0x0180 0x0278 0x5 0x3
+#define IMX7ULP_PAD_PTF0__TPM4_CLKIN 0x0180 0x0298 0x6 0x3
+#define IMX7ULP_PAD_PTF0__FB_RW_B 0x0180 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF0__VIU_DE 0x0180 0x033C 0xc 0x0
+#define IMX7ULP_PAD_PTF1__PTF1 0x0184 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF1__LPUART4_RTS_B 0x0184 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTF1__LPI2C4_SDA 0x0184 0x027C 0x5 0x3
+#define IMX7ULP_PAD_PTF1__TPM4_CH0 0x0184 0x0280 0x6 0x3
+#define IMX7ULP_PAD_PTF1__CLKOUT 0x0184 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF1__VIU_HSYNC 0x0184 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF2__PTF2 0x0188 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF2__LPUART4_TX 0x0188 0x024C 0x4 0x3
+#define IMX7ULP_PAD_PTF2__LPI2C4_HREQ 0x0188 0x0274 0x5 0x3
+#define IMX7ULP_PAD_PTF2__TPM4_CH1 0x0188 0x0284 0x6 0x3
+#define IMX7ULP_PAD_PTF2__FB_TSIZ1_FB_CS5_B_FB_BE23_16_BLS15_8_B 0x0188 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF2__VIU_VSYNC 0x0188 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF3__PTF3 0x018C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF3__LPUART4_RX 0x018C 0x0248 0x4 0x3
+#define IMX7ULP_PAD_PTF3__TPM4_CH2 0x018C 0x0288 0x6 0x3
+#define IMX7ULP_PAD_PTF3__FB_AD16 0x018C 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF3__VIU_PCLK 0x018C 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF4__PTF4 0x0190 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF4__FXIO1_D0 0x0190 0x0204 0x2 0x2
+#define IMX7ULP_PAD_PTF4__LPSPI2_PCS1 0x0190 0x02A0 0x3 0x3
+#define IMX7ULP_PAD_PTF4__LPUART5_CTS_B 0x0190 0x0250 0x4 0x3
+#define IMX7ULP_PAD_PTF4__LPI2C5_SCL 0x0190 0x02BC 0x5 0x3
+#define IMX7ULP_PAD_PTF4__TPM4_CH3 0x0190 0x028C 0x6 0x2
+#define IMX7ULP_PAD_PTF4__FB_AD17 0x0190 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF4__VIU_D0 0x0190 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF5__PTF5 0x0194 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF5__FXIO1_D1 0x0194 0x0208 0x2 0x2
+#define IMX7ULP_PAD_PTF5__LPSPI2_PCS2 0x0194 0x02A4 0x3 0x3
+#define IMX7ULP_PAD_PTF5__LPUART5_RTS_B 0x0194 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTF5__LPI2C5_SDA 0x0194 0x02C0 0x5 0x3
+#define IMX7ULP_PAD_PTF5__TPM4_CH4 0x0194 0x0290 0x6 0x2
+#define IMX7ULP_PAD_PTF5__FB_AD18 0x0194 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF5__VIU_D1 0x0194 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF6__PTF6 0x0198 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF6__FXIO1_D2 0x0198 0x020C 0x2 0x2
+#define IMX7ULP_PAD_PTF6__LPSPI2_PCS3 0x0198 0x02A8 0x3 0x3
+#define IMX7ULP_PAD_PTF6__LPUART5_TX 0x0198 0x0258 0x4 0x3
+#define IMX7ULP_PAD_PTF6__LPI2C5_HREQ 0x0198 0x02B8 0x5 0x3
+#define IMX7ULP_PAD_PTF6__TPM4_CH5 0x0198 0x0294 0x6 0x2
+#define IMX7ULP_PAD_PTF6__FB_AD19 0x0198 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF6__VIU_D2 0x0198 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF7__PTF7 0x019C 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF7__FXIO1_D3 0x019C 0x0210 0x2 0x2
+#define IMX7ULP_PAD_PTF7__LPUART5_RX 0x019C 0x0254 0x4 0x3
+#define IMX7ULP_PAD_PTF7__TPM5_CH1 0x019C 0x02C8 0x6 0x3
+#define IMX7ULP_PAD_PTF7__FB_AD20 0x019C 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF7__VIU_D3 0x019C 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF8__PTF8 0x01A0 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF8__FXIO1_D4 0x01A0 0x0214 0x2 0x2
+#define IMX7ULP_PAD_PTF8__LPSPI2_SIN 0x01A0 0x02B0 0x3 0x3
+#define IMX7ULP_PAD_PTF8__LPUART6_CTS_B 0x01A0 0x025C 0x4 0x3
+#define IMX7ULP_PAD_PTF8__LPI2C6_SCL 0x01A0 0x02FC 0x5 0x3
+#define IMX7ULP_PAD_PTF8__TPM5_CLKIN 0x01A0 0x02CC 0x6 0x3
+#define IMX7ULP_PAD_PTF8__FB_AD21 0x01A0 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF8__USB1_CLK 0x01A0 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF8__VIU_D4 0x01A0 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF9__PTF9 0x01A4 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF9__FXIO1_D5 0x01A4 0x0218 0x2 0x2
+#define IMX7ULP_PAD_PTF9__LPSPI2_SOUT 0x01A4 0x02B4 0x3 0x3
+#define IMX7ULP_PAD_PTF9__LPUART6_RTS_B 0x01A4 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTF9__LPI2C6_SDA 0x01A4 0x0300 0x5 0x3
+#define IMX7ULP_PAD_PTF9__TPM5_CH0 0x01A4 0x02C4 0x6 0x3
+#define IMX7ULP_PAD_PTF9__FB_AD22 0x01A4 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF9__USB1_NXT 0x01A4 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF9__VIU_D5 0x01A4 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF10__PTF10 0x01A8 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF10__FXIO1_D6 0x01A8 0x021C 0x2 0x2
+#define IMX7ULP_PAD_PTF10__LPSPI2_SCK 0x01A8 0x02AC 0x3 0x3
+#define IMX7ULP_PAD_PTF10__LPUART6_TX 0x01A8 0x0264 0x4 0x3
+#define IMX7ULP_PAD_PTF10__LPI2C6_HREQ 0x01A8 0x02F8 0x5 0x3
+#define IMX7ULP_PAD_PTF10__TPM7_CH3 0x01A8 0x02E8 0x6 0x3
+#define IMX7ULP_PAD_PTF10__FB_AD23 0x01A8 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF10__USB1_STP 0x01A8 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF10__VIU_D6 0x01A8 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF11__PTF11 0x01AC 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF11__FXIO1_D7 0x01AC 0x0220 0x2 0x2
+#define IMX7ULP_PAD_PTF11__LPSPI2_PCS0 0x01AC 0x029C 0x3 0x3
+#define IMX7ULP_PAD_PTF11__LPUART6_RX 0x01AC 0x0260 0x4 0x3
+#define IMX7ULP_PAD_PTF11__TPM7_CH4 0x01AC 0x02EC 0x6 0x3
+#define IMX7ULP_PAD_PTF11__FB_CS4_B_FB_TSIZ0_FB_BE31_24_BLS7_0_B 0x01AC 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF11__USB1_DIR 0x01AC 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF11__VIU_D7 0x01AC 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF12__PTF12 0x01B0 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF12__FXIO1_D8 0x01B0 0x0224 0x2 0x2
+#define IMX7ULP_PAD_PTF12__LPSPI3_PCS1 0x01B0 0x0314 0x3 0x3
+#define IMX7ULP_PAD_PTF12__LPUART7_CTS_B 0x01B0 0x0268 0x4 0x3
+#define IMX7ULP_PAD_PTF12__LPI2C7_SCL 0x01B0 0x0308 0x5 0x3
+#define IMX7ULP_PAD_PTF12__TPM7_CH5 0x01B0 0x02F0 0x6 0x3
+#define IMX7ULP_PAD_PTF12__FB_AD24 0x01B0 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF12__USB1_DATA0 0x01B0 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF12__VIU_D8 0x01B0 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF13__PTF13 0x01B4 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF13__FXIO1_D9 0x01B4 0x0228 0x2 0x2
+#define IMX7ULP_PAD_PTF13__LPSPI3_PCS2 0x01B4 0x0318 0x3 0x3
+#define IMX7ULP_PAD_PTF13__LPUART7_RTS_B 0x01B4 0x0000 0x4 0x0
+#define IMX7ULP_PAD_PTF13__LPI2C7_SDA 0x01B4 0x030C 0x5 0x3
+#define IMX7ULP_PAD_PTF13__TPM7_CLKIN 0x01B4 0x02F4 0x6 0x3
+#define IMX7ULP_PAD_PTF13__FB_AD25 0x01B4 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF13__USB1_DATA1 0x01B4 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF13__VIU_D9 0x01B4 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF14__PTF14 0x01B8 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF14__FXIO1_D10 0x01B8 0x022C 0x2 0x2
+#define IMX7ULP_PAD_PTF14__LPSPI3_PCS3 0x01B8 0x031C 0x3 0x3
+#define IMX7ULP_PAD_PTF14__LPUART7_TX 0x01B8 0x0270 0x4 0x3
+#define IMX7ULP_PAD_PTF14__LPI2C7_HREQ 0x01B8 0x0304 0x5 0x3
+#define IMX7ULP_PAD_PTF14__TPM7_CH0 0x01B8 0x02DC 0x6 0x3
+#define IMX7ULP_PAD_PTF14__FB_AD26 0x01B8 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF14__USB1_DATA2 0x01B8 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF14__VIU_D10 0x01B8 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF15__PTF15 0x01BC 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF15__FXIO1_D11 0x01BC 0x0230 0x2 0x2
+#define IMX7ULP_PAD_PTF15__LPUART7_RX 0x01BC 0x026C 0x4 0x3
+#define IMX7ULP_PAD_PTF15__TPM7_CH1 0x01BC 0x02E0 0x6 0x3
+#define IMX7ULP_PAD_PTF15__FB_AD27 0x01BC 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF15__USB1_DATA3 0x01BC 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF15__VIU_D11 0x01BC 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF16__PTF16 0x01C0 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF16__USB1_DATA4 0x01C0 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF16__VIU_D12 0x01C0 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF16__FXIO1_D12 0x01C0 0x0234 0x2 0x2
+#define IMX7ULP_PAD_PTF16__LPSPI3_SIN 0x01C0 0x0324 0x3 0x3
+#define IMX7ULP_PAD_PTF16__TPM7_CH2 0x01C0 0x02E4 0x6 0x3
+#define IMX7ULP_PAD_PTF16__FB_AD28 0x01C0 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF17__PTF17 0x01C4 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF17__USB1_DATA5 0x01C4 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF17__VIU_D13 0x01C4 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF17__FXIO1_D13 0x01C4 0x0238 0x2 0x2
+#define IMX7ULP_PAD_PTF17__LPSPI3_SOUT 0x01C4 0x0328 0x3 0x3
+#define IMX7ULP_PAD_PTF17__TPM6_CLKIN 0x01C4 0x02D8 0x6 0x3
+#define IMX7ULP_PAD_PTF17__FB_AD29 0x01C4 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF18__PTF18 0x01C8 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF18__USB1_DATA6 0x01C8 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF18__VIU_D14 0x01C8 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF18__FXIO1_D14 0x01C8 0x023C 0x2 0x2
+#define IMX7ULP_PAD_PTF18__LPSPI3_SCK 0x01C8 0x0320 0x3 0x3
+#define IMX7ULP_PAD_PTF18__TPM6_CH0 0x01C8 0x02D0 0x6 0x3
+#define IMX7ULP_PAD_PTF18__FB_AD30 0x01C8 0x0000 0x9 0x0
+#define IMX7ULP_PAD_PTF19__PTF19 0x01CC 0x0000 0x1 0x0
+#define IMX7ULP_PAD_PTF19__USB1_DATA7 0x01CC 0x0000 0xb 0x0
+#define IMX7ULP_PAD_PTF19__VIU_D15 0x01CC 0x0000 0xc 0x0
+#define IMX7ULP_PAD_PTF19__FXIO1_D15 0x01CC 0x0240 0x2 0x2
+#define IMX7ULP_PAD_PTF19__LPSPI3_PCS0 0x01CC 0x0310 0x3 0x3
+#define IMX7ULP_PAD_PTF19__TPM6_CH1 0x01CC 0x02D4 0x6 0x3
+#define IMX7ULP_PAD_PTF19__FB_AD31 0x01CC 0x0000 0x9 0x0
-#define ULP1_PAD_PTA0_LLWU0_P0__CMP0_IN2A 0x0000 0x0000 0x0 0x0
-#define ULP1_PAD_PTA0_LLWU0_P0__PTA0 0x0000 0x0000 0x1 0x0
-#define ULP1_PAD_PTA0_LLWU0_P0__LLWU0_P0 0x0000 0x0000 0xd 0x0
-#define ULP1_PAD_PTA0_LLWU0_P0__LPSPI0_PCS1 0x0000 0xd104 0x3 0x2
-#define ULP1_PAD_PTA0_LLWU0_P0__LPUART0_CTS_B 0x0000 0xd1f8 0x4 0x2
-#define ULP1_PAD_PTA0_LLWU0_P0__LPI2C0_SCL 0x0000 0xd17c 0x5 0x2
-#define ULP1_PAD_PTA0_LLWU0_P0__TPM0_CLKIN 0x0000 0xd1a8 0x6 0x2
-#define ULP1_PAD_PTA0_LLWU0_P0__I2S0_RX_BCLK 0x0000 0x01b8 0x7 0x2
-#define ULP1_PAD_PTA1__CMP0_IN2B 0x0004 0x0000 0x0 0x0
-#define ULP1_PAD_PTA1__PTA1 0x0004 0x0000 0x1 0x0
-#define ULP1_PAD_PTA1__LPSPI0_PCS2 0x0004 0xd108 0x3 0x1
-#define ULP1_PAD_PTA1__LPUART0_RTS_B 0x0004 0x0000 0x4 0x0
-#define ULP1_PAD_PTA1__LPI2C0_SDA 0x0004 0xd180 0x5 0x1
-#define ULP1_PAD_PTA1__TPM0_CH0 0x0004 0xd138 0x6 0x1
-#define ULP1_PAD_PTA1__I2S0_RX_FS 0x0004 0x01bc 0x7 0x1
-#define ULP1_PAD_PTA2__CMP1_IN2A 0x0008 0x0000 0x0 0x0
-#define ULP1_PAD_PTA2__PTA2 0x0008 0x0000 0x1 0x0
-#define ULP1_PAD_PTA2__LPSPI0_PCS3 0x0008 0xd10c 0x3 0x1
-#define ULP1_PAD_PTA2__LPUART0_TX 0x0008 0xd200 0x4 0x1
-#define ULP1_PAD_PTA2__LPI2C0_HREQ 0x0008 0xd178 0x5 0x1
-#define ULP1_PAD_PTA2__TPM0_CH1 0x0008 0xd13c 0x6 0x1
-#define ULP1_PAD_PTA2__I2S0_RXD0 0x0008 0x01dc 0x7 0x1
-#define ULP1_PAD_PTA3_LLWU0_P1__CMP1_IN2B 0x000c 0x0000 0x0 0x0
-#define ULP1_PAD_PTA3_LLWU0_P1__PTA3 0x000c 0x0000 0x1 0x0
-#define ULP1_PAD_PTA3_LLWU0_P1__CMP0_OUT 0x000c 0x0000 0xb 0x0
-#define ULP1_PAD_PTA3_LLWU0_P1__LLWU0_P1 0x000c 0x0000 0xd 0x0
-#define ULP1_PAD_PTA3_LLWU0_P1__LPUART0_RX 0x000c 0xd1fc 0x4 0x1
-#define ULP1_PAD_PTA3_LLWU0_P1__TPM0_CH2 0x000c 0xd140 0x6 0x1
-#define ULP1_PAD_PTA3_LLWU0_P1__I2S0_RXD1 0x000c 0x01e0 0x7 0x1
-#define ULP1_PAD_PTA4__ADC1_CH2A 0x0010 0x0000 0x0 0x0
-#define ULP1_PAD_PTA4__PTA4 0x0010 0x0000 0x1 0x0
-#define ULP1_PAD_PTA4__LPSPI0_SIN 0x0010 0xd114 0x3 0x1
-#define ULP1_PAD_PTA4__LPUART1_CTS_B 0x0010 0xd204 0x4 0x1
-#define ULP1_PAD_PTA4__LPI2C1_SCL 0x0010 0xd188 0x5 0x1
-#define ULP1_PAD_PTA4__TPM0_CH3 0x0010 0xd144 0x6 0x1
-#define ULP1_PAD_PTA4__I2S0_MCLK 0x0010 0x01b4 0x7 0x1
-#define ULP1_PAD_PTA5__ADC1_CH2B 0x0014 0x0000 0x0 0x0
-#define ULP1_PAD_PTA5__PTA5 0x0014 0x0000 0x1 0x0
-#define ULP1_PAD_PTA5__LPSPI0_SOUT 0x0014 0xd118 0x3 0x1
-#define ULP1_PAD_PTA5__LPUART1_RTS_B 0x0014 0x0000 0x4 0x0
-#define ULP1_PAD_PTA5__LPI2C1_SDA 0x0014 0xd18c 0x5 0x1
-#define ULP1_PAD_PTA5__TPM0_CH4 0x0014 0xd148 0x6 0x1
-#define ULP1_PAD_PTA5__I2S0_TX_BCLK 0x0014 0x01c0 0x7 0x1
-#define ULP1_PAD_PTA6__ADC1_CH3A 0x0018 0x0000 0x0 0x0
-#define ULP1_PAD_PTA6__PTA6 0x0018 0x0000 0x1 0x0
-#define ULP1_PAD_PTA6__LPSPI0_SCK 0x0018 0xd110 0x3 0x1
-#define ULP1_PAD_PTA6__LPUART1_TX 0x0018 0xd20c 0x4 0x1
-#define ULP1_PAD_PTA6__LPI2C1_HREQ 0x0018 0xd184 0x5 0x1
-#define ULP1_PAD_PTA6__TPM0_CH5 0x0018 0xd14c 0x6 0x1
-#define ULP1_PAD_PTA6__I2S0_TX_FS 0x0018 0x01c4 0x7 0x1
-#define ULP1_PAD_PTA7__ADC1_CH3B 0x001c 0x0000 0x0 0x0
-#define ULP1_PAD_PTA7__PTA7 0x001c 0x0000 0x1 0x0
-#define ULP1_PAD_PTA7__LPSPI0_PCS0 0x001c 0xd100 0x3 0x1
-#define ULP1_PAD_PTA7__LPUART1_RX 0x001c 0xd208 0x4 0x1
-#define ULP1_PAD_PTA7__TPM1_CH1 0x001c 0xd154 0x6 0x1
-#define ULP1_PAD_PTA7__I2S0_TXD0 0x001c 0x0000 0x7 0x0
-#define ULP1_PAD_PTA8__ADC1_CH7A 0x0020 0x0000 0x0 0x0
-#define ULP1_PAD_PTA8__PTA8 0x0020 0x0000 0x1 0x0
-#define ULP1_PAD_PTA8__LPSPI1_PCS1 0x0020 0xd120 0x3 0x1
-#define ULP1_PAD_PTA8__LPUART2_CTS_B 0x0020 0xd210 0x4 0x1
-#define ULP1_PAD_PTA8__LPI2C2_SCL 0x0020 0xd194 0x5 0x1
-#define ULP1_PAD_PTA8__TPM1_CLKIN 0x0020 0xd1ac 0x6 0x1
-#define ULP1_PAD_PTA8__I2S0_TXD1 0x0020 0x0000 0x7 0x0
-#define ULP1_PAD_PTA9__ADC1_CH7B 0x0024 0x0000 0x0 0x0
-#define ULP1_PAD_PTA9__PTA9 0x0024 0x0000 0x1 0x0
-#define ULP1_PAD_PTA9__NMI0_B 0x0024 0x0000 0xb 0x0
-#define ULP1_PAD_PTA9__LPSPI1_PCS2 0x0024 0xd124 0x3 0x1
-#define ULP1_PAD_PTA9__LPUART2_RTS_B 0x0024 0x0000 0x4 0x0
-#define ULP1_PAD_PTA9__LPI2C2_SDA 0x0024 0xd198 0x5 0x1
-#define ULP1_PAD_PTA9__TPM1_CH0 0x0024 0xd150 0x6 0x1
-#define ULP1_PAD_PTA10__ADC1_CH6A 0x0028 0x0000 0x0 0x0
-#define ULP1_PAD_PTA10__PTA10 0x0028 0x0000 0x1 0x0
-#define ULP1_PAD_PTA10__LPSPI1_PCS3 0x0028 0xd128 0x3 0x1
-#define ULP1_PAD_PTA10__LPUART2_TX 0x0028 0xd218 0x4 0x1
-#define ULP1_PAD_PTA10__LPI2C2_HREQ 0x0028 0xd190 0x5 0x1
-#define ULP1_PAD_PTA10__TPM2_CLKIN 0x0028 0xd1f4 0x6 0x1
-#define ULP1_PAD_PTA10__I2S0_RX_BCLK 0x0028 0x01b8 0x7 0x1
-#define ULP1_PAD_PTA11__ADC1_CH6B 0x002c 0x0000 0x0 0x0
-#define ULP1_PAD_PTA11__PTA11 0x002c 0x0000 0x1 0x0
-#define ULP1_PAD_PTA11__LPUART2_RX 0x002c 0xd214 0x4 0x1
-#define ULP1_PAD_PTA11__TPM2_CH0 0x002c 0xd158 0x6 0x1
-#define ULP1_PAD_PTA11__I2S0_RX_FS 0x002c 0x01bc 0x7 0x2
-#define ULP1_PAD_PTA12__ADC1_CH5A 0x0030 0x0000 0x0 0x0
-#define ULP1_PAD_PTA12__PTA12 0x0030 0x0000 0x1 0x0
-#define ULP1_PAD_PTA12__LPSPI1_SIN 0x0030 0xd130 0x3 0x1
-#define ULP1_PAD_PTA12__LPUART3_CTS_B 0x0030 0xd21c 0x4 0x1
-#define ULP1_PAD_PTA12__LPI2C3_SCL 0x0030 0xd1a0 0x5 0x1
-#define ULP1_PAD_PTA12__TPM2_CH1 0x0030 0xd15c 0x6 0x1
-#define ULP1_PAD_PTA12__I2S0_RXD0 0x0030 0x01dc 0x7 0x2
-#define ULP1_PAD_PTA13_LLWU0_P2__ADC1_CH5B 0x0034 0x0000 0x0 0x0
-#define ULP1_PAD_PTA13_LLWU0_P2__PTA13 0x0034 0x0000 0x1 0x0
-#define ULP1_PAD_PTA13_LLWU0_P2__CMP0_OUT 0x0034 0x0000 0xb 0x0
-#define ULP1_PAD_PTA13_LLWU0_P2__LLWU0_P2 0x0034 0x0000 0xd 0x0
-#define ULP1_PAD_PTA13_LLWU0_P2__LPSPI1_SOUT 0x0034 0xd134 0x3 0x2
-#define ULP1_PAD_PTA13_LLWU0_P2__LPUART3_RTS_B 0x0034 0x0000 0x4 0x0
-#define ULP1_PAD_PTA13_LLWU0_P2__LPI2C3_SDA 0x0034 0xd1a4 0x5 0x2
-#define ULP1_PAD_PTA13_LLWU0_P2__TPM3_CLKIN 0x0034 0xd1b0 0x6 0x1
-#define ULP1_PAD_PTA13_LLWU0_P2__I2S0_RXD1 0x0034 0x01e0 0x7 0x2
-#define ULP1_PAD_PTA14_LLWU0_P3__ADC1_CH4A 0x0038 0x0000 0x0 0x0
-#define ULP1_PAD_PTA14_LLWU0_P3__PTA14 0x0038 0x0000 0x1 0x0
-#define ULP1_PAD_PTA14_LLWU0_P3__LLWU0_P3 0x0038 0x0000 0xd 0x0
-#define ULP1_PAD_PTA14_LLWU0_P3__LPSPI1_SCK 0x0038 0xd12c 0x3 0x2
-#define ULP1_PAD_PTA14_LLWU0_P3__LPUART3_TX 0x0038 0xd224 0x4 0x2
-#define ULP1_PAD_PTA14_LLWU0_P3__LPI2C3_HREQ 0x0038 0xd19c 0x5 0x2
-#define ULP1_PAD_PTA14_LLWU0_P3__TPM3_CH0 0x0038 0xd160 0x6 0x1
-#define ULP1_PAD_PTA14_LLWU0_P3__I2S0_MCLK 0x0038 0x01b4 0x7 0x2
-#define ULP1_PAD_PTA15__ADC1_CH4B 0x003c 0x0000 0x0 0x0
-#define ULP1_PAD_PTA15__PTA15 0x003c 0x0000 0x1 0x0
-#define ULP1_PAD_PTA15__LPSPI1_PCS0 0x003c 0xd11c 0x3 0x1
-#define ULP1_PAD_PTA15__LPUART3_RX 0x003c 0xd220 0x4 0x1
-#define ULP1_PAD_PTA15__TPM3_CH1 0x003c 0xd164 0x6 0x1
-#define ULP1_PAD_PTA15__I2S0_TX_BCLK 0x003c 0x01c0 0x7 0x2
-#define ULP1_PAD_PTA16__CMP1_IN0A 0x0040 0x0000 0x0 0x0
-#define ULP1_PAD_PTA16__PTA16 0x0040 0x0000 0x1 0x0
-#define ULP1_PAD_PTA16__FXIO0_D0 0x0040 0x0000 0x2 0x0
-#define ULP1_PAD_PTA16__LPSPI0_PCS1 0x0040 0xd104 0x3 0x1
-#define ULP1_PAD_PTA16__LPUART0_CTS_B 0x0040 0xd1f8 0x4 0x1
-#define ULP1_PAD_PTA16__LPI2C0_SCL 0x0040 0xd17c 0x5 0x1
-#define ULP1_PAD_PTA16__TPM3_CH2 0x0040 0xd168 0x6 0x1
-#define ULP1_PAD_PTA16__I2S0_TX_FS 0x0040 0x01c4 0x7 0x2
-#define ULP1_PAD_PTA17__CMP1_IN0B 0x0044 0x0000 0x0 0x0
-#define ULP1_PAD_PTA17__PTA17 0x0044 0x0000 0x1 0x0
-#define ULP1_PAD_PTA17__FXIO0_D1 0x0044 0x0000 0x2 0x0
-#define ULP1_PAD_PTA17__LPSPI0_PCS2 0x0044 0xd108 0x3 0x2
-#define ULP1_PAD_PTA17__LPUART0_RTS_B 0x0044 0x0000 0x4 0x0
-#define ULP1_PAD_PTA17__LPI2C0_SDA 0x0044 0xd180 0x5 0x2
-#define ULP1_PAD_PTA17__TPM3_CH3 0x0044 0xd16c 0x6 0x1
-#define ULP1_PAD_PTA17__I2S0_TXD0 0x0044 0x0000 0x7 0x0
-#define ULP1_PAD_PTA18_LLWU0_P4__CMP1_IN1A 0x0048 0x0000 0x0 0x0
-#define ULP1_PAD_PTA18_LLWU0_P4__PTA18 0x0048 0x0000 0x1 0x0
-#define ULP1_PAD_PTA18_LLWU0_P4__NMI1_B 0x0048 0x0000 0xb 0x0
-#define ULP1_PAD_PTA18_LLWU0_P4__LLWU0_P4 0x0048 0x0000 0xd 0x0
-#define ULP1_PAD_PTA18_LLWU0_P4__FXIO0_D2 0x0048 0x0000 0x2 0x0
-#define ULP1_PAD_PTA18_LLWU0_P4__LPSPI0_PCS3 0x0048 0xd10c 0x3 0x2
-#define ULP1_PAD_PTA18_LLWU0_P4__LPUART0_TX 0x0048 0xd200 0x4 0x2
-#define ULP1_PAD_PTA18_LLWU0_P4__LPI2C0_HREQ 0x0048 0xd178 0x5 0x2
-#define ULP1_PAD_PTA18_LLWU0_P4__TPM3_CH4 0x0048 0xd170 0x6 0x1
-#define ULP1_PAD_PTA18_LLWU0_P4__I2S0_TXD1 0x0048 0x0000 0x7 0x0
-#define ULP1_PAD_PTA19_LLWU0_P5__CMP1_IN1B 0x004c 0x0000 0x0 0x0
-#define ULP1_PAD_PTA19_LLWU0_P5__PTA19 0x004c 0x0000 0x1 0x0
-#define ULP1_PAD_PTA19_LLWU0_P5__LPTMR0_ALT3 0x004c 0x0000 0xb 0x0
-#define ULP1_PAD_PTA19_LLWU0_P5__LLWU0_P5 0x004c 0x0000 0xd 0x0
-#define ULP1_PAD_PTA19_LLWU0_P5__FXIO0_D3 0x004c 0x0000 0x2 0x0
-#define ULP1_PAD_PTA19_LLWU0_P5__LPUART0_RX 0x004c 0xd1fc 0x4 0x2
-#define ULP1_PAD_PTA19_LLWU0_P5__TPM3_CH5 0x004c 0xd174 0x6 0x1
-#define ULP1_PAD_PTA19_LLWU0_P5__I2S1_RX_BCLK 0x004c 0xd1cc 0x7 0x1
-#define ULP1_PAD_PTA20__ADC0_CH7A 0x0050 0x0000 0x0 0x0
-#define ULP1_PAD_PTA20__PTA20 0x0050 0x0000 0x1 0x0
-#define ULP1_PAD_PTA20__FXIO0_D4 0x0050 0x0000 0x2 0x0
-#define ULP1_PAD_PTA20__LPSPI0_SIN 0x0050 0xd114 0x3 0x2
-#define ULP1_PAD_PTA20__LPUART1_CTS_B 0x0050 0xd204 0x4 0x2
-#define ULP1_PAD_PTA20__LPI2C1_SCL 0x0050 0xd188 0x5 0x2
-#define ULP1_PAD_PTA20__TPM0_CLKIN 0x0050 0xd1a8 0x6 0x1
-#define ULP1_PAD_PTA20__I2S1_RX_FS 0x0050 0xd1d0 0x7 0x1
-#define ULP1_PAD_PTA21__ADC0_CH7B 0x0054 0x0000 0x0 0x0
-#define ULP1_PAD_PTA21__PTA21 0x0054 0x0000 0x1 0x0
-#define ULP1_PAD_PTA21__FXIO0_D5 0x0054 0x0000 0x2 0x0
-#define ULP1_PAD_PTA21__LPSPI0_SOUT 0x0054 0xd118 0x3 0x2
-#define ULP1_PAD_PTA21__LPUART1_RTS_B 0x0054 0x0000 0x4 0x0
-#define ULP1_PAD_PTA21__LPI2C1_SDA 0x0054 0xd18c 0x5 0x2
-#define ULP1_PAD_PTA21__TPM0_CH0 0x0054 0xd138 0x6 0x2
-#define ULP1_PAD_PTA21__I2S1_RXD0 0x0054 0xd1e4 0x7 0x1
-#define ULP1_PAD_PTA22__ADC0_CH6A 0x0058 0x0000 0x0 0x0
-#define ULP1_PAD_PTA22__PTA22 0x0058 0x0000 0x1 0x0
-#define ULP1_PAD_PTA22__LPTMR0_ALT2 0x0058 0x0000 0xb 0x0
-#define ULP1_PAD_PTA22__EWM_OUT_B 0x0058 0x0000 0xc 0x0
-#define ULP1_PAD_PTA22__FXIO0_D6 0x0058 0x0000 0x2 0x0
-#define ULP1_PAD_PTA22__LPSPI0_SCK 0x0058 0xd110 0x3 0x2
-#define ULP1_PAD_PTA22__LPUART1_TX 0x0058 0xd20c 0x4 0x2
-#define ULP1_PAD_PTA22__LPI2C1_HREQ 0x0058 0xd184 0x5 0x2
-#define ULP1_PAD_PTA22__TPM0_CH1 0x0058 0xd13c 0x6 0x2
-#define ULP1_PAD_PTA22__I2S1_RXD1 0x0058 0xd1e8 0x7 0x1
-#define ULP1_PAD_PTA23_LLWU0_P6__ADC0_CH6B 0x005c 0x0000 0x0 0x0
-#define ULP1_PAD_PTA23_LLWU0_P6__PTA23 0x005c 0x0000 0x1 0x0
-#define ULP1_PAD_PTA23_LLWU0_P6__LLWU0_P6 0x005c 0x0000 0xd 0x0
-#define ULP1_PAD_PTA23_LLWU0_P6__FXIO0_D7 0x005c 0x0000 0x2 0x0
-#define ULP1_PAD_PTA23_LLWU0_P6__LPSPI0_PCS0 0x005c 0xd100 0x3 0x2
-#define ULP1_PAD_PTA23_LLWU0_P6__LPUART1_RX 0x005c 0xd208 0x4 0x2
-#define ULP1_PAD_PTA23_LLWU0_P6__TPM0_CH2 0x005c 0xd140 0x6 0x2
-#define ULP1_PAD_PTA23_LLWU0_P6__I2S1_MCLK 0x005c 0xd1c8 0x7 0x1
-#define ULP1_PAD_PTA24__ADC0_CH5A 0x0060 0x0000 0x0 0x0
-#define ULP1_PAD_PTA24__PTA24 0x0060 0x0000 0x1 0x0
-#define ULP1_PAD_PTA24__FXIO0_D8 0x0060 0x0000 0x2 0x0
-#define ULP1_PAD_PTA24__LPSPI1_PCS1 0x0060 0xd120 0x3 0x2
-#define ULP1_PAD_PTA24__LPUART2_CTS_B 0x0060 0xd210 0x4 0x2
-#define ULP1_PAD_PTA24__LPI2C2_SCL 0x0060 0xd194 0x5 0x2
-#define ULP1_PAD_PTA24__TPM0_CH3 0x0060 0xd144 0x6 0x2
-#define ULP1_PAD_PTA24__I2S1_TX_BCLK 0x0060 0xd1d4 0x7 0x1
-#define ULP1_PAD_PTA25__ADC0_CH5B 0x0064 0x0000 0x0 0x0
-#define ULP1_PAD_PTA25__PTA25 0x0064 0x0000 0x1 0x0
-#define ULP1_PAD_PTA25__FXIO0_D9 0x0064 0x0000 0x2 0x0
-#define ULP1_PAD_PTA25__LPSPI1_PCS2 0x0064 0xd124 0x3 0x2
-#define ULP1_PAD_PTA25__LPUART2_RTS_B 0x0064 0x0000 0x4 0x0
-#define ULP1_PAD_PTA25__LPI2C2_SDA 0x0064 0xd198 0x5 0x2
-#define ULP1_PAD_PTA25__TPM0_CH4 0x0064 0xd148 0x6 0x2
-#define ULP1_PAD_PTA25__I2S1_TX_FS 0x0064 0xd1d8 0x7 0x1
-#define ULP1_PAD_PTA26__PTA26 0x0068 0x0000 0x1 0x0
-#define ULP1_PAD_PTA26__JTAG_TMS_SWD_DIO 0x0068 0x0000 0xa 0x0
-#define ULP1_PAD_PTA26__FXIO0_D10 0x0068 0x0000 0x2 0x0
-#define ULP1_PAD_PTA26__LPSPI1_PCS3 0x0068 0xd128 0x3 0x2
-#define ULP1_PAD_PTA26__LPUART2_TX 0x0068 0xd218 0x4 0x2
-#define ULP1_PAD_PTA26__LPI2C2_HREQ 0x0068 0xd190 0x5 0x2
-#define ULP1_PAD_PTA26__TPM0_CH5 0x0068 0xd14c 0x6 0x2
-#define ULP1_PAD_PTA26__I2S1_RXD2 0x0068 0xd1ec 0x7 0x1
-#define ULP1_PAD_PTA27__PTA27 0x006c 0x0000 0x1 0x0
-#define ULP1_PAD_PTA27__JTAG_TDO 0x006c 0x0000 0xa 0x0
-#define ULP1_PAD_PTA27__FXIO0_D11 0x006c 0x0000 0x2 0x0
-#define ULP1_PAD_PTA27__LPUART2_RX 0x006c 0xd214 0x4 0x2
-#define ULP1_PAD_PTA27__TPM1_CH1 0x006c 0xd154 0x6 0x2
-#define ULP1_PAD_PTA27__I2S1_RXD3 0x006c 0xd1f0 0x7 0x1
-#define ULP1_PAD_PTA28__PTA28 0x0070 0x0000 0x1 0x0
-#define ULP1_PAD_PTA28__JTAG_TDI 0x0070 0x0000 0xa 0x0
-#define ULP1_PAD_PTA28__FXIO0_D12 0x0070 0x0000 0x2 0x0
-#define ULP1_PAD_PTA28__LPSPI1_SIN 0x0070 0xd130 0x3 0x2
-#define ULP1_PAD_PTA28__LPUART3_CTS_B 0x0070 0xd21c 0x4 0x2
-#define ULP1_PAD_PTA28__LPI2C3_SCL 0x0070 0xd1a0 0x5 0x2
-#define ULP1_PAD_PTA28__TPM1_CLKIN 0x0070 0xd1ac 0x6 0x2
-#define ULP1_PAD_PTA28__I2S1_TXD2 0x0070 0x0000 0x7 0x0
-#define ULP1_PAD_PTA29__PTA29 0x0074 0x0000 0x1 0x0
-#define ULP1_PAD_PTA29__JTAG_TCLK_SWD_CLK 0x0074 0x0000 0xa 0x0
-#define ULP1_PAD_PTA29__FXIO0_D13 0x0074 0x0000 0x2 0x0
-#define ULP1_PAD_PTA29__LPSPI1_SOUT 0x0074 0xd134 0x3 0x1
-#define ULP1_PAD_PTA29__LPUART3_RTS_B 0x0074 0x0000 0x4 0x0
-#define ULP1_PAD_PTA29__LPI2C3_SDA 0x0074 0xd1a4 0x5 0x1
-#define ULP1_PAD_PTA29__TPM1_CH0 0x0074 0xd150 0x6 0x2
-#define ULP1_PAD_PTA29__I2S1_TXD3 0x0074 0x0000 0x7 0x0
-#define ULP1_PAD_PTA30__ADC0_CH4A 0x0078 0x0000 0x0 0x0
-#define ULP1_PAD_PTA30__PTA30 0x0078 0x0000 0x1 0x0
-#define ULP1_PAD_PTA30__JTAG_TRST_B 0x0078 0x0000 0xa 0x0
-#define ULP1_PAD_PTA30__FXIO0_D14 0x0078 0x0000 0x2 0x0
-#define ULP1_PAD_PTA30__LPSPI1_SCK 0x0078 0xd12c 0x3 0x1
-#define ULP1_PAD_PTA30__LPUART3_TX 0x0078 0xd224 0x4 0x1
-#define ULP1_PAD_PTA30__LPI2C3_HREQ 0x0078 0xd19c 0x5 0x1
-#define ULP1_PAD_PTA30__TPM2_CLKIN 0x0078 0xd1f4 0x6 0x2
-#define ULP1_PAD_PTA30__I2S1_TXD0 0x0078 0x0000 0x7 0x0
-#define ULP1_PAD_PTA31_LLWU0_P7__ADC0_CH4B 0x007c 0x0000 0x0 0x0
-#define ULP1_PAD_PTA31_LLWU0_P7__PTA31 0x007c 0x0000 0x1 0x0
-#define ULP1_PAD_PTA31_LLWU0_P7__LPTMR0_ALT1 0x007c 0x0000 0xb 0x0
-#define ULP1_PAD_PTA31_LLWU0_P7__EWM_IN 0x007c 0xd228 0xc 0x1
-#define ULP1_PAD_PTA31_LLWU0_P7__LLWU0_P7 0x007c 0x0000 0xd 0x0
-#define ULP1_PAD_PTA31_LLWU0_P7__FXIO0_D15 0x007c 0x0000 0x2 0x0
-#define ULP1_PAD_PTA31_LLWU0_P7__LPSPI1_PCS0 0x007c 0xd11c 0x3 0x2
-#define ULP1_PAD_PTA31_LLWU0_P7__LPUART3_RX 0x007c 0xd220 0x4 0x2
-#define ULP1_PAD_PTA31_LLWU0_P7__TPM2_CH0 0x007c 0xd158 0x6 0x2
-#define ULP1_PAD_PTA31_LLWU0_P7__I2S1_TXD1 0x007c 0x0000 0x7 0x0
-#define ULP1_PAD_PTB0__ADC0_CH0A 0x0080 0x0000 0x0 0x0
-#define ULP1_PAD_PTB0__PTB0 0x0080 0x0000 0x1 0x0
-#define ULP1_PAD_PTB0__CMP1_OUT 0x0080 0x0000 0xb 0x0
-#define ULP1_PAD_PTB0__EWM_OUT_B 0x0080 0x0000 0xc 0x0
-#define ULP1_PAD_PTB0__FXIO0_D16 0x0080 0x0000 0x2 0x0
-#define ULP1_PAD_PTB0__LPSPI0_SIN 0x0080 0xd114 0x3 0x3
-#define ULP1_PAD_PTB0__LPUART0_TX 0x0080 0xd200 0x4 0x3
-#define ULP1_PAD_PTB0__TPM2_CH1 0x0080 0xd15c 0x6 0x2
-#define ULP1_PAD_PTB0__CLKOUT 0x0080 0x0000 0x9 0x0
-#define ULP1_PAD_PTB1_LLWU0_P8__ADC0_CH0B 0x0084 0x0000 0x0 0x0
-#define ULP1_PAD_PTB1_LLWU0_P8__PTB1 0x0084 0x0000 0x1 0x0
-#define ULP1_PAD_PTB1_LLWU0_P8__RTC_CLKOUT 0x0084 0x0000 0xb 0x0
-#define ULP1_PAD_PTB1_LLWU0_P8__EWM_IN 0x0084 0xd228 0xc 0x2
-#define ULP1_PAD_PTB1_LLWU0_P8__LLWU0_P8 0x0084 0x0000 0xd 0x0
-#define ULP1_PAD_PTB1_LLWU0_P8__FXIO0_D17 0x0084 0x0000 0x2 0x0
-#define ULP1_PAD_PTB1_LLWU0_P8__LPSPI0_SOUT 0x0084 0xd118 0x3 0x3
-#define ULP1_PAD_PTB1_LLWU0_P8__LPUART0_RX 0x0084 0xd1fc 0x4 0x3
-#define ULP1_PAD_PTB1_LLWU0_P8__TPM3_CLKIN 0x0084 0xd1b0 0x6 0x3
-#define ULP1_PAD_PTB1_LLWU0_P8__I2S1_TX_BCLK 0x0084 0xd1d4 0x7 0x2
-#define ULP1_PAD_PTB2__ADC0_CH1A 0x0088 0x0000 0x0 0x0
-#define ULP1_PAD_PTB2__PTB2 0x0088 0x0000 0x1 0x0
-#define ULP1_PAD_PTB2__TRACE_CLKOUT 0x0088 0x0000 0xa 0x0
-#define ULP1_PAD_PTB2__FXIO0_D18 0x0088 0x0000 0x2 0x0
-#define ULP1_PAD_PTB2__LPSPI0_SCK 0x0088 0xd110 0x3 0x3
-#define ULP1_PAD_PTB2__LPUART1_TX 0x0088 0xd20c 0x4 0x3
-#define ULP1_PAD_PTB2__TPM3_CH0 0x0088 0xd160 0x6 0x2
-#define ULP1_PAD_PTB2__I2S1_TX_FS 0x0088 0xd1d8 0x7 0x2
-#define ULP1_PAD_PTB3_LLWU0_P9__ADC0_CH1B 0x008c 0x0000 0x0 0x0
-#define ULP1_PAD_PTB3_LLWU0_P9__PTB3 0x008c 0x0000 0x1 0x0
-#define ULP1_PAD_PTB3_LLWU0_P9__TRACE_D0 0x008c 0x0000 0xa 0x0
-#define ULP1_PAD_PTB3_LLWU0_P9__LPTMR1_ALT2 0x008c 0x0000 0xb 0x0
-#define ULP1_PAD_PTB3_LLWU0_P9__LLWU0_P9 0x008c 0x0000 0xd 0x0
-#define ULP1_PAD_PTB3_LLWU0_P9__FXIO0_D19 0x008c 0x0000 0x2 0x0
-#define ULP1_PAD_PTB3_LLWU0_P9__LPSPI0_PCS0 0x008c 0xd100 0x3 0x3
-#define ULP1_PAD_PTB3_LLWU0_P9__LPUART1_RX 0x008c 0xd208 0x4 0x3
-#define ULP1_PAD_PTB3_LLWU0_P9__TPM3_CH1 0x008c 0xd164 0x6 0x2
-#define ULP1_PAD_PTB3_LLWU0_P9__I2S1_TXD0 0x008c 0x0000 0x7 0x0
-#define ULP1_PAD_PTB4__PTB4 0x0090 0x0000 0x1 0x0
-#define ULP1_PAD_PTB4__TRACE_D1 0x0090 0x0000 0xa 0x0
-#define ULP1_PAD_PTB4__BOOTCFG0 0x0090 0x0000 0xd 0x0
-#define ULP1_PAD_PTB4__FXIO0_D20 0x0090 0x0000 0x2 0x0
-#define ULP1_PAD_PTB4__LPSPI0_PCS1 0x0090 0xd104 0x3 0x3
-#define ULP1_PAD_PTB4__LPUART2_TX 0x0090 0xd218 0x4 0x3
-#define ULP1_PAD_PTB4__LPI2C0_HREQ 0x0090 0xd178 0x5 0x3
-#define ULP1_PAD_PTB4__TPM3_CH2 0x0090 0xd168 0x6 0x2
-#define ULP1_PAD_PTB4__I2S1_TXD1 0x0090 0x0000 0x7 0x0
-#define ULP1_PAD_PTB5__PTB5 0x0094 0x0000 0x1 0x0
-#define ULP1_PAD_PTB5__TRACE_D2 0x0094 0x0000 0xa 0x0
-#define ULP1_PAD_PTB5__BOOTCFG1 0x0094 0x0000 0xd 0x0
-#define ULP1_PAD_PTB5__FXIO0_D21 0x0094 0x0000 0x2 0x0
-#define ULP1_PAD_PTB5__LPSPI0_PCS2 0x0094 0xd108 0x3 0x3
-#define ULP1_PAD_PTB5__LPUART2_RX 0x0094 0xd214 0x4 0x3
-#define ULP1_PAD_PTB5__LPI2C1_HREQ 0x0094 0xd184 0x5 0x3
-#define ULP1_PAD_PTB5__TPM3_CH3 0x0094 0xd16c 0x6 0x2
-#define ULP1_PAD_PTB5__I2S1_TXD2 0x0094 0x0000 0x7 0x0
-#define ULP1_PAD_PTB6_LLWU0_P10__PTB6 0x0098 0x0000 0x1 0x0
-#define ULP1_PAD_PTB6_LLWU0_P10__TRACE_D3 0x0098 0x0000 0xa 0x0
-#define ULP1_PAD_PTB6_LLWU0_P10__LPTMR1_ALT3 0x0098 0x0000 0xb 0x0
-#define ULP1_PAD_PTB6_LLWU0_P10__LLWU0_P10 0x0098 0x0000 0xd 0x0
-#define ULP1_PAD_PTB6_LLWU0_P10__FXIO0_D22 0x0098 0x0000 0x2 0x0
-#define ULP1_PAD_PTB6_LLWU0_P10__LPSPI0_PCS3 0x0098 0xd10c 0x3 0x3
-#define ULP1_PAD_PTB6_LLWU0_P10__LPUART3_TX 0x0098 0xd224 0x4 0x3
-#define ULP1_PAD_PTB6_LLWU0_P10__LPI2C0_SCL 0x0098 0xd17c 0x5 0x3
-#define ULP1_PAD_PTB6_LLWU0_P10__TPM3_CH4 0x0098 0xd170 0x6 0x2
-#define ULP1_PAD_PTB6_LLWU0_P10__I2S1_TXD3 0x0098 0x0000 0x7 0x0
-#define ULP1_PAD_PTB7_LLWU0_P11__PTB7 0x009c 0x0000 0x1 0x0
-#define ULP1_PAD_PTB7_LLWU0_P11__CMP1_OUT 0x009c 0x0000 0xb 0x0
-#define ULP1_PAD_PTB7_LLWU0_P11__LLWU0_P11 0x009c 0x0000 0xd 0x0
-#define ULP1_PAD_PTB7_LLWU0_P11__FXIO0_D23 0x009c 0x0000 0x2 0x0
-#define ULP1_PAD_PTB7_LLWU0_P11__LPSPI1_SIN 0x009c 0xd130 0x3 0x3
-#define ULP1_PAD_PTB7_LLWU0_P11__LPUART3_RX 0x009c 0xd220 0x4 0x3
-#define ULP1_PAD_PTB7_LLWU0_P11__LPI2C0_SDA 0x009c 0xd180 0x5 0x3
-#define ULP1_PAD_PTB7_LLWU0_P11__TPM3_CH5 0x009c 0xd174 0x6 0x2
-#define ULP1_PAD_PTB7_LLWU0_P11__I2S1_MCLK 0x009c 0xd1c8 0x7 0x2
-#define ULP1_PAD_PTB7_LLWU0_P11__QSPIA_SS1_B 0x009c 0x0000 0x8 0x0
-#define ULP1_PAD_PTB8__CMP0_IN0A 0x00a0 0x0000 0x0 0x0
-#define ULP1_PAD_PTB8__PTB8 0x00a0 0x0000 0x1 0x0
-#define ULP1_PAD_PTB8__RTC_CLKOUT 0x00a0 0x0000 0xb 0x0
-#define ULP1_PAD_PTB8__FXIO0_D24 0x00a0 0x0000 0x2 0x0
-#define ULP1_PAD_PTB8__LPSPI1_SOUT 0x00a0 0xd134 0x3 0x3
-#define ULP1_PAD_PTB8__LPI2C1_SCL 0x00a0 0xd188 0x5 0x3
-#define ULP1_PAD_PTB8__TPM0_CLKIN 0x00a0 0xd1a8 0x6 0x3
-#define ULP1_PAD_PTB8__I2S1_RX_BCLK 0x00a0 0xd1cc 0x7 0x2
-#define ULP1_PAD_PTB8__QSPIA_SS0_B 0x00a0 0x0000 0x8 0x0
-#define ULP1_PAD_PTB9_LLWU0_P12__CMP0_IN0B 0x00a4 0x0000 0x0 0x0
-#define ULP1_PAD_PTB9_LLWU0_P12__PTB9 0x00a4 0x0000 0x1 0x0
-#define ULP1_PAD_PTB9_LLWU0_P12__LLWU0_P12 0x00a4 0x0000 0xd 0x0
-#define ULP1_PAD_PTB9_LLWU0_P12__FXIO0_D25 0x00a4 0x0000 0x2 0x0
-#define ULP1_PAD_PTB9_LLWU0_P12__LPSPI1_SCK 0x00a4 0xd12c 0x3 0x3
-#define ULP1_PAD_PTB9_LLWU0_P12__LPI2C1_SDA 0x00a4 0xd18c 0x5 0x3
-#define ULP1_PAD_PTB9_LLWU0_P12__TPM0_CH0 0x00a4 0xd138 0x6 0x3
-#define ULP1_PAD_PTB9_LLWU0_P12__I2S1_RX_FS 0x00a4 0xd1d0 0x7 0x2
-#define ULP1_PAD_PTB9_LLWU0_P12__QSPIA_DQS 0x00a4 0x0000 0x8 0x0
-#define ULP1_PAD_PTB10__CMP0_IN1A 0x00a8 0x0000 0x0 0x0
-#define ULP1_PAD_PTB10__PTB10 0x00a8 0x0000 0x1 0x0
-#define ULP1_PAD_PTB10__TRACE_D4 0x00a8 0x0000 0xa 0x0
-#define ULP1_PAD_PTB10__FXIO0_D26 0x00a8 0x0000 0x2 0x0
-#define ULP1_PAD_PTB10__LPSPI1_PCS0 0x00a8 0xd11c 0x3 0x3
-#define ULP1_PAD_PTB10__LPI2C2_SCL 0x00a8 0xd194 0x5 0x3
-#define ULP1_PAD_PTB10__TPM0_CH1 0x00a8 0xd13c 0x6 0x3
-#define ULP1_PAD_PTB10__I2S1_RXD0 0x00a8 0xd1e4 0x7 0x2
-#define ULP1_PAD_PTB10__QSPIA_DATA7 0x00a8 0x0000 0x8 0x0
-#define ULP1_PAD_PTB11__CMP0_IN1B 0x00ac 0x0000 0x0 0x0
-#define ULP1_PAD_PTB11__PTB11 0x00ac 0x0000 0x1 0x0
-#define ULP1_PAD_PTB11__TRACE_D5 0x00ac 0x0000 0xa 0x0
-#define ULP1_PAD_PTB11__FXIO0_D27 0x00ac 0x0000 0x2 0x0
-#define ULP1_PAD_PTB11__LPSPI1_PCS1 0x00ac 0xd120 0x3 0x3
-#define ULP1_PAD_PTB11__LPI2C2_SDA 0x00ac 0xd198 0x5 0x3
-#define ULP1_PAD_PTB11__TPM1_CLKIN 0x00ac 0xd1ac 0x6 0x3
-#define ULP1_PAD_PTB11__I2S1_RXD1 0x00ac 0xd1e8 0x7 0x2
-#define ULP1_PAD_PTB11__QSPIA_DATA6 0x00ac 0x0000 0x8 0x0
-#define ULP1_PAD_PTB12__ADC1_CH0A 0x00b0 0x0000 0x0 0x0
-#define ULP1_PAD_PTB12__PTB12 0x00b0 0x0000 0x1 0x0
-#define ULP1_PAD_PTB12__TRACE_D6 0x00b0 0x0000 0xa 0x0
-#define ULP1_PAD_PTB12__FXIO0_D28 0x00b0 0x0000 0x2 0x0
-#define ULP1_PAD_PTB12__LPSPI1_PCS2 0x00b0 0xd124 0x3 0x3
-#define ULP1_PAD_PTB12__LPI2C3_SCL 0x00b0 0xd1a0 0x5 0x3
-#define ULP1_PAD_PTB12__TPM1_CH0 0x00b0 0xd150 0x6 0x3
-#define ULP1_PAD_PTB12__I2S1_RXD2 0x00b0 0xd1ec 0x7 0x2
-#define ULP1_PAD_PTB12__QSPIA_DATA5 0x00b0 0x0000 0x8 0x0
-#define ULP1_PAD_PTB13__ADC1_CH0B 0x00b4 0x0000 0x0 0x0
-#define ULP1_PAD_PTB13__PTB13 0x00b4 0x0000 0x1 0x0
-#define ULP1_PAD_PTB13__TRACE_D7 0x00b4 0x0000 0xa 0x0
-#define ULP1_PAD_PTB13__FXIO0_D29 0x00b4 0x0000 0x2 0x0
-#define ULP1_PAD_PTB13__LPSPI1_PCS3 0x00b4 0xd128 0x3 0x3
-#define ULP1_PAD_PTB13__LPI2C3_SDA 0x00b4 0xd1a4 0x5 0x3
-#define ULP1_PAD_PTB13__TPM1_CH1 0x00b4 0xd154 0x6 0x3
-#define ULP1_PAD_PTB13__I2S1_RXD3 0x00b4 0xd1f0 0x7 0x2
-#define ULP1_PAD_PTB13__QSPIA_DATA4 0x00b4 0x0000 0x8 0x0
-#define ULP1_PAD_PTB14_LLWU0_P13__ADC1_CH1A 0x00b8 0x0000 0x0 0x0
-#define ULP1_PAD_PTB14_LLWU0_P13__PTB14 0x00b8 0x0000 0x1 0x0
-#define ULP1_PAD_PTB14_LLWU0_P13__LLWU0_P13 0x00b8 0x0000 0xd 0x0
-#define ULP1_PAD_PTB14_LLWU0_P13__FXIO0_D30 0x00b8 0x0000 0x2 0x0
-#define ULP1_PAD_PTB14_LLWU0_P13__LPI2C2_HREQ 0x00b8 0xd190 0x5 0x3
-#define ULP1_PAD_PTB14_LLWU0_P13__TPM2_CLKIN 0x00b8 0xd1f4 0x6 0x3
-#define ULP1_PAD_PTB14_LLWU0_P13__QSPIA_SS0_B 0x00b8 0x0000 0x8 0x0
-#define ULP1_PAD_PTB14_LLWU0_P13__QSPIA_SCLK_B 0x00b8 0x0000 0x9 0x0
-#define ULP1_PAD_PTB15__ADC1_CH1B 0x00bc 0x0000 0x0 0x0
-#define ULP1_PAD_PTB15__PTB15 0x00bc 0x0000 0x1 0x0
-#define ULP1_PAD_PTB15__FXIO0_D31 0x00bc 0x0000 0x2 0x0
-#define ULP1_PAD_PTB15__LPI2C3_HREQ 0x00bc 0xd19c 0x5 0x3
-#define ULP1_PAD_PTB15__TPM2_CH0 0x00bc 0xd158 0x6 0x3
-#define ULP1_PAD_PTB15__QSPIA_SCLK 0x00bc 0x0000 0x8 0x0
-#define ULP1_PAD_PTB16_LLWU0_P14__ADC0_CH2A 0x00c0 0x0000 0x0 0x0
-#define ULP1_PAD_PTB16_LLWU0_P14__PTB16 0x00c0 0x0000 0x1 0x0
-#define ULP1_PAD_PTB16_LLWU0_P14__LLWU0_P14 0x00c0 0x0000 0xd 0x0
-#define ULP1_PAD_PTB16_LLWU0_P14__TPM2_CH1 0x00c0 0xd15c 0x6 0x3
-#define ULP1_PAD_PTB16_LLWU0_P14__QSPIA_DATA3 0x00c0 0x0000 0x8 0x0
-#define ULP1_PAD_PTB17__ADC0_CH2B 0x00c4 0x0000 0x0 0x0
-#define ULP1_PAD_PTB17__PTB17 0x00c4 0x0000 0x1 0x0
-#define ULP1_PAD_PTB17__TPM3_CLKIN 0x00c4 0xd1b0 0x6 0x2
-#define ULP1_PAD_PTB17__QSPIA_DATA2 0x00c4 0x0000 0x8 0x0
-#define ULP1_PAD_PTB18__ADC0_CH3A 0x00c8 0x0000 0x0 0x0
-#define ULP1_PAD_PTB18__PTB18 0x00c8 0x0000 0x1 0x0
-#define ULP1_PAD_PTB18__TPM3_CH0 0x00c8 0xd160 0x6 0x3
-#define ULP1_PAD_PTB18__QSPIA_DATA1 0x00c8 0x0000 0x8 0x0
-#define ULP1_PAD_PTB19_LLWU0_P15__ADC0_CH3B 0x00cc 0x0000 0x0 0x0
-#define ULP1_PAD_PTB19_LLWU0_P15__PTB19 0x00cc 0x0000 0x1 0x0
-#define ULP1_PAD_PTB19_LLWU0_P15__USB0_ID 0x00cc 0x0000 0xa 0x0
-#define ULP1_PAD_PTB19_LLWU0_P15__LLWU0_P15 0x00cc 0x0000 0xd 0x0
-#define ULP1_PAD_PTB19_LLWU0_P15__TPM3_CH1 0x00cc 0xd164 0x6 0x3
-#define ULP1_PAD_PTB19_LLWU0_P15__QSPIA_DATA0 0x00cc 0x0000 0x8 0x0
-#define ULP1_PAD_PTC0__PTC0 0x0000 0x0000 0x1 0x0
-#define ULP1_PAD_PTC0__TRACE_D15 0x0000 0x0000 0xa 0x0
-#define ULP1_PAD_PTC0__LPUART4_CTS_B 0x0000 0x0244 0x4 0x1
-#define ULP1_PAD_PTC0__LPI2C4_SCL 0x0000 0x0278 0x5 0x1
-#define ULP1_PAD_PTC0__TPM4_CLKIN 0x0000 0x0298 0x6 0x1
-#define ULP1_PAD_PTC0__FB_AD0 0x0000 0x0000 0x9 0x0
-#define ULP1_PAD_PTC1__PTC1 0x0004 0x0000 0x1 0x0
-#define ULP1_PAD_PTC1__TRACE_D14 0x0004 0x0000 0xa 0x0
-#define ULP1_PAD_PTC1__LPUART4_RTS_B 0x0004 0x0000 0x4 0x0
-#define ULP1_PAD_PTC1__LPI2C4_SDA 0x0004 0x027c 0x5 0x1
-#define ULP1_PAD_PTC1__TPM4_CH0 0x0004 0x0280 0x6 0x1
-#define ULP1_PAD_PTC1__FB_AD1 0x0004 0x0000 0x9 0x0
-#define ULP1_PAD_PTC2__PTC2 0x0008 0x0000 0x1 0x0
-#define ULP1_PAD_PTC2__TRACE_D13 0x0008 0x0000 0xa 0x0
-#define ULP1_PAD_PTC2__LPUART4_TX 0x0008 0x024c 0x4 0x1
-#define ULP1_PAD_PTC2__LPI2C4_HREQ 0x0008 0x0274 0x5 0x1
-#define ULP1_PAD_PTC2__TPM4_CH1 0x0008 0x0284 0x6 0x1
-#define ULP1_PAD_PTC2__FB_AD2 0x0008 0x0000 0x9 0x0
-#define ULP1_PAD_PTC3__PTC3 0x000c 0x0000 0x1 0x0
-#define ULP1_PAD_PTC3__TRACE_D12 0x000c 0x0000 0xa 0x0
-#define ULP1_PAD_PTC3__LPUART4_RX 0x000c 0x0248 0x4 0x1
-#define ULP1_PAD_PTC3__TPM4_CH2 0x000c 0x0288 0x6 0x1
-#define ULP1_PAD_PTC3__FB_AD3 0x000c 0x0000 0x9 0x0
-#define ULP1_PAD_PTC4__PTC4 0x0010 0x0000 0x1 0x0
-#define ULP1_PAD_PTC4__TRACE_D11 0x0010 0x0000 0xa 0x0
-#define ULP1_PAD_PTC4__FXIO1_D0 0x0010 0x0204 0x2 0x1
-#define ULP1_PAD_PTC4__LPSPI2_PCS1 0x0010 0x02a0 0x3 0x1
-#define ULP1_PAD_PTC4__LPUART5_CTS_B 0x0010 0x0250 0x4 0x1
-#define ULP1_PAD_PTC4__LPI2C5_SCL 0x0010 0x02bc 0x5 0x1
-#define ULP1_PAD_PTC4__TPM4_CH3 0x0010 0x028c 0x6 0x1
-#define ULP1_PAD_PTC4__FB_AD4 0x0010 0x0000 0x9 0x0
-#define ULP1_PAD_PTC5__PTC5 0x0014 0x0000 0x1 0x0
-#define ULP1_PAD_PTC5__TRACE_D10 0x0014 0x0000 0xa 0x0
-#define ULP1_PAD_PTC5__FXIO1_D1 0x0014 0x0208 0x2 0x1
-#define ULP1_PAD_PTC5__LPSPI2_PCS2 0x0014 0x02a4 0x3 0x1
-#define ULP1_PAD_PTC5__LPUART5_RTS_B 0x0014 0x0000 0x4 0x0
-#define ULP1_PAD_PTC5__LPI2C5_SDA 0x0014 0x02c0 0x5 0x1
-#define ULP1_PAD_PTC5__TPM4_CH4 0x0014 0x0290 0x6 0x1
-#define ULP1_PAD_PTC5__FB_AD5 0x0014 0x0000 0x9 0x0
-#define ULP1_PAD_PTC6__PTC6 0x0018 0x0000 0x1 0x0
-#define ULP1_PAD_PTC6__TRACE_D9 0x0018 0x0000 0xa 0x0
-#define ULP1_PAD_PTC6__FXIO1_D2 0x0018 0x020c 0x2 0x1
-#define ULP1_PAD_PTC6__LPSPI2_PCS3 0x0018 0x02a8 0x3 0x1
-#define ULP1_PAD_PTC6__LPUART5_TX 0x0018 0x0258 0x4 0x1
-#define ULP1_PAD_PTC6__LPI2C5_HREQ 0x0018 0x02b8 0x5 0x1
-#define ULP1_PAD_PTC6__TPM4_CH5 0x0018 0x0294 0x6 0x1
-#define ULP1_PAD_PTC6__FB_AD6 0x0018 0x0000 0x9 0x0
-#define ULP1_PAD_PTC7__PTC7 0x001c 0x0000 0x1 0x0
-#define ULP1_PAD_PTC7__TRACE_D8 0x001c 0x0000 0xa 0x0
-#define ULP1_PAD_PTC7__FXIO1_D3 0x001c 0x0210 0x2 0x1
-#define ULP1_PAD_PTC7__LPUART5_RX 0x001c 0x0254 0x4 0x1
-#define ULP1_PAD_PTC7__TPM5_CH1 0x001c 0x02c8 0x6 0x1
-#define ULP1_PAD_PTC7__FB_AD7 0x001c 0x0000 0x9 0x0
-#define ULP1_PAD_PTC8__PTC8 0x0020 0x0000 0x1 0x0
-#define ULP1_PAD_PTC8__TRACE_D7 0x0020 0x0000 0xa 0x0
-#define ULP1_PAD_PTC8__FXIO1_D4 0x0020 0x0214 0x2 0x1
-#define ULP1_PAD_PTC8__LPSPI2_SIN 0x0020 0x02b0 0x3 0x1
-#define ULP1_PAD_PTC8__LPUART6_CTS_B 0x0020 0x025c 0x4 0x1
-#define ULP1_PAD_PTC8__LPI2C6_SCL 0x0020 0x02fc 0x5 0x1
-#define ULP1_PAD_PTC8__TPM5_CLKIN 0x0020 0x02cc 0x6 0x1
-#define ULP1_PAD_PTC8__FB_AD8 0x0020 0x0000 0x9 0x0
-#define ULP1_PAD_PTC9__PTC9 0x0024 0x0000 0x1 0x0
-#define ULP1_PAD_PTC9__TRACE_D6 0x0024 0x0000 0xa 0x0
-#define ULP1_PAD_PTC9__FXIO1_D5 0x0024 0x0218 0x2 0x1
-#define ULP1_PAD_PTC9__LPSPI2_SOUT 0x0024 0x02b4 0x3 0x1
-#define ULP1_PAD_PTC9__LPUART6_RTS_B 0x0024 0x0000 0x4 0x0
-#define ULP1_PAD_PTC9__LPI2C6_SDA 0x0024 0x0300 0x5 0x1
-#define ULP1_PAD_PTC9__TPM5_CH0 0x0024 0x02c4 0x6 0x1
-#define ULP1_PAD_PTC9__FB_AD9 0x0024 0x0000 0x9 0x0
-#define ULP1_PAD_PTC10__PTC10 0x0028 0x0000 0x1 0x0
-#define ULP1_PAD_PTC10__TRACE_D5 0x0028 0x0000 0xa 0x0
-#define ULP1_PAD_PTC10__FXIO1_D6 0x0028 0x021c 0x2 0x1
-#define ULP1_PAD_PTC10__LPSPI2_SCK 0x0028 0x02ac 0x3 0x1
-#define ULP1_PAD_PTC10__LPUART6_TX 0x0028 0x0264 0x4 0x1
-#define ULP1_PAD_PTC10__LPI2C6_HREQ 0x0028 0x02f8 0x5 0x1
-#define ULP1_PAD_PTC10__TPM7_CH3 0x0028 0x02e8 0x6 0x1
-#define ULP1_PAD_PTC10__FB_AD10 0x0028 0x0000 0x9 0x0
-#define ULP1_PAD_PTC11__PTC11 0x002c 0x0000 0x1 0x0
-#define ULP1_PAD_PTC11__TRACE_D4 0x002c 0x0000 0xa 0x0
-#define ULP1_PAD_PTC11__FXIO1_D7 0x002c 0x0220 0x2 0x1
-#define ULP1_PAD_PTC11__LPSPI2_PCS0 0x002c 0x029c 0x3 0x1
-#define ULP1_PAD_PTC11__LPUART6_RX 0x002c 0x0260 0x4 0x1
-#define ULP1_PAD_PTC11__TPM7_CH4 0x002c 0x02ec 0x6 0x1
-#define ULP1_PAD_PTC11__FB_AD11 0x002c 0x0000 0x9 0x0
-#define ULP1_PAD_PTC12__PTC12 0x0030 0x0000 0x1 0x0
-#define ULP1_PAD_PTC12__TRACE_D3 0x0030 0x0000 0xa 0x0
-#define ULP1_PAD_PTC12__FXIO1_D8 0x0030 0x0224 0x2 0x1
-#define ULP1_PAD_PTC12__LPSPI3_PCS1 0x0030 0x0314 0x3 0x1
-#define ULP1_PAD_PTC12__LPUART7_CTS_B 0x0030 0x0268 0x4 0x1
-#define ULP1_PAD_PTC12__LPI2C7_SCL 0x0030 0x0308 0x5 0x1
-#define ULP1_PAD_PTC12__TPM7_CH5 0x0030 0x02f0 0x6 0x1
-#define ULP1_PAD_PTC12__FB_AD12 0x0030 0x0000 0x9 0x0
-#define ULP1_PAD_PTC13__PTC13 0x0034 0x0000 0x1 0x0
-#define ULP1_PAD_PTC13__TRACE_D2 0x0034 0x0000 0xa 0x0
-#define ULP1_PAD_PTC13__FXIO1_D9 0x0034 0x0228 0x2 0x1
-#define ULP1_PAD_PTC13__LPSPI3_PCS2 0x0034 0x0318 0x3 0x1
-#define ULP1_PAD_PTC13__LPUART7_RTS_B 0x0034 0x0000 0x4 0x0
-#define ULP1_PAD_PTC13__LPI2C7_SDA 0x0034 0x030c 0x5 0x1
-#define ULP1_PAD_PTC13__TPM7_CLKIN 0x0034 0x02f4 0x6 0x1
-#define ULP1_PAD_PTC13__FB_AD13 0x0034 0x0000 0x9 0x0
-#define ULP1_PAD_PTC14__PTC14 0x0038 0x0000 0x1 0x0
-#define ULP1_PAD_PTC14__TRACE_D1 0x0038 0x0000 0xa 0x0
-#define ULP1_PAD_PTC14__FXIO1_D10 0x0038 0x022c 0x2 0x1
-#define ULP1_PAD_PTC14__LPSPI3_PCS3 0x0038 0x031c 0x3 0x1
-#define ULP1_PAD_PTC14__LPUART7_TX 0x0038 0x0270 0x4 0x1
-#define ULP1_PAD_PTC14__LPI2C7_HREQ 0x0038 0x0304 0x5 0x1
-#define ULP1_PAD_PTC14__TPM7_CH0 0x0038 0x02dc 0x6 0x1
-#define ULP1_PAD_PTC14__FB_AD14 0x0038 0x0000 0x9 0x0
-#define ULP1_PAD_PTC15__PTC15 0x003c 0x0000 0x1 0x0
-#define ULP1_PAD_PTC15__TRACE_D0 0x003c 0x0000 0xa 0x0
-#define ULP1_PAD_PTC15__FXIO1_D11 0x003c 0x0230 0x2 0x1
-#define ULP1_PAD_PTC15__LPUART7_RX 0x003c 0x026c 0x4 0x1
-#define ULP1_PAD_PTC15__TPM7_CH1 0x003c 0x02e0 0x6 0x1
-#define ULP1_PAD_PTC15__FB_AD15 0x003c 0x0000 0x9 0x0
-#define ULP1_PAD_PTC16__PTC16 0x0040 0x0000 0x1 0x0
-#define ULP1_PAD_PTC16__TRACE_CLKOUT 0x0040 0x0000 0xa 0x0
-#define ULP1_PAD_PTC16__FXIO1_D12 0x0040 0x0234 0x2 0x1
-#define ULP1_PAD_PTC16__LPSPI3_SIN 0x0040 0x0324 0x3 0x1
-#define ULP1_PAD_PTC16__TPM7_CH2 0x0040 0x02e4 0x6 0x1
-#define ULP1_PAD_PTC16__FB_ALE_FB_CS1_B_FB_TS_B 0x0040 0x0000 0x9 0x0
-#define ULP1_PAD_PTC17__PTC17 0x0044 0x0000 0x1 0x0
-#define ULP1_PAD_PTC17__FXIO1_D13 0x0044 0x0238 0x2 0x1
-#define ULP1_PAD_PTC17__LPSPI3_SOUT 0x0044 0x0328 0x3 0x1
-#define ULP1_PAD_PTC17__TPM6_CLKIN 0x0044 0x02d8 0x6 0x1
-#define ULP1_PAD_PTC17__FB_CS0_B 0x0044 0x0000 0x9 0x0
-#define ULP1_PAD_PTC18__PTC18 0x0048 0x0000 0x1 0x0
-#define ULP1_PAD_PTC18__FXIO1_D14 0x0048 0x023c 0x2 0x1
-#define ULP1_PAD_PTC18__LPSPI3_SCK 0x0048 0x0320 0x3 0x1
-#define ULP1_PAD_PTC18__TPM6_CH0 0x0048 0x02d0 0x6 0x1
-#define ULP1_PAD_PTC18__FB_OE_B 0x0048 0x0000 0x9 0x0
-#define ULP1_PAD_PTC19__PTC19 0x004c 0x0000 0x1 0x0
-#define ULP1_PAD_PTC19__FXIO1_D15 0x004c 0x0240 0x2 0x1
-#define ULP1_PAD_PTC19__LPSPI3_PCS0 0x004c 0x0310 0x3 0x1
-#define ULP1_PAD_PTC19__TPM6_CH1 0x004c 0x02d4 0x6 0x1
-#define ULP1_PAD_PTC19__FB_A16 0x004c 0x0000 0x9 0x0
-#define ULP1_PAD_PTD0__PTD0 0x0080 0x0000 0x1 0x0
-#define ULP1_PAD_PTD0__SDHC0_RESET_B 0x0080 0x0000 0x8 0x0
-#define ULP1_PAD_PTD1__PTD1 0x0084 0x0000 0x1 0x0
-#define ULP1_PAD_PTD1__SDHC0_CMD 0x0084 0x0000 0x8 0x0
-#define ULP1_PAD_PTD2__PTD2 0x0088 0x0000 0x1 0x0
-#define ULP1_PAD_PTD2__SDHC0_CLK 0x0088 0x0000 0x8 0x0
-#define ULP1_PAD_PTD3__PTD3 0x008c 0x0000 0x1 0x0
-#define ULP1_PAD_PTD3__SDHC0_D7 0x008c 0x0000 0x8 0x0
-#define ULP1_PAD_PTD4__PTD4 0x0090 0x0000 0x1 0x0
-#define ULP1_PAD_PTD4__SDHC0_D6 0x0090 0x0000 0x8 0x0
-#define ULP1_PAD_PTD5__PTD5 0x0094 0x0000 0x1 0x0
-#define ULP1_PAD_PTD5__SDHC0_D5 0x0094 0x0000 0x8 0x0
-#define ULP1_PAD_PTD6__PTD6 0x0098 0x0000 0x1 0x0
-#define ULP1_PAD_PTD6__SDHC0_D4 0x0098 0x0000 0x8 0x0
-#define ULP1_PAD_PTD7__PTD7 0x009c 0x0000 0x1 0x0
-#define ULP1_PAD_PTD7__SDHC0_D3 0x009c 0x0000 0x8 0x0
-#define ULP1_PAD_PTD8__PTD8 0x00a0 0x0000 0x1 0x0
-#define ULP1_PAD_PTD8__TPM4_CLKIN 0x00a0 0x0298 0x6 0x2
-#define ULP1_PAD_PTD8__SDHC0_D2 0x00a0 0x0000 0x8 0x0
-#define ULP1_PAD_PTD9__PTD9 0x00a4 0x0000 0x1 0x0
-#define ULP1_PAD_PTD9__TPM4_CH0 0x00a4 0x0280 0x6 0x2
-#define ULP1_PAD_PTD9__SDHC0_D1 0x00a4 0x0000 0x8 0x0
-#define ULP1_PAD_PTD10__PTD10 0x00a8 0x0000 0x1 0x0
-#define ULP1_PAD_PTD10__TPM4_CH1 0x00a8 0x0284 0x6 0x2
-#define ULP1_PAD_PTD10__SDHC0_D0 0x00a8 0x0000 0x8 0x0
-#define ULP1_PAD_PTD11__PTD11 0x00ac 0x0000 0x1 0x0
-#define ULP1_PAD_PTD11__TPM4_CH2 0x00ac 0x0288 0x6 0x2
-#define ULP1_PAD_PTD11__SDHC0_DQS 0x00ac 0x0000 0x8 0x0
-#define ULP1_PAD_PTE0__PTE0 0x0100 0x0000 0x1 0x0
-#define ULP1_PAD_PTE0__FXIO1_D31 0x0100 0x0000 0x2 0x0
-#define ULP1_PAD_PTE0__LPSPI2_PCS1 0x0100 0x02a0 0x3 0x2
-#define ULP1_PAD_PTE0__LPUART4_CTS_B 0x0100 0x0244 0x4 0x2
-#define ULP1_PAD_PTE0__LPI2C4_SCL 0x0100 0x0278 0x5 0x2
-#define ULP1_PAD_PTE0__SDHC1_D1 0x0100 0x0000 0x8 0x0
-#define ULP1_PAD_PTE0__FB_A25 0x0100 0x0000 0x9 0x0
-#define ULP1_PAD_PTE1__PTE1 0x0104 0x0000 0x1 0x0
-#define ULP1_PAD_PTE1__FXIO1_D30 0x0104 0x0000 0x2 0x0
-#define ULP1_PAD_PTE1__LPSPI2_PCS2 0x0104 0x02a4 0x3 0x2
-#define ULP1_PAD_PTE1__LPUART4_RTS_B 0x0104 0x0000 0x4 0x0
-#define ULP1_PAD_PTE1__LPI2C4_SDA 0x0104 0x027c 0x5 0x2
-#define ULP1_PAD_PTE1__SDHC1_D0 0x0104 0x0000 0x8 0x0
-#define ULP1_PAD_PTE1__FB_A26 0x0104 0x0000 0x9 0x0
-#define ULP1_PAD_PTE2__PTE2 0x0108 0x0000 0x1 0x0
-#define ULP1_PAD_PTE2__FXIO1_D29 0x0108 0x0000 0x2 0x0
-#define ULP1_PAD_PTE2__LPSPI2_PCS3 0x0108 0x02a8 0x3 0x2
-#define ULP1_PAD_PTE2__LPUART4_TX 0x0108 0x024c 0x4 0x2
-#define ULP1_PAD_PTE2__LPI2C4_HREQ 0x0108 0x0274 0x5 0x2
-#define ULP1_PAD_PTE2__SDHC1_CLK 0x0108 0x0000 0x8 0x0
-#define ULP1_PAD_PTE3__PTE3 0x010c 0x0000 0x1 0x0
-#define ULP1_PAD_PTE3__FXIO1_D28 0x010c 0x0000 0x2 0x0
-#define ULP1_PAD_PTE3__LPUART4_RX 0x010c 0x0248 0x4 0x2
-#define ULP1_PAD_PTE3__TPM5_CH1 0x010c 0x02c8 0x6 0x2
-#define ULP1_PAD_PTE3__SDHC1_CMD 0x010c 0x0000 0x8 0x0
-#define ULP1_PAD_PTE4__PTE4 0x0110 0x0000 0x1 0x0
-#define ULP1_PAD_PTE4__FXIO1_D27 0x0110 0x0000 0x2 0x0
-#define ULP1_PAD_PTE4__LPSPI2_SIN 0x0110 0x02b0 0x3 0x2
-#define ULP1_PAD_PTE4__LPUART5_CTS_B 0x0110 0x0250 0x4 0x2
-#define ULP1_PAD_PTE4__LPI2C5_SCL 0x0110 0x02bc 0x5 0x2
-#define ULP1_PAD_PTE4__TPM5_CLKIN 0x0110 0x02cc 0x6 0x2
-#define ULP1_PAD_PTE4__SDHC1_D3 0x0110 0x0000 0x8 0x0
-#define ULP1_PAD_PTE5__PTE5 0x0114 0x0000 0x1 0x0
-#define ULP1_PAD_PTE5__FXIO1_D26 0x0114 0x0000 0x2 0x0
-#define ULP1_PAD_PTE5__LPSPI2_SOUT 0x0114 0x02b4 0x3 0x2
-#define ULP1_PAD_PTE5__LPUART5_RTS_B 0x0114 0x0000 0x4 0x0
-#define ULP1_PAD_PTE5__LPI2C5_SDA 0x0114 0x02c0 0x5 0x2
-#define ULP1_PAD_PTE5__TPM5_CH0 0x0114 0x02c4 0x6 0x2
-#define ULP1_PAD_PTE5__SDHC1_D2 0x0114 0x0000 0x8 0x0
-#define ULP1_PAD_PTE6__PTE6 0x0118 0x0000 0x1 0x0
-#define ULP1_PAD_PTE6__FXIO1_D25 0x0118 0x0000 0x2 0x0
-#define ULP1_PAD_PTE6__LPSPI2_SCK 0x0118 0x02ac 0x3 0x2
-#define ULP1_PAD_PTE6__LPUART5_TX 0x0118 0x0258 0x4 0x2
-#define ULP1_PAD_PTE6__LPI2C5_HREQ 0x0118 0x02b8 0x5 0x2
-#define ULP1_PAD_PTE6__TPM7_CH3 0x0118 0x02e8 0x6 0x2
-#define ULP1_PAD_PTE6__SDHC1_D4 0x0118 0x0000 0x8 0x0
-#define ULP1_PAD_PTE6__FB_A17 0x0118 0x0000 0x9 0x0
-#define ULP1_PAD_PTE7__PTE7 0x011c 0x0000 0x1 0x0
-#define ULP1_PAD_PTE7__TRACE_D7 0x011c 0x0000 0xa 0x0
-#define ULP1_PAD_PTE7__VIU_FID 0x011c 0x0000 0xc 0x0
-#define ULP1_PAD_PTE7__FXIO1_D24 0x011c 0x0000 0x2 0x0
-#define ULP1_PAD_PTE7__LPSPI2_PCS0 0x011c 0x029c 0x3 0x2
-#define ULP1_PAD_PTE7__LPUART5_RX 0x011c 0x0254 0x4 0x2
-#define ULP1_PAD_PTE7__TPM7_CH4 0x011c 0x02ec 0x6 0x2
-#define ULP1_PAD_PTE7__SDHC1_D5 0x011c 0x0000 0x8 0x0
-#define ULP1_PAD_PTE7__FB_A18 0x011c 0x0000 0x9 0x0
-#define ULP1_PAD_PTE8__PTE8 0x0120 0x0000 0x1 0x0
-#define ULP1_PAD_PTE8__TRACE_D6 0x0120 0x0000 0xa 0x0
-#define ULP1_PAD_PTE8__VIU_D16 0x0120 0x0000 0xc 0x0
-#define ULP1_PAD_PTE8__FXIO1_D23 0x0120 0x0000 0x2 0x0
-#define ULP1_PAD_PTE8__LPSPI3_PCS1 0x0120 0x0314 0x3 0x2
-#define ULP1_PAD_PTE8__LPUART6_CTS_B 0x0120 0x025c 0x4 0x2
-#define ULP1_PAD_PTE8__LPI2C6_SCL 0x0120 0x02fc 0x5 0x2
-#define ULP1_PAD_PTE8__TPM7_CH5 0x0120 0x02f0 0x6 0x2
-#define ULP1_PAD_PTE8__SDHC1_WP 0x0120 0x0200 0x7 0x1
-#define ULP1_PAD_PTE8__SDHC1_D6 0x0120 0x0000 0x8 0x0
-#define ULP1_PAD_PTE8__FB_CS3_B_FB_BE7_0_BLS31_24_B 0x0120 0x0000 0x9 0x0
-#define ULP1_PAD_PTE9__PTE9 0x0124 0x0000 0x1 0x0
-#define ULP1_PAD_PTE9__TRACE_D5 0x0124 0x0000 0xa 0x0
-#define ULP1_PAD_PTE9__VIU_D17 0x0124 0x0000 0xc 0x0
-#define ULP1_PAD_PTE9__FXIO1_D22 0x0124 0x0000 0x2 0x0
-#define ULP1_PAD_PTE9__LPSPI3_PCS2 0x0124 0x0318 0x3 0x2
-#define ULP1_PAD_PTE9__LPUART6_RTS_B 0x0124 0x0000 0x4 0x0
-#define ULP1_PAD_PTE9__LPI2C6_SDA 0x0124 0x0300 0x5 0x2
-#define ULP1_PAD_PTE9__TPM7_CLKIN 0x0124 0x02f4 0x6 0x2
-#define ULP1_PAD_PTE9__SDHC1_CD 0x0124 0x032c 0x7 0x1
-#define ULP1_PAD_PTE9__SDHC1_D7 0x0124 0x0000 0x8 0x0
-#define ULP1_PAD_PTE9__FB_TBST_B_FB_CS2_B_FB_BE15_8_BLS23_16_B 0x0124 0x0000 0x9 0x0
-#define ULP1_PAD_PTE10__PTE10 0x0128 0x0000 0x1 0x0
-#define ULP1_PAD_PTE10__TRACE_D4 0x0128 0x0000 0xa 0x0
-#define ULP1_PAD_PTE10__VIU_D18 0x0128 0x0000 0xc 0x0
-#define ULP1_PAD_PTE10__FXIO1_D21 0x0128 0x0000 0x2 0x0
-#define ULP1_PAD_PTE10__LPSPI3_PCS3 0x0128 0x031c 0x3 0x2
-#define ULP1_PAD_PTE10__LPUART6_TX 0x0128 0x0264 0x4 0x2
-#define ULP1_PAD_PTE10__LPI2C6_HREQ 0x0128 0x02f8 0x5 0x2
-#define ULP1_PAD_PTE10__TPM7_CH0 0x0128 0x02dc 0x6 0x2
-#define ULP1_PAD_PTE10__SDHC1_VS 0x0128 0x0000 0x7 0x0
-#define ULP1_PAD_PTE10__SDHC1_DQS 0x0128 0x0000 0x8 0x0
-#define ULP1_PAD_PTE10__FB_A19 0x0128 0x0000 0x9 0x0
-#define ULP1_PAD_PTE11__PTE11 0x012c 0x0000 0x1 0x0
-#define ULP1_PAD_PTE11__TRACE_D3 0x012c 0x0000 0xa 0x0
-#define ULP1_PAD_PTE11__VIU_D19 0x012c 0x0000 0xc 0x0
-#define ULP1_PAD_PTE11__FXIO1_D20 0x012c 0x0000 0x2 0x0
-#define ULP1_PAD_PTE11__LPUART6_RX 0x012c 0x0260 0x4 0x2
-#define ULP1_PAD_PTE11__TPM7_CH1 0x012c 0x02e0 0x6 0x2
-#define ULP1_PAD_PTE11__SDHC1_RESET_B 0x012c 0x0000 0x8 0x0
-#define ULP1_PAD_PTE11__FB_A20 0x012c 0x0000 0x9 0x0
-#define ULP1_PAD_PTE12__PTE12 0x0130 0x0000 0x1 0x0
-#define ULP1_PAD_PTE12__TRACE_D2 0x0130 0x0000 0xa 0x0
-#define ULP1_PAD_PTE12__VIU_D20 0x0130 0x0000 0xc 0x0
-#define ULP1_PAD_PTE12__FXIO1_D19 0x0130 0x0000 0x2 0x0
-#define ULP1_PAD_PTE12__LPSPI3_SIN 0x0130 0x0324 0x3 0x2
-#define ULP1_PAD_PTE12__LPUART7_CTS_B 0x0130 0x0268 0x4 0x2
-#define ULP1_PAD_PTE12__LPI2C7_SCL 0x0130 0x0308 0x5 0x2
-#define ULP1_PAD_PTE12__TPM7_CH2 0x0130 0x02e4 0x6 0x2
-#define ULP1_PAD_PTE12__SDHC1_WP 0x0130 0x0200 0x8 0x2
-#define ULP1_PAD_PTE12__FB_A21 0x0130 0x0000 0x9 0x0
-#define ULP1_PAD_PTE13__PTE13 0x0134 0x0000 0x1 0x0
-#define ULP1_PAD_PTE13__TRACE_D1 0x0134 0x0000 0xa 0x0
-#define ULP1_PAD_PTE13__VIU_D21 0x0134 0x0000 0xc 0x0
-#define ULP1_PAD_PTE13__FXIO1_D18 0x0134 0x0000 0x2 0x0
-#define ULP1_PAD_PTE13__LPSPI3_SOUT 0x0134 0x0328 0x3 0x2
-#define ULP1_PAD_PTE13__LPUART7_RTS_B 0x0134 0x0000 0x4 0x0
-#define ULP1_PAD_PTE13__LPI2C7_SDA 0x0134 0x030c 0x5 0x2
-#define ULP1_PAD_PTE13__TPM6_CLKIN 0x0134 0x02d8 0x6 0x2
-#define ULP1_PAD_PTE13__SDHC1_CD 0x0134 0x032c 0x8 0x2
-#define ULP1_PAD_PTE13__FB_A22 0x0134 0x0000 0x9 0x0
-#define ULP1_PAD_PTE14__PTE14 0x0138 0x0000 0x1 0x0
-#define ULP1_PAD_PTE14__TRACE_D0 0x0138 0x0000 0xa 0x0
-#define ULP1_PAD_PTE14__VIU_D22 0x0138 0x0000 0xc 0x0
-#define ULP1_PAD_PTE14__FXIO1_D17 0x0138 0x0000 0x2 0x0
-#define ULP1_PAD_PTE14__LPSPI3_SCK 0x0138 0x0320 0x3 0x2
-#define ULP1_PAD_PTE14__LPUART7_TX 0x0138 0x0270 0x4 0x2
-#define ULP1_PAD_PTE14__LPI2C7_HREQ 0x0138 0x0304 0x5 0x2
-#define ULP1_PAD_PTE14__TPM6_CH0 0x0138 0x02d0 0x6 0x2
-#define ULP1_PAD_PTE14__SDHC1_VS 0x0138 0x0000 0x8 0x0
-#define ULP1_PAD_PTE14__FB_A23 0x0138 0x0000 0x9 0x0
-#define ULP1_PAD_PTE15__PTE15 0x013c 0x0000 0x1 0x0
-#define ULP1_PAD_PTE15__TRACE_CLKOUT 0x013c 0x0000 0xa 0x0
-#define ULP1_PAD_PTE15__VIU_D23 0x013c 0x0000 0xc 0x0
-#define ULP1_PAD_PTE15__FXIO1_D16 0x013c 0x0000 0x2 0x0
-#define ULP1_PAD_PTE15__LPSPI3_PCS0 0x013c 0x0310 0x3 0x2
-#define ULP1_PAD_PTE15__LPUART7_RX 0x013c 0x026c 0x4 0x2
-#define ULP1_PAD_PTE15__TPM6_CH1 0x013c 0x02d4 0x6 0x2
-#define ULP1_PAD_PTE15__FB_A24 0x013c 0x0000 0x9 0x0
-#define ULP1_PAD_PTF0__PTF0 0x0180 0x0000 0x1 0x0
-#define ULP1_PAD_PTF0__VIU_DE 0x0180 0x0000 0xc 0x0
-#define ULP1_PAD_PTF0__LPUART4_CTS_B 0x0180 0x0244 0x4 0x3
-#define ULP1_PAD_PTF0__LPI2C4_SCL 0x0180 0x0278 0x5 0x3
-#define ULP1_PAD_PTF0__TPM4_CLKIN 0x0180 0x0298 0x6 0x3
-#define ULP1_PAD_PTF0__FB_RW_B 0x0180 0x0000 0x9 0x0
-#define ULP1_PAD_PTF1__PTF1 0x0184 0x0000 0x1 0x0
-#define ULP1_PAD_PTF1__VIU_HSYNC 0x0184 0x0000 0xc 0x0
-#define ULP1_PAD_PTF1__LPUART4_RTS_B 0x0184 0x0000 0x4 0x0
-#define ULP1_PAD_PTF1__LPI2C4_SDA 0x0184 0x027c 0x5 0x3
-#define ULP1_PAD_PTF1__TPM4_CH0 0x0184 0x0280 0x6 0x3
-#define ULP1_PAD_PTF1__CLKOUT 0x0184 0x0000 0x9 0x0
-#define ULP1_PAD_PTF2__PTF2 0x0188 0x0000 0x1 0x0
-#define ULP1_PAD_PTF2__VIU_VSYNC 0x0188 0x0000 0xc 0x0
-#define ULP1_PAD_PTF2__LPUART4_TX 0x0188 0x024c 0x4 0x3
-#define ULP1_PAD_PTF2__LPI2C4_HREQ 0x0188 0x0274 0x5 0x3
-#define ULP1_PAD_PTF2__TPM4_CH1 0x0188 0x0284 0x6 0x3
-#define ULP1_PAD_PTF2__FB_TSIZ1_FB_CS5_B_FB_BE23_16_BLS15_8_B 0x0188 0x0000 0x9 0x0
-#define ULP1_PAD_PTF3__PTF3 0x018c 0x0000 0x1 0x0
-#define ULP1_PAD_PTF3__VIU_PCLK 0x018c 0x0000 0xc 0x0
-#define ULP1_PAD_PTF3__LPUART4_RX 0x018c 0x0248 0x4 0x3
-#define ULP1_PAD_PTF3__TPM4_CH2 0x018c 0x0288 0x6 0x3
-#define ULP1_PAD_PTF3__FB_AD16 0x018c 0x0000 0x9 0x0
-#define ULP1_PAD_PTF4__PTF4 0x0190 0x0000 0x1 0x0
-#define ULP1_PAD_PTF4__VIU_D0 0x0190 0x0000 0xc 0x0
-#define ULP1_PAD_PTF4__FXIO1_D0 0x0190 0x0204 0x2 0x2
-#define ULP1_PAD_PTF4__LPSPI2_PCS1 0x0190 0x02a0 0x3 0x3
-#define ULP1_PAD_PTF4__LPUART5_CTS_B 0x0190 0x0250 0x4 0x3
-#define ULP1_PAD_PTF4__LPI2C5_SCL 0x0190 0x02bc 0x5 0x3
-#define ULP1_PAD_PTF4__TPM4_CH3 0x0190 0x028c 0x6 0x2
-#define ULP1_PAD_PTF4__FB_AD17 0x0190 0x0000 0x9 0x0
-#define ULP1_PAD_PTF5__PTF5 0x0194 0x0000 0x1 0x0
-#define ULP1_PAD_PTF5__VIU_D1 0x0194 0x0000 0xc 0x0
-#define ULP1_PAD_PTF5__FXIO1_D1 0x0194 0x0208 0x2 0x2
-#define ULP1_PAD_PTF5__LPSPI2_PCS2 0x0194 0x02a4 0x3 0x3
-#define ULP1_PAD_PTF5__LPUART5_RTS_B 0x0194 0x0000 0x4 0x0
-#define ULP1_PAD_PTF5__LPI2C5_SDA 0x0194 0x02c0 0x5 0x3
-#define ULP1_PAD_PTF5__TPM4_CH4 0x0194 0x0290 0x6 0x2
-#define ULP1_PAD_PTF5__FB_AD18 0x0194 0x0000 0x9 0x0
-#define ULP1_PAD_PTF6__PTF6 0x0198 0x0000 0x1 0x0
-#define ULP1_PAD_PTF6__VIU_D2 0x0198 0x0000 0xc 0x0
-#define ULP1_PAD_PTF6__FXIO1_D2 0x0198 0x020c 0x2 0x2
-#define ULP1_PAD_PTF6__LPSPI2_PCS3 0x0198 0x02a8 0x3 0x3
-#define ULP1_PAD_PTF6__LPUART5_TX 0x0198 0x0258 0x4 0x3
-#define ULP1_PAD_PTF6__LPI2C5_HREQ 0x0198 0x02b8 0x5 0x3
-#define ULP1_PAD_PTF6__TPM4_CH5 0x0198 0x0294 0x6 0x2
-#define ULP1_PAD_PTF6__FB_AD19 0x0198 0x0000 0x9 0x0
-#define ULP1_PAD_PTF7__PTF7 0x019c 0x0000 0x1 0x0
-#define ULP1_PAD_PTF7__VIU_D3 0x019c 0x0000 0xc 0x0
-#define ULP1_PAD_PTF7__FXIO1_D3 0x019c 0x0210 0x2 0x2
-#define ULP1_PAD_PTF7__LPUART5_RX 0x019c 0x0254 0x4 0x3
-#define ULP1_PAD_PTF7__TPM5_CH1 0x019c 0x02c8 0x6 0x3
-#define ULP1_PAD_PTF7__FB_AD20 0x019c 0x0000 0x9 0x0
-#define ULP1_PAD_PTF8__PTF8 0x01a0 0x0000 0x1 0x0
-#define ULP1_PAD_PTF8__USB1_ULPI_CLK 0x01a0 0x0000 0xb 0x0
-#define ULP1_PAD_PTF8__VIU_D4 0x01a0 0x0000 0xc 0x0
-#define ULP1_PAD_PTF8__FXIO1_D4 0x01a0 0x0214 0x2 0x2
-#define ULP1_PAD_PTF8__LPSPI2_SIN 0x01a0 0x02b0 0x3 0x3
-#define ULP1_PAD_PTF8__LPUART6_CTS_B 0x01a0 0x025c 0x4 0x3
-#define ULP1_PAD_PTF8__LPI2C6_SCL 0x01a0 0x02fc 0x5 0x3
-#define ULP1_PAD_PTF8__TPM5_CLKIN 0x01a0 0x02cc 0x6 0x3
-#define ULP1_PAD_PTF8__FB_AD21 0x01a0 0x0000 0x9 0x0
-#define ULP1_PAD_PTF9__PTF9 0x01a4 0x0000 0x1 0x0
-#define ULP1_PAD_PTF9__USB1_ULPI_NXT 0x01a4 0x0000 0xb 0x0
-#define ULP1_PAD_PTF9__VIU_D5 0x01a4 0x0000 0xc 0x0
-#define ULP1_PAD_PTF9__FXIO1_D5 0x01a4 0x0218 0x2 0x2
-#define ULP1_PAD_PTF9__LPSPI2_SOUT 0x01a4 0x02b4 0x3 0x3
-#define ULP1_PAD_PTF9__LPUART6_RTS_B 0x01a4 0x0000 0x4 0x0
-#define ULP1_PAD_PTF9__LPI2C6_SDA 0x01a4 0x0300 0x5 0x3
-#define ULP1_PAD_PTF9__TPM5_CH0 0x01a4 0x02c4 0x6 0x3
-#define ULP1_PAD_PTF9__FB_AD22 0x01a4 0x0000 0x9 0x0
-#define ULP1_PAD_PTF10__PTF10 0x01a8 0x0000 0x1 0x0
-#define ULP1_PAD_PTF10__USB1_ULPI_STP 0x01a8 0x0000 0xb 0x0
-#define ULP1_PAD_PTF10__VIU_D6 0x01a8 0x0000 0xc 0x0
-#define ULP1_PAD_PTF10__FXIO1_D6 0x01a8 0x021c 0x2 0x2
-#define ULP1_PAD_PTF10__LPSPI2_SCK 0x01a8 0x02ac 0x3 0x3
-#define ULP1_PAD_PTF10__LPUART6_TX 0x01a8 0x0264 0x4 0x3
-#define ULP1_PAD_PTF10__LPI2C6_HREQ 0x01a8 0x02f8 0x5 0x3
-#define ULP1_PAD_PTF10__TPM7_CH3 0x01a8 0x02e8 0x6 0x3
-#define ULP1_PAD_PTF10__FB_AD23 0x01a8 0x0000 0x9 0x0
-#define ULP1_PAD_PTF11__PTF11 0x01ac 0x0000 0x1 0x0
-#define ULP1_PAD_PTF11__USB1_ULPI_DIR 0x01ac 0x0000 0xb 0x0
-#define ULP1_PAD_PTF11__VIU_D7 0x01ac 0x0000 0xc 0x0
-#define ULP1_PAD_PTF11__FXIO1_D7 0x01ac 0x0220 0x2 0x2
-#define ULP1_PAD_PTF11__LPSPI2_PCS0 0x01ac 0x029c 0x3 0x3
-#define ULP1_PAD_PTF11__LPUART6_RX 0x01ac 0x0260 0x4 0x3
-#define ULP1_PAD_PTF11__TPM7_CH4 0x01ac 0x02ec 0x6 0x3
-#define ULP1_PAD_PTF11__FB_CS4_B_FB_TSIZ0_FB_BE31_24_BLS7_0_B 0x01ac 0x0000 0x9 0x0
-#define ULP1_PAD_PTF12__PTF12 0x01b0 0x0000 0x1 0x0
-#define ULP1_PAD_PTF12__USB1_ULPI_DATA0 0x01b0 0x0000 0xb 0x0
-#define ULP1_PAD_PTF12__VIU_D8 0x01b0 0x0000 0xc 0x0
-#define ULP1_PAD_PTF12__FXIO1_D8 0x01b0 0x0224 0x2 0x2
-#define ULP1_PAD_PTF12__LPSPI3_PCS1 0x01b0 0x0314 0x3 0x3
-#define ULP1_PAD_PTF12__LPUART7_CTS_B 0x01b0 0x0268 0x4 0x3
-#define ULP1_PAD_PTF12__LPI2C7_SCL 0x01b0 0x0308 0x5 0x3
-#define ULP1_PAD_PTF12__TPM7_CH5 0x01b0 0x02f0 0x6 0x3
-#define ULP1_PAD_PTF12__FB_AD24 0x01b0 0x0000 0x9 0x0
-#define ULP1_PAD_PTF13__PTF13 0x01b4 0x0000 0x1 0x0
-#define ULP1_PAD_PTF13__USB1_ULPI_DATA1 0x01b4 0x0000 0xb 0x0
-#define ULP1_PAD_PTF13__VIU_D9 0x01b4 0x0000 0xc 0x0
-#define ULP1_PAD_PTF13__FXIO1_D9 0x01b4 0x0228 0x2 0x2
-#define ULP1_PAD_PTF13__LPSPI3_PCS2 0x01b4 0x0318 0x3 0x3
-#define ULP1_PAD_PTF13__LPUART7_RTS_B 0x01b4 0x0000 0x4 0x0
-#define ULP1_PAD_PTF13__LPI2C7_SDA 0x01b4 0x030c 0x5 0x3
-#define ULP1_PAD_PTF13__TPM7_CLKIN 0x01b4 0x02f4 0x6 0x3
-#define ULP1_PAD_PTF13__FB_AD25 0x01b4 0x0000 0x9 0x0
-#define ULP1_PAD_PTF14__PTF14 0x01b8 0x0000 0x1 0x0
-#define ULP1_PAD_PTF14__USB1_ULPI_DATA2 0x01b8 0x0000 0xb 0x0
-#define ULP1_PAD_PTF14__VIU_D10 0x01b8 0x0000 0xc 0x0
-#define ULP1_PAD_PTF14__FXIO1_D10 0x01b8 0x022c 0x2 0x2
-#define ULP1_PAD_PTF14__LPSPI3_PCS3 0x01b8 0x031c 0x3 0x3
-#define ULP1_PAD_PTF14__LPUART7_TX 0x01b8 0x0270 0x4 0x3
-#define ULP1_PAD_PTF14__LPI2C7_HREQ 0x01b8 0x0304 0x5 0x3
-#define ULP1_PAD_PTF14__TPM7_CH0 0x01b8 0x02dc 0x6 0x3
-#define ULP1_PAD_PTF14__FB_AD26 0x01b8 0x0000 0x9 0x0
-#define ULP1_PAD_PTF15__PTF15 0x01bc 0x0000 0x1 0x0
-#define ULP1_PAD_PTF15__USB1_ULPI_DATA3 0x01bc 0x0000 0xb 0x0
-#define ULP1_PAD_PTF15__VIU_D11 0x01bc 0x0000 0xc 0x0
-#define ULP1_PAD_PTF15__FXIO1_D11 0x01bc 0x0230 0x2 0x2
-#define ULP1_PAD_PTF15__LPUART7_RX 0x01bc 0x026c 0x4 0x3
-#define ULP1_PAD_PTF15__TPM7_CH1 0x01bc 0x02e0 0x6 0x3
-#define ULP1_PAD_PTF15__FB_AD27 0x01bc 0x0000 0x9 0x0
-#define ULP1_PAD_PTF16__PTF16 0x01c0 0x0000 0x1 0x0
-#define ULP1_PAD_PTF16__USB1_ULPI_DATA4 0x01c0 0x0000 0xb 0x0
-#define ULP1_PAD_PTF16__VIU_D12 0x01c0 0x0000 0xc 0x0
-#define ULP1_PAD_PTF16__FXIO1_D12 0x01c0 0x0234 0x2 0x2
-#define ULP1_PAD_PTF16__LPSPI3_SIN 0x01c0 0x0324 0x3 0x3
-#define ULP1_PAD_PTF16__TPM7_CH2 0x01c0 0x02e4 0x6 0x3
-#define ULP1_PAD_PTF16__FB_AD28 0x01c0 0x0000 0x9 0x0
-#define ULP1_PAD_PTF17__PTF17 0x01c4 0x0000 0x1 0x0
-#define ULP1_PAD_PTF17__USB1_ULPI_DATA5 0x01c4 0x0000 0xb 0x0
-#define ULP1_PAD_PTF17__VIU_D13 0x01c4 0x0000 0xc 0x0
-#define ULP1_PAD_PTF17__FXIO1_D13 0x01c4 0x0238 0x2 0x2
-#define ULP1_PAD_PTF17__LPSPI3_SOUT 0x01c4 0x0328 0x3 0x3
-#define ULP1_PAD_PTF17__TPM6_CLKIN 0x01c4 0x02d8 0x6 0x3
-#define ULP1_PAD_PTF17__FB_AD29 0x01c4 0x0000 0x9 0x0
-#define ULP1_PAD_PTF18__PTF18 0x01c8 0x0000 0x1 0x0
-#define ULP1_PAD_PTF18__USB1_ULPI_DATA6 0x01c8 0x0000 0xb 0x0
-#define ULP1_PAD_PTF18__VIU_D14 0x01c8 0x0000 0xc 0x0
-#define ULP1_PAD_PTF18__FXIO1_D14 0x01c8 0x023c 0x2 0x2
-#define ULP1_PAD_PTF18__LPSPI3_SCK 0x01c8 0x0320 0x3 0x3
-#define ULP1_PAD_PTF18__TPM6_CH0 0x01c8 0x02d0 0x6 0x3
-#define ULP1_PAD_PTF18__FB_AD30 0x01c8 0x0000 0x9 0x0
-#define ULP1_PAD_PTF19__PTF19 0x01cc 0x0000 0x1 0x0
-#define ULP1_PAD_PTF19__USB1_ULPI_DATA7 0x01cc 0x0000 0xb 0x0
-#define ULP1_PAD_PTF19__VIU_D15 0x01cc 0x0000 0xc 0x0
-#define ULP1_PAD_PTF19__FXIO1_D15 0x01cc 0x0240 0x2 0x2
-#define ULP1_PAD_PTF19__LPSPI3_PCS0 0x01cc 0x0310 0x3 0x3
-#define ULP1_PAD_PTF19__TPM6_CH1 0x01cc 0x02d4 0x6 0x3
-#define ULP1_PAD_PTF19__FB_AD31 0x01cc 0x0000 0x9 0x0
-
-#endif /* __DTS_ULP1_PINFUNC_H */
+#endif /* __DTS_IMX7ULP_PINFUNC_H */
diff --git a/arch/arm/dts/imx7ulp.dtsi b/arch/arm/dts/imx7ulp.dtsi
index a8458f89d5..7bcd2cc346 100644
--- a/arch/arm/dts/imx7ulp.dtsi
+++ b/arch/arm/dts/imx7ulp.dtsi
@@ -16,10 +16,12 @@
interrupt-parent = <&intc>;
aliases {
- gpio0 = &gpio0;
- gpio1 = &gpio1;
- gpio2 = &gpio2;
- gpio3 = &gpio3;
+ gpio0 = &gpio4;
+ gpio1 = &gpio5;
+ gpio2 = &gpio0;
+ gpio3 = &gpio1;
+ gpio4 = &gpio2;
+ gpio5 = &gpio3;
mmc0 = &usdhc0;
mmc1 = &usdhc1;
serial0 = &lpuart4;
@@ -27,10 +29,12 @@
serial2 = &lpuart6;
serial3 = &lpuart7;
usbphy0 = &usbphy1;
+ usb0 = &usbotg1;
i2c4 = &lpi2c4;
i2c5 = &lpi2c5;
i2c6 = &lpi2c6;
i2c7 = &lpi2c7;
+ spi0 = &qspi1;
};
cpus {
@@ -503,6 +507,22 @@
fsl,mux_mask = <0xf00>;
};
+ gpio4: gpio@4103f000 {
+ compatible = "fsl,imx7ulp-gpio";
+ reg = <0x4103f000 0x1000 0x4100F000 0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&iomuxc 0 0 32>;
+ };
+
+ gpio5: gpio@41040000 {
+ compatible = "fsl,imx7ulp-gpio";
+ reg = <0x41040000 0x1000 0x4100F040 0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&iomuxc 0 32 32>;
+ };
+
gpio0: gpio@40ae0000 {
compatible = "fsl,imx7ulp-gpio";
reg = <0x40ae0000 0x1000 0x400F0000 0x40>;
diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi
index 8589f76d23..bea80c5d00 100644
--- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi
+++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi
@@ -336,13 +336,12 @@
reg = <0>;
/* TODO: phy reset: TCA9555RTWR(i2c:0x21)[p04].GPIO_MCU_RGMII_RSTN */
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
- ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
};
};
&cpsw_port1 {
- phy-mode = "rgmii-id";
+ phy-mode = "rgmii-rxid";
phy-handle = <&phy0>;
};
diff --git a/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi b/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi
index 541da22c48..9291e57e25 100644
--- a/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi
+++ b/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi
@@ -3,11 +3,18 @@
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*/
+#include <dt-bindings/dma/k3-udma.h>
+#include <dt-bindings/net/ti-dp83867.h>
+
/ {
chosen {
stdout-path = "serial2:115200n8";
tick-timer = &timer1;
};
+
+ aliases {
+ ethernet0 = &cpsw_port1;
+ };
};
&cbass_main{
@@ -24,6 +31,184 @@
clock-frequency = <25000000>;
u-boot,dm-spl;
};
+
+ mcu_conf: scm_conf@40f00000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x0 0x40f00000 0x0 0x20000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x40f00000 0x20000>;
+
+ phy_sel: cpsw-phy-sel@4040 {
+ compatible = "ti,am654-cpsw-phy-sel";
+ reg = <0x4040 0x4>;
+ reg-names = "gmii-sel";
+ };
+ };
+
+ cbass_mcu_navss: mcu_navss {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ dma-coherent;
+ dma-ranges;
+ ranges;
+
+ ti,sci-dev-id = <232>;
+ u-boot,dm-spl;
+
+ mcu_ringacc: ringacc@2b800000 {
+ compatible = "ti,am654-navss-ringacc";
+ reg = <0x0 0x2b800000 0x0 0x400000>,
+ <0x0 0x2b000000 0x0 0x400000>,
+ <0x0 0x28590000 0x0 0x100>,
+ <0x0 0x2a500000 0x0 0x40000>;
+ reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target";
+ ti,num-rings = <286>;
+ ti,sci-rm-range-gp-rings = <0x1>; /* GP ring range */
+ ti,sci = <&dmsc>;
+ ti,sci-dev-id = <235>;
+ u-boot,dm-spl;
+ };
+
+ mcu_udmap: udmap@31150000 {
+ compatible = "ti,j721e-navss-mcu-udmap";
+ reg = <0x0 0x285c0000 0x0 0x100>,
+ <0x0 0x2a800000 0x0 0x40000>,
+ <0x0 0x2aa00000 0x0 0x40000>;
+ reg-names = "gcfg", "rchanrt", "tchanrt";
+ #dma-cells = <3>;
+
+ ti,ringacc = <&mcu_ringacc>;
+ ti,psil-base = <0x6000>;
+
+ ti,sci = <&dmsc>;
+ ti,sci-dev-id = <236>;
+
+ ti,sci-rm-range-tchan = <0x0d>, /* TX_CHAN */
+ <0x0f>; /* TX_HCHAN */
+ ti,sci-rm-range-rchan = <0x0a>, /* RX_CHAN */
+ <0x0b>; /* RX_HCHAN */
+ ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */
+ u-boot,dm-spl;
+ };
+ };
+
+ mcu_cpsw: ethernet@046000000 {
+ compatible = "ti,j721e-cpsw-nuss";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ reg = <0x0 0x46000000 0x0 0x200000>;
+ reg-names = "cpsw_nuss";
+ ranges;
+ dma-coherent;
+ clocks = <&k3_clks 18 22>;
+ clock-names = "fck";
+ power-domains = <&k3_pds 18 TI_SCI_PD_EXCLUSIVE>;
+ ti,psil-base = <0x7000>;
+ cpsw-phy-sel = <&phy_sel>;
+
+ dmas = <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_TX>,
+ <&mcu_udmap &mcu_cpsw 1 UDMA_DIR_TX>,
+ <&mcu_udmap &mcu_cpsw 2 UDMA_DIR_TX>,
+ <&mcu_udmap &mcu_cpsw 3 UDMA_DIR_TX>,
+ <&mcu_udmap &mcu_cpsw 4 UDMA_DIR_TX>,
+ <&mcu_udmap &mcu_cpsw 5 UDMA_DIR_TX>,
+ <&mcu_udmap &mcu_cpsw 6 UDMA_DIR_TX>,
+ <&mcu_udmap &mcu_cpsw 7 UDMA_DIR_TX>,
+ <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_RX>;
+ dma-names = "tx0", "tx1", "tx2", "tx3",
+ "tx4", "tx5", "tx6", "tx7",
+ "rx";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ host: host@0 {
+ reg = <0>;
+ ti,label = "host";
+ };
+
+ cpsw_port1: port@1 {
+ reg = <1>;
+ ti,mac-only;
+ ti,label = "port1";
+ ti,syscon-efuse = <&mcu_conf 0x200>;
+ };
+ };
+
+ davinci_mdio: mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus_freq = <1000000>;
+ };
+
+ cpts {
+ clocks = <&k3_clks 18 2>;
+ clock-names = "cpts";
+ interrupts-extended = <&gic500 GIC_SPI 858 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "cpts";
+ ti,cpts-ext-ts-inputs = <4>;
+ ti,cpts-periodic-outputs = <2>;
+ };
+
+ ti,psil-config0 {
+ linux,udma-mode = <UDMA_PKT_MODE>;
+ statictr-type = <PSIL_STATIC_TR_NONE>;
+ ti,needs-epib;
+ ti,psd-size = <16>;
+ };
+
+ ti,psil-config1 {
+ linux,udma-mode = <UDMA_PKT_MODE>;
+ statictr-type = <PSIL_STATIC_TR_NONE>;
+ ti,needs-epib;
+ ti,psd-size = <16>;
+ };
+
+ ti,psil-config2 {
+ linux,udma-mode = <UDMA_PKT_MODE>;
+ statictr-type = <PSIL_STATIC_TR_NONE>;
+ ti,needs-epib;
+ ti,psd-size = <16>;
+ };
+
+ ti,psil-config3 {
+ linux,udma-mode = <UDMA_PKT_MODE>;
+ statictr-type = <PSIL_STATIC_TR_NONE>;
+ ti,needs-epib;
+ ti,psd-size = <16>;
+ };
+
+ ti,psil-config4 {
+ linux,udma-mode = <UDMA_PKT_MODE>;
+ statictr-type = <PSIL_STATIC_TR_NONE>;
+ ti,needs-epib;
+ ti,psd-size = <16>;
+ };
+
+ ti,psil-config5 {
+ linux,udma-mode = <UDMA_PKT_MODE>;
+ statictr-type = <PSIL_STATIC_TR_NONE>;
+ ti,needs-epib;
+ ti,psd-size = <16>;
+ };
+
+ ti,psil-config6 {
+ linux,udma-mode = <UDMA_PKT_MODE>;
+ statictr-type = <PSIL_STATIC_TR_NONE>;
+ ti,needs-epib;
+ ti,psd-size = <16>;
+ };
+
+ ti,psil-config7 {
+ linux,udma-mode = <UDMA_PKT_MODE>;
+ statictr-type = <PSIL_STATIC_TR_NONE>;
+ ti,needs-epib;
+ ti,psd-size = <16>;
+ };
+ };
};
&secure_proxy_main {
@@ -52,6 +237,29 @@
&wkup_pmx0 {
u-boot,dm-spl;
+ mcu_cpsw_pins_default: mcu_cpsw_pins_default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0x0058, PIN_OUTPUT, 0) /* (N4) MCU_RGMII1_TX_CTL */
+ J721E_WKUP_IOPAD(0x005c, PIN_INPUT, 0) /* (N5) MCU_RGMII1_RX_CTL */
+ J721E_WKUP_IOPAD(0x0060, PIN_OUTPUT, 0) /* (M2) MCU_RGMII1_TD3 */
+ J721E_WKUP_IOPAD(0x0064, PIN_OUTPUT, 0) /* (M3) MCU_RGMII1_TD2 */
+ J721E_WKUP_IOPAD(0x0068, PIN_OUTPUT, 0) /* (M4) MCU_RGMII1_TD1 */
+ J721E_WKUP_IOPAD(0x006c, PIN_OUTPUT, 0) /* (M5) MCU_RGMII1_TD0 */
+ J721E_WKUP_IOPAD(0x0078, PIN_INPUT, 0) /* (L2) MCU_RGMII1_RD3 */
+ J721E_WKUP_IOPAD(0x007c, PIN_INPUT, 0) /* (L5) MCU_RGMII1_RD2 */
+ J721E_WKUP_IOPAD(0x0080, PIN_INPUT, 0) /* (M6) MCU_RGMII1_RD1 */
+ J721E_WKUP_IOPAD(0x0084, PIN_INPUT, 0) /* (L6) MCU_RGMII1_RD0 */
+ J721E_WKUP_IOPAD(0x0070, PIN_INPUT, 0) /* (N1) MCU_RGMII1_TXC */
+ J721E_WKUP_IOPAD(0x0074, PIN_INPUT, 0) /* (M1) MCU_RGMII1_RXC */
+ >;
+ };
+
+ mcu_mdio_pins_default: mcu_mdio1_pins_default {
+ pinctrl-single,pins = <
+ J721E_WKUP_IOPAD(0x008c, PIN_OUTPUT, 0) /* (L1) MCU_MDIO0_MDC */
+ J721E_WKUP_IOPAD(0x0088, PIN_INPUT, 0) /* (L4) MCU_MDIO0_MDIO */
+ >;
+ };
};
&main_pmx0 {
@@ -73,3 +281,33 @@
&main_sdhci1 {
u-boot,dm-spl;
};
+
+&mcu_cpsw {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcu_cpsw_pins_default &mcu_mdio_pins_default>;
+};
+
+&davinci_mdio {
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+ ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+ };
+};
+
+&cpsw_port1 {
+ phy-mode = "rgmii-rxid";
+ phy-handle = <&phy0>;
+};
+
+&mcu_cpsw {
+ reg = <0x0 0x46000000 0x0 0x200000>,
+ <0x0 0x40f00200 0x0 0x2>;
+ reg-names = "cpsw_nuss", "mac_efuse";
+
+ cpsw-phy-sel@40f04040 {
+ compatible = "ti,am654-cpsw-phy-sel";
+ reg= <0x0 0x40f04040 0x0 0x4>;
+ reg-names = "gmii-sel";
+ };
+};
diff --git a/arch/arm/dts/rk3308-roc-cc.dts b/arch/arm/dts/rk3308-roc-cc.dts
index e10aa638a3..b4a54a852c 100644
--- a/arch/arm/dts/rk3308-roc-cc.dts
+++ b/arch/arm/dts/rk3308-roc-cc.dts
@@ -143,6 +143,15 @@
};
};
+&mac {
+ assigned-clocks = <&cru SCLK_MAC>;
+ assigned-clock-parents = <&mac_clkin>;
+ clock_in_out = "input";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rmiim1_pins &macm1_refclk>;
+ status = "okay";
+};
+
&pwm5 {
status = "okay";
pinctrl-names = "active";
diff --git a/arch/arm/dts/rk3308-u-boot.dtsi b/arch/arm/dts/rk3308-u-boot.dtsi
index 1a68decef3..f5a595337e 100644
--- a/arch/arm/dts/rk3308-u-boot.dtsi
+++ b/arch/arm/dts/rk3308-u-boot.dtsi
@@ -12,6 +12,8 @@
};
&emmc {
+ /* mmc to sram can't do dma, prevent aborts transferring TF-A parts */
+ u-boot,spl-fifo-mode;
u-boot,dm-pre-reloc;
};
diff --git a/arch/arm/dts/rk3308.dtsi b/arch/arm/dts/rk3308.dtsi
index 0eeec165d4..a5c0b72ae0 100644
--- a/arch/arm/dts/rk3308.dtsi
+++ b/arch/arm/dts/rk3308.dtsi
@@ -627,6 +627,28 @@
status = "disabled";
};
+ mac: ethernet@ff4e0000 {
+ compatible = "rockchip,rk3308-mac";
+ reg = <0x0 0xff4e0000 0x0 0x10000>;
+ rockchip,grf = <&grf>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ clocks = <&cru SCLK_MAC>, <&cru SCLK_MAC_RX_TX>,
+ <&cru SCLK_MAC_RX_TX>, <&cru SCLK_MAC_REF>,
+ <&cru SCLK_MAC>, <&cru ACLK_MAC>,
+ <&cru PCLK_MAC>, <&cru SCLK_MAC_RMII>;
+ clock-names = "stmmaceth", "mac_clk_rx",
+ "mac_clk_tx", "clk_mac_ref",
+ "clk_mac_refout", "aclk_mac",
+ "pclk_mac", "clk_mac_speed";
+ phy-mode = "rmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rmii_pins &mac_refclk_12ma>;
+ resets = <&cru SRST_MAC_A>;
+ reset-names = "stmmaceth";
+ status = "disabled";
+ };
+
cru: clock-controller@ff500000 {
compatible = "rockchip,rk3308-cru";
reg = <0x0 0xff500000 0x0 0x1000>;
diff --git a/arch/arm/dts/rk3368-px5-evb-u-boot.dtsi b/arch/arm/dts/rk3368-px5-evb-u-boot.dtsi
index 002767a033..936ce55727 100644
--- a/arch/arm/dts/rk3368-px5-evb-u-boot.dtsi
+++ b/arch/arm/dts/rk3368-px5-evb-u-boot.dtsi
@@ -58,6 +58,8 @@
};
&emmc {
+ /* mmc to sram can't do dma, prevent aborts transferring TF-A parts */
+ u-boot,spl-fifo-mode;
u-boot,dm-pre-reloc;
};
diff --git a/arch/arm/include/asm/arch-mx6/sys_proto.h b/arch/arm/include/asm/arch-mx6/sys_proto.h
index 4bf7dff8b4..1e5fa1a75e 100644
--- a/arch/arm/include/asm/arch-mx6/sys_proto.h
+++ b/arch/arm/include/asm/arch-mx6/sys_proto.h
@@ -20,6 +20,14 @@
int imx6_pcie_toggle_power(void);
int imx6_pcie_toggle_reset(void);
+enum ldo_reg {
+ LDO_ARM,
+ LDO_SOC,
+ LDO_PU,
+};
+
+int set_ldo_voltage(enum ldo_reg ldo, u32 mv);
+
/**
* iomuxc_set_rgmii_io_voltage - set voltage level of RGMII/USB pins
*
diff --git a/arch/arm/include/asm/arch-mx7ulp/scg.h b/arch/arm/include/asm/arch-mx7ulp/scg.h
index 531d8f3a95..b79bde338f 100644
--- a/arch/arm/include/asm/arch-mx7ulp/scg.h
+++ b/arch/arm/include/asm/arch-mx7ulp/scg.h
@@ -331,7 +331,6 @@ u32 decode_pll(enum pll_clocks pll);
void scg_a7_rccr_init(void);
void scg_a7_spll_init(void);
void scg_a7_ddrclk_init(void);
-void scg_a7_apll_init(void);
void scg_a7_firc_init(void);
void scg_a7_nicclk_init(void);
void scg_a7_sys_clk_sel(enum scg_sys_src clk);
diff --git a/arch/arm/include/asm/arch-rockchip/cru_px30.h b/arch/arm/include/asm/arch-rockchip/cru_px30.h
index 7d9fd181ac..798444ae49 100644
--- a/arch/arm/include/asm/arch-rockchip/cru_px30.h
+++ b/arch/arm/include/asm/arch-rockchip/cru_px30.h
@@ -357,6 +357,25 @@ enum {
UART2_DIVNP5_SHIFT = 0,
UART2_DIVNP5_MASK = 0x1f << UART2_DIVNP5_SHIFT,
+ /* CRU_CLK_SEL40_CON */
+ UART3_PLL_SEL_SHIFT = 14,
+ UART3_PLL_SEL_MASK = 3 << UART3_PLL_SEL_SHIFT,
+ UART3_PLL_SEL_GPLL = 0,
+ UART3_PLL_SEL_24M,
+ UART3_PLL_SEL_480M,
+ UART3_PLL_SEL_NPLL,
+ UART3_DIV_CON_SHIFT = 0,
+ UART3_DIV_CON_MASK = 0x1f << UART3_DIV_CON_SHIFT,
+
+ /* CRU_CLK_SEL41_CON */
+ UART3_CLK_SEL_SHIFT = 14,
+ UART3_CLK_SEL_MASK = 3 << UART3_PLL_SEL_SHIFT,
+ UART3_CLK_SEL_UART3 = 0,
+ UART3_CLK_SEL_UART3_NP5,
+ UART3_CLK_SEL_UART3_FRAC,
+ UART3_DIVNP5_SHIFT = 0,
+ UART3_DIVNP5_MASK = 0x1f << UART3_DIVNP5_SHIFT,
+
/* CRU_CLK_SEL46_CON */
UART5_PLL_SEL_SHIFT = 14,
UART5_PLL_SEL_MASK = 3 << UART5_PLL_SEL_SHIFT,
diff --git a/arch/arm/include/asm/arch-rockchip/grf_px30.h b/arch/arm/include/asm/arch-rockchip/grf_px30.h
index c167bb42fa..3d2a877032 100644
--- a/arch/arm/include/asm/arch-rockchip/grf_px30.h
+++ b/arch/arm/include/asm/arch-rockchip/grf_px30.h
@@ -112,18 +112,18 @@ struct px30_grf {
check_member(px30_grf, mac_con1, 0x904);
struct px30_pmugrf {
- unsigned int gpio0a_e;
- unsigned int gpio0b_e;
- unsigned int gpio0c_e;
- unsigned int gpio0d_e;
- unsigned int gpio0a_p;
- unsigned int gpio0b_p;
- unsigned int gpio0c_p;
- unsigned int gpio0d_p;
unsigned int gpio0al_iomux;
unsigned int gpio0bl_iomux;
unsigned int gpio0cl_iomux;
unsigned int gpio0dl_iomux;
+ unsigned int gpio0a_p;
+ unsigned int gpio0b_p;
+ unsigned int gpio0c_p;
+ unsigned int gpio0d_p;
+ unsigned int gpio0a_e;
+ unsigned int gpio0b_e;
+ unsigned int gpio0c_e;
+ unsigned int gpio0d_e;
unsigned int gpio0l_sr;
unsigned int gpio0h_sr;
unsigned int gpio0l_smt;
diff --git a/arch/arm/include/asm/arch-rockchip/pwm.h b/arch/arm/include/asm/arch-rockchip/pwm.h
index b5178db394..e8594055cd 100644
--- a/arch/arm/include/asm/arch-rockchip/pwm.h
+++ b/arch/arm/include/asm/arch-rockchip/pwm.h
@@ -7,13 +7,15 @@
#ifndef _ASM_ARCH_PWM_H
#define _ASM_ARCH_PWM_H
-struct rk3288_pwm {
- u32 cnt;
- u32 period_hpr;
- u32 duty_lpr;
- u32 ctrl;
+struct rockchip_pwm_regs {
+ unsigned long duty;
+ unsigned long period;
+ unsigned long cntr;
+ unsigned long ctrl;
};
-check_member(rk3288_pwm, ctrl, 0xc);
+
+#define PWM_CTRL_TIMER_EN (1 << 0)
+#define PWM_CTRL_OUTPUT_EN (1 << 3)
#define RK_PWM_DISABLE (0 << 0)
#define RK_PWM_ENABLE (1 << 0)
@@ -33,6 +35,9 @@ check_member(rk3288_pwm, ctrl, 0xc);
#define PWM_OUTPUT_LEFT (0 << 5)
#define PWM_OUTPUT_CENTER (1 << 5)
+#define PWM_LOCK (1 << 6)
+#define PWM_UNLOCK (0 << 6)
+
#define PWM_LP_ENABLE (1 << 8)
#define PWM_LP_DISABLE (0 << 8)
diff --git a/arch/arm/include/asm/mach-imx/sys_proto.h b/arch/arm/include/asm/mach-imx/sys_proto.h
index 52c83ba9e4..c9b509e6a7 100644
--- a/arch/arm/include/asm/mach-imx/sys_proto.h
+++ b/arch/arm/include/asm/mach-imx/sys_proto.h
@@ -153,6 +153,8 @@ void init_src(void);
void init_snvs(void);
void imx_wdog_disable_powerdown(void);
+int arch_auxiliary_core_check_up(u32 core_id);
+
int board_mmc_get_env_dev(int devno);
int nxp_board_rev(void);
diff --git a/arch/arm/mach-imx/imx8m/soc.c b/arch/arm/mach-imx/imx8m/soc.c
index 181c715be3..5ce5a180e8 100644
--- a/arch/arm/mach-imx/imx8m/soc.c
+++ b/arch/arm/mach-imx/imx8m/soc.c
@@ -217,6 +217,7 @@ u32 get_cpu_rev(void)
readl((void __iomem *)ROM_VERSION_A0);
if (rom_version != CHIP_REV_1_0) {
rom_version = readl((void __iomem *)ROM_VERSION_B0);
+ rom_version &= 0xff;
if (rom_version == CHIP_REV_2_0)
reg = CHIP_REV_2_0;
}
diff --git a/arch/arm/mach-imx/mx6/Kconfig b/arch/arm/mach-imx/mx6/Kconfig
index 607210520f..ef816a24ff 100644
--- a/arch/arm/mach-imx/mx6/Kconfig
+++ b/arch/arm/mach-imx/mx6/Kconfig
@@ -558,6 +558,7 @@ config TARGET_SOFTING_VINING_2000
select DM
select DM_THERMAL
select MX6SX
+ select SUPPORT_SPL
imply CMD_DM
config TARGET_WANDBOARD
diff --git a/arch/arm/mach-imx/mx6/soc.c b/arch/arm/mach-imx/mx6/soc.c
index 926718b49c..b8aaf3ef01 100644
--- a/arch/arm/mach-imx/mx6/soc.c
+++ b/arch/arm/mach-imx/mx6/soc.c
@@ -24,12 +24,6 @@
#include <imx_thermal.h>
#include <mmc.h>
-enum ldo_reg {
- LDO_ARM,
- LDO_SOC,
- LDO_PU,
-};
-
struct scu_regs {
u32 ctrl;
u32 config;
@@ -255,7 +249,7 @@ static void clear_ldo_ramp(void)
* Possible values are from 0.725V to 1.450V in steps of
* 0.025V (25mV).
*/
-static int set_ldo_voltage(enum ldo_reg ldo, u32 mv)
+int set_ldo_voltage(enum ldo_reg ldo, u32 mv)
{
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
u32 val, step, old, reg = readl(&anatop->reg_core);
@@ -375,6 +369,37 @@ static void init_bandgap(void)
}
}
+#if defined(CONFIG_MX6Q) || defined(CONFIG_MX6QDL)
+static void noc_setup(void)
+{
+ enable_ipu_clock();
+
+ writel(0x80000201, 0xbb0608);
+ /* Bypass IPU1 QoS generator */
+ writel(0x00000002, 0x00bb048c);
+ /* Bypass IPU2 QoS generator */
+ writel(0x00000002, 0x00bb050c);
+ /* Bandwidth THR for of PRE0 */
+ writel(0x00000200, 0x00bb0690);
+ /* Bandwidth THR for of PRE1 */
+ writel(0x00000200, 0x00bb0710);
+ /* Bandwidth THR for of PRE2 */
+ writel(0x00000200, 0x00bb0790);
+ /* Bandwidth THR for of PRE3 */
+ writel(0x00000200, 0x00bb0810);
+ /* Saturation THR for of PRE0 */
+ writel(0x00000010, 0x00bb0694);
+ /* Saturation THR for of PRE1 */
+ writel(0x00000010, 0x00bb0714);
+ /* Saturation THR for of PRE2 */
+ writel(0x00000010, 0x00bb0794);
+ /* Saturation THR for of PRE */
+ writel(0x00000010, 0x00bb0814);
+
+ disable_ipu_clock();
+}
+#endif
+
int arch_cpu_init(void)
{
struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
@@ -452,6 +477,10 @@ int arch_cpu_init(void)
init_src();
+#if defined(CONFIG_MX6Q) || defined(CONFIG_MX6QDL)
+ if (is_mx6dqp())
+ noc_setup();
+#endif
return 0;
}
diff --git a/arch/arm/mach-imx/mx7ulp/Kconfig b/arch/arm/mach-imx/mx7ulp/Kconfig
index ed5f0aeb2d..138c58363f 100644
--- a/arch/arm/mach-imx/mx7ulp/Kconfig
+++ b/arch/arm/mach-imx/mx7ulp/Kconfig
@@ -3,6 +3,11 @@ if ARCH_MX7ULP
config SYS_SOC
default "mx7ulp"
+config LDO_ENABLED_MODE
+ bool "i.MX7ULP LDO Enabled Mode"
+ help
+ Select this option to enable the PMC1 LDO.
+
config MX7ULP
bool
diff --git a/arch/arm/mach-imx/mx7ulp/scg.c b/arch/arm/mach-imx/mx7ulp/scg.c
index 819c90af6c..c7bb7a1c66 100644
--- a/arch/arm/mach-imx/mx7ulp/scg.c
+++ b/arch/arm/mach-imx/mx7ulp/scg.c
@@ -949,67 +949,6 @@ void scg_a7_ddrclk_init(void)
/* Clock source is System OSC <<0 */
#define SCG1_APLL_CFG_CLKSRC_NUM ((0x0) << SCG_PLL_CFG_CLKSRC_SHIFT)
-/*
- * A7 APLL = 24MHz / 1 * 22 / 1 / 1 = 528MHz,
- * system PLL is sourced from APLL,
- * APLL clock source is system OSC (24MHz)
- */
-#define SCG1_APLL_CFG_NUM_24M_OSC (SCG1_APLL_CFG_POSTDIV2_NUM | \
- SCG1_APLL_CFG_POSTDIV1_NUM | \
- (22 << SCG_PLL_CFG_MULT_SHIFT) | \
- SCG1_APLL_CFG_PFDSEL_NUM | \
- SCG1_APLL_CFG_PREDIV_NUM | \
- SCG1_APLL_CFG_BYPASS_NUM | \
- SCG1_APLL_CFG_PLLSEL_NUM | \
- SCG1_APLL_CFG_CLKSRC_NUM)
-
-/* PFD0 Freq = A7 APLL(528MHz) * 18 / 27 = 352MHz */
-#define SCG1_APLL_PFD0_FRAC_NUM (27)
-
-
-void scg_a7_apll_init(void)
-{
- u32 val = 0;
-
- /* Disable A7 Auxiliary PLL */
- val = readl(&scg1_regs->apllcsr);
- val &= ~SCG_APLL_CSR_APLLEN_MASK;
- writel(val, &scg1_regs->apllcsr);
-
- /* Gate off A7 APLL PFD0 ~ PDF4 */
- val = readl(&scg1_regs->apllpfd);
- val |= 0x80808080;
- writel(val, &scg1_regs->apllpfd);
-
- /* ================ A7 APLL Configuration Start ============== */
- /* Configure A7 Auxiliary PLL */
- writel(SCG1_APLL_CFG_NUM_24M_OSC, &scg1_regs->apllcfg);
-
- /* Enable A7 Auxiliary PLL */
- val = readl(&scg1_regs->apllcsr);
- val |= SCG_APLL_CSR_APLLEN_MASK;
- writel(val, &scg1_regs->apllcsr);
-
- /* Wait for A7 APLL clock ready */
- while (!(readl(&scg1_regs->apllcsr) & SCG_APLL_CSR_APLLVLD_MASK))
- ;
-
- /* Configure A7 APLL PFD0 */
- val = readl(&scg1_regs->apllpfd);
- val &= ~SCG_PLL_PFD0_FRAC_MASK;
- val |= SCG1_APLL_PFD0_FRAC_NUM;
- writel(val, &scg1_regs->apllpfd);
-
- /* Un-gate A7 APLL PFD0 */
- val = readl(&scg1_regs->apllpfd);
- val &= ~SCG_PLL_PFD0_GATE_MASK;
- writel(val, &scg1_regs->apllpfd);
-
- /* Wait for A7 APLL PFD0 clock being valid */
- while (!(readl(&scg1_regs->apllpfd) & SCG_PLL_PFD0_VALID_MASK))
- ;
-}
-
/* SCG1(A7) FIRC DIV configurations */
/* Disable FIRC DIV3 */
#define SCG1_FIRCDIV_DIV3_NUM ((0x0) << SCG_FIRCDIV_DIV3_SHIFT)
diff --git a/arch/arm/mach-imx/mx7ulp/soc.c b/arch/arm/mach-imx/mx7ulp/soc.c
index 4b6014e724..8345b01398 100644
--- a/arch/arm/mach-imx/mx7ulp/soc.c
+++ b/arch/arm/mach-imx/mx7ulp/soc.c
@@ -10,6 +10,22 @@
#include <asm/mach-imx/boot_mode.h>
#include <asm/mach-imx/hab.h>
+#define PMC0_BASE_ADDR 0x410a1000
+#define PMC0_CTRL 0x28
+#define PMC0_CTRL_LDOEN BIT(31)
+#define PMC0_CTRL_LDOOKDIS BIT(30)
+#define PMC0_CTRL_PMC1ON BIT(24)
+#define PMC1_BASE_ADDR 0x40400000
+#define PMC1_RUN 0x8
+#define PMC1_STOP 0x10
+#define PMC1_VLPS 0x14
+#define PMC1_LDOVL_SHIFT 16
+#define PMC1_LDOVL_MASK (0x3f << PMC1_LDOVL_SHIFT)
+#define PMC1_LDOVL_900 0x1e
+#define PMC1_LDOVL_950 0x23
+#define PMC1_STATUS 0x20
+#define PMC1_STATUS_LDOVLF BIT(8)
+
static char *get_reset_cause(char *);
#if defined(CONFIG_IMX_HAB)
@@ -101,6 +117,44 @@ void init_wdog(void)
disable_wdog(WDG2_RBASE);
}
+#if defined(CONFIG_LDO_ENABLED_MODE)
+static void init_ldo_mode(void)
+{
+ unsigned int reg;
+
+ /* Set LDOOKDIS */
+ setbits_le32(PMC0_BASE_ADDR + PMC0_CTRL, PMC0_CTRL_LDOOKDIS);
+
+ /* Set LDOVL to 0.95V in PMC1_RUN */
+ reg = readl(PMC1_BASE_ADDR + PMC1_RUN);
+ reg &= ~PMC1_LDOVL_MASK;
+ reg |= (PMC1_LDOVL_950 << PMC1_LDOVL_SHIFT);
+ writel(PMC1_BASE_ADDR + PMC1_RUN, reg);
+
+ /* Wait for LDOVLF to be cleared */
+ reg = readl(PMC1_BASE_ADDR + PMC1_STATUS);
+ while (reg & PMC1_STATUS_LDOVLF)
+ ;
+
+ /* Set LDOVL to 0.95V in PMC1_STOP */
+ reg = readl(PMC1_BASE_ADDR + PMC1_STOP);
+ reg &= ~PMC1_LDOVL_MASK;
+ reg |= (PMC1_LDOVL_950 << PMC1_LDOVL_SHIFT);
+ writel(PMC1_BASE_ADDR + PMC1_STOP, reg);
+
+ /* Set LDOVL to 0.90V in PMC1_VLPS */
+ reg = readl(PMC1_BASE_ADDR + PMC1_VLPS);
+ reg &= ~PMC1_LDOVL_MASK;
+ reg |= (PMC1_LDOVL_900 << PMC1_LDOVL_SHIFT);
+ writel(PMC1_BASE_ADDR + PMC1_VLPS, reg);
+
+ /* Set LDOEN bit */
+ setbits_le32(PMC0_BASE_ADDR + PMC0_CTRL, PMC0_CTRL_LDOEN);
+
+ /* Set the PMC1ON bit */
+ setbits_le32(PMC0_BASE_ADDR + PMC0_CTRL, PMC0_CTRL_PMC1ON);
+}
+#endif
void s_init(void)
{
@@ -114,6 +168,10 @@ void s_init(void)
/* enable dumb pmic */
writel((readl(SNVS_LP_LPCR) | SNVS_LPCR_DPEN), SNVS_LP_LPCR);
}
+
+#if defined(CONFIG_LDO_ENABLED_MODE)
+ init_ldo_mode();
+#endif
return;
}
@@ -132,6 +190,21 @@ const char *get_imx_type(u32 imxtype)
return "7ULP";
}
+#define PMC0_BASE_ADDR 0x410a1000
+#define PMC0_CTRL 0x28
+#define PMC0_CTRL_LDOEN BIT(31)
+
+static bool ldo_mode_is_enabled(void)
+{
+ unsigned int reg;
+
+ reg = readl(PMC0_BASE_ADDR + PMC0_CTRL);
+ if (reg & PMC0_CTRL_LDOEN)
+ return true;
+ else
+ return false;
+}
+
int print_cpuinfo(void)
{
u32 cpurev;
@@ -160,6 +233,11 @@ int print_cpuinfo(void)
break;
}
+ if (ldo_mode_is_enabled())
+ printf("PMC1: LDO enabled mode\n");
+ else
+ printf("PMC1: LDO bypass mode\n");
+
return 0;
}
#endif
diff --git a/arch/arm/mach-omap2/omap5/fdt.c b/arch/arm/mach-omap2/omap5/fdt.c
index 8dee555c10..5ba8806dd7 100644
--- a/arch/arm/mach-omap2/omap5/fdt.c
+++ b/arch/arm/mach-omap2/omap5/fdt.c
@@ -180,6 +180,14 @@ u32 dra7_opp_dsp_clk_rates[NUM_OPPS][OPP_DSP_CLK_NUM] = {
{750000000, 750000000, 500000000}, /* OPP_HIGH */
};
+/* DSP clock rates on DRA76x ACD-package based SoCs */
+u32 dra76_opp_dsp_clk_rates[NUM_OPPS][OPP_DSP_CLK_NUM] = {
+ {}, /* OPP_LOW */
+ {600000000, 600000000, 400000000}, /* OPP_NOM */
+ {700000000, 700000000, 466666667}, /* OPP_OD */
+ {850000000, 850000000, 566666667}, /* OPP_HIGH */
+};
+
/* IVA voltage domain */
u32 dra7_opp_iva_clk_rates[NUM_OPPS][OPP_IVA_CLK_NUM] = {
{}, /* OPP_LOW */
@@ -257,6 +265,10 @@ static void ft_opp_clock_fixups(void *fdt, bd_t *bd)
/* fixup DSP clocks */
clk_names = dra7_opp_dsp_clk_names;
clk_rates = dra7_opp_dsp_clk_rates[get_voltrail_opp(VOLT_EVE)];
+ /* adjust for higher OPP_HIGH clock rate on DRA76xP/DRA77xP SoCs */
+ if (is_dra76x_acd())
+ clk_rates = dra76_opp_dsp_clk_rates[get_voltrail_opp(VOLT_EVE)];
+
ret = ft_fixup_clocks(fdt, clk_names, clk_rates, OPP_DSP_CLK_NUM);
if (ret) {
printf("ft_fixup_clocks failed for DSP voltage domain: %s\n",
diff --git a/arch/arm/mach-rockchip/misc.c b/arch/arm/mach-rockchip/misc.c
index f697e937c6..6dbb9bde48 100644
--- a/arch/arm/mach-rockchip/misc.c
+++ b/arch/arm/mach-rockchip/misc.c
@@ -30,7 +30,7 @@ int rockchip_setup_macaddr(void)
/* Only generate a MAC address, if none is set in the environment */
if (env_get("ethaddr"))
- return -1;
+ return 0;
if (!cpuid) {
debug("%s: could not retrieve 'cpuid#'\n", __func__);
@@ -92,6 +92,7 @@ int rockchip_cpuid_set(const u8 *cpuid, const u32 cpuid_length)
char cpuid_str[cpuid_length * 2 + 1];
u64 serialno;
char serialno_str[17];
+ const char *oldid;
int i;
memset(cpuid_str, 0, sizeof(cpuid_str));
@@ -113,8 +114,16 @@ int rockchip_cpuid_set(const u8 *cpuid, const u32 cpuid_length)
serialno |= (u64)crc32_no_comp(serialno, high, 8) << 32;
snprintf(serialno_str, sizeof(serialno_str), "%016llx", serialno);
+ oldid = env_get("cpuid#");
+ if (oldid && strcmp(oldid, cpuid_str) != 0)
+ printf("cpuid: value %s present in env does not match hardware %s\n",
+ oldid, cpuid_str);
+
env_set("cpuid#", cpuid_str);
- env_set("serial#", serialno_str);
+
+ /* Only generate serial# when none is set yet */
+ if (!env_get("serial#"))
+ env_set("serial#", serialno_str);
return 0;
}
diff --git a/arch/arm/mach-rockchip/px30/Kconfig b/arch/arm/mach-rockchip/px30/Kconfig
index 109a37be15..9f3ad4f623 100644
--- a/arch/arm/mach-rockchip/px30/Kconfig
+++ b/arch/arm/mach-rockchip/px30/Kconfig
@@ -27,12 +27,12 @@ config TPL_MAX_SIZE
config TPL_STACK
default 0xff0e4fff
-config DEBUG_UART2_CHANNEL
- int "Mux channel to use for debug UART2"
+config DEBUG_UART_CHANNEL
+ int "Mux channel to use for debug UART2/UART3"
depends on DEBUG_UART_BOARD_INIT
default 0
help
- UART2 can use two different set of pins to route the output.
+ UART2 and UART3 can use two different set of pins to route the output.
For using the UART for early debugging the route to use needs
to be declared (0 or 1).
diff --git a/arch/arm/mach-rockchip/px30/px30.c b/arch/arm/mach-rockchip/px30/px30.c
index bacdcc0b93..5014ee83d7 100644
--- a/arch/arm/mach-rockchip/px30/px30.c
+++ b/arch/arm/mach-rockchip/px30/px30.c
@@ -37,6 +37,7 @@ static struct mm_region px30_mem_map[] = {
struct mm_region *mem_map = px30_mem_map;
#define PMU_PWRDN_CON 0xff000018
+#define PMUGRF_BASE 0xff010000
#define GRF_BASE 0xff140000
#define CRU_BASE 0xff2b0000
#define VIDEO_PHY_BASE 0xff2e0000
@@ -49,6 +50,23 @@ struct mm_region *mem_map = px30_mem_map;
#define QOS_PRIORITY_LEVEL(h, l) ((((h) & 3) << 8) | ((l) & 3))
+/* GRF_GPIO1BH_IOMUX */
+enum {
+ GPIO1B7_SHIFT = 12,
+ GPIO1B7_MASK = 0xf << GPIO1B7_SHIFT,
+ GPIO1B7_GPIO = 0,
+ GPIO1B7_FLASH_RDN,
+ GPIO1B7_UART3_RXM1,
+ GPIO1B7_SPI0_CLK,
+
+ GPIO1B6_SHIFT = 8,
+ GPIO1B6_MASK = 0xf << GPIO1B6_SHIFT,
+ GPIO1B6_GPIO = 0,
+ GPIO1B6_FLASH_CS1,
+ GPIO1B6_UART3_TXM1,
+ GPIO1B6_SPI0_CSN,
+};
+
/* GRF_GPIO1CL_IOMUX */
enum {
GPIO1C1_SHIFT = 4,
@@ -128,6 +146,23 @@ enum {
GPIO3A1_UART5_RX = 4,
};
+/* PMUGRF_GPIO0CL_IOMUX */
+enum {
+ GPIO0C1_SHIFT = 2,
+ GPIO0C1_MASK = 0x3 << GPIO0C1_SHIFT,
+ GPIO0C1_GPIO = 0,
+ GPIO0C1_PWM_3,
+ GPIO0C1_UART3_RXM0,
+ GPIO0C1_PMU_DEBUG4,
+
+ GPIO0C0_SHIFT = 0,
+ GPIO0C0_MASK = 0x3 << GPIO0C0_SHIFT,
+ GPIO0C0_GPIO = 0,
+ GPIO0C0_PWM_1,
+ GPIO0C0_UART3_TXM0,
+ GPIO0C0_PMU_DEBUG3,
+};
+
int arch_cpu_init(void)
{
static struct px30_grf * const grf = (void *)GRF_BASE;
@@ -175,6 +210,11 @@ int arch_cpu_init(void)
#ifdef CONFIG_DEBUG_UART_BOARD_INIT
void board_debug_uart_init(void)
{
+#if defined(CONFIG_DEBUG_UART_BASE) && \
+ (CONFIG_DEBUG_UART_BASE == 0xff168000) && \
+ (CONFIG_DEBUG_UART_CHANNEL != 1)
+ static struct px30_pmugrf * const pmugrf = (void *)PMUGRF_BASE;
+#endif
static struct px30_grf * const grf = (void *)GRF_BASE;
static struct px30_cru * const cru = (void *)CRU_BASE;
@@ -191,6 +231,43 @@ void board_debug_uart_init(void)
GPIO1C1_MASK | GPIO1C0_MASK,
GPIO1C1_UART1_TX << GPIO1C1_SHIFT |
GPIO1C0_UART1_RX << GPIO1C0_SHIFT);
+#elif defined(CONFIG_DEBUG_UART_BASE) && (CONFIG_DEBUG_UART_BASE == 0xff168000)
+ /* GRF_IOFUNC_CON0 */
+ enum {
+ CON_IOMUX_UART3SEL_SHIFT = 9,
+ CON_IOMUX_UART3SEL_MASK = 1 << CON_IOMUX_UART3SEL_SHIFT,
+ CON_IOMUX_UART3SEL_M0 = 0,
+ CON_IOMUX_UART3SEL_M1,
+ };
+
+ /* uart_sel_clk default select 24MHz */
+ rk_clrsetreg(&cru->clksel_con[40],
+ UART3_PLL_SEL_MASK | UART3_DIV_CON_MASK,
+ UART3_PLL_SEL_24M << UART3_PLL_SEL_SHIFT | 0);
+ rk_clrsetreg(&cru->clksel_con[41],
+ UART3_CLK_SEL_MASK,
+ UART3_CLK_SEL_UART3 << UART3_CLK_SEL_SHIFT);
+
+#if (CONFIG_DEBUG_UART_CHANNEL == 1)
+ rk_clrsetreg(&grf->iofunc_con0,
+ CON_IOMUX_UART3SEL_MASK,
+ CON_IOMUX_UART3SEL_M1 << CON_IOMUX_UART3SEL_SHIFT);
+
+ rk_clrsetreg(&grf->gpio1bh_iomux,
+ GPIO1B7_MASK | GPIO1B6_MASK,
+ GPIO1B7_UART3_RXM1 << GPIO1B7_SHIFT |
+ GPIO1B6_UART3_TXM1 << GPIO1B6_SHIFT);
+#else
+ rk_clrsetreg(&grf->iofunc_con0,
+ CON_IOMUX_UART3SEL_MASK,
+ CON_IOMUX_UART3SEL_M0 << CON_IOMUX_UART3SEL_SHIFT);
+
+ rk_clrsetreg(&pmugrf->gpio0cl_iomux,
+ GPIO0C1_MASK | GPIO0C0_MASK,
+ GPIO0C1_UART3_RXM0 << GPIO0C1_SHIFT |
+ GPIO0C0_UART3_TXM0 << GPIO0C0_SHIFT);
+#endif /* CONFIG_DEBUG_UART_CHANNEL == 1 */
+
#elif defined(CONFIG_DEBUG_UART_BASE) && (CONFIG_DEBUG_UART_BASE == 0xff178000)
/* uart_sel_clk default select 24MHz */
rk_clrsetreg(&cru->clksel_con[46],
@@ -222,7 +299,7 @@ void board_debug_uart_init(void)
UART2_CLK_SEL_MASK,
UART2_CLK_SEL_UART2 << UART2_CLK_SEL_SHIFT);
-#if (CONFIG_DEBUG_UART2_CHANNEL == 1)
+#if (CONFIG_DEBUG_UART_CHANNEL == 1)
/* Enable early UART2 */
rk_clrsetreg(&grf->iofunc_con0,
CON_IOMUX_UART2SEL_MASK,
@@ -241,7 +318,7 @@ void board_debug_uart_init(void)
GPIO1D3_MASK | GPIO1D2_MASK,
GPIO1D3_UART2_RXM0 << GPIO1D3_SHIFT |
GPIO1D2_UART2_TXM0 << GPIO1D2_SHIFT);
-#endif /* CONFIG_DEBUG_UART2_CHANNEL == 1 */
+#endif /* CONFIG_DEBUG_UART_CHANNEL == 1 */
#endif /* CONFIG_DEBUG_UART_BASE && CONFIG_DEBUG_UART_BASE == ... */
}
diff --git a/arch/arm/mach-rockchip/rk3308/rk3308.c b/arch/arm/mach-rockchip/rk3308/rk3308.c
index f27f9e8c0b..b6815ddc55 100644
--- a/arch/arm/mach-rockchip/rk3308/rk3308.c
+++ b/arch/arm/mach-rockchip/rk3308/rk3308.c
@@ -72,6 +72,11 @@ enum {
UART2_IO_SEL_M1,
UART2_IO_SEL_USB,
+ GPIO2C0_SEL_SRC_CTRL_SHIFT = 11,
+ GPIO2C0_SEL_SRC_CTRL_MASK = BIT(11),
+ GPIO2C0_SEL_SRC_CTRL_IOMUX = 0,
+ GPIO2C0_SEL_SRC_CTRL_SEL_PLUS,
+
GPIO3B3_SEL_SRC_CTRL_SHIFT = 7,
GPIO3B3_SEL_SRC_CTRL_MASK = BIT(7),
GPIO3B3_SEL_SRC_CTRL_IOMUX = 0,
@@ -97,6 +102,18 @@ enum {
GPIO3B2_SEL_PLUS_EMMC_RSTN,
GPIO3B2_SEL_PLUS_SPI1_MISO,
GPIO3B2_SEL_PLUS_LCDC_D22_M1,
+
+ I2C3_IOFUNC_SRC_CTRL_SHIFT = 10,
+ I2C3_IOFUNC_SRC_CTRL_MASK = BIT(10),
+ I2C3_IOFUNC_SRC_CTRL_SEL_PLUS = 1,
+
+ GPIO2A3_SEL_SRC_CTRL_SHIFT = 7,
+ GPIO2A3_SEL_SRC_CTRL_MASK = BIT(7),
+ GPIO2A3_SEL_SRC_CTRL_SEL_PLUS = 1,
+
+ GPIO2A2_SEL_SRC_CTRL_SHIFT = 3,
+ GPIO2A2_SEL_SRC_CTRL_MASK = BIT(3),
+ GPIO2A2_SEL_SRC_CTRL_SEL_PLUS = 1,
};
enum {
@@ -166,10 +183,30 @@ __weak void board_debug_uart_init(void)
int arch_cpu_init(void)
{
static struct rk3308_sgrf * const sgrf = (void *)SGRF_BASE;
+ static struct rk3308_grf * const grf = (void *)GRF_BASE;
/* Set CRYPTO SDMMC EMMC NAND SFC USB master bus to be secure access */
rk_clrreg(&sgrf->con_secure0, 0x2b83);
+ /*
+ * Enable plus options to use more pinctrl functions, including
+ * GPIO2A2_PLUS, GPIO2A3_PLUS and I2C3_MULTI_SRC_PLUS.
+ */
+ rk_clrsetreg(&grf->soc_con13,
+ I2C3_IOFUNC_SRC_CTRL_MASK | GPIO2A3_SEL_SRC_CTRL_MASK |
+ GPIO2A2_SEL_SRC_CTRL_MASK,
+ I2C3_IOFUNC_SRC_CTRL_SEL_PLUS << I2C3_IOFUNC_SRC_CTRL_SHIFT |
+ GPIO2A3_SEL_SRC_CTRL_SEL_PLUS << GPIO2A3_SEL_SRC_CTRL_SHIFT |
+ GPIO2A2_SEL_SRC_CTRL_SEL_PLUS << GPIO2A2_SEL_SRC_CTRL_SHIFT);
+
+ /* Plus options about GPIO3B2_PLUS, GPIO3B3_PLUS and GPIO2C0_PLUS. */
+ rk_clrsetreg(&grf->soc_con15,
+ GPIO2C0_SEL_SRC_CTRL_MASK | GPIO3B3_SEL_SRC_CTRL_MASK |
+ GPIO3B2_SEL_SRC_CTRL_MASK,
+ GPIO2C0_SEL_SRC_CTRL_SEL_PLUS << GPIO2C0_SEL_SRC_CTRL_SHIFT |
+ GPIO3B3_SEL_SRC_CTRL_SEL_PLUS << GPIO3B3_SEL_SRC_CTRL_SHIFT |
+ GPIO3B2_SEL_SRC_CTRL_SEL_PLUS << GPIO3B2_SEL_SRC_CTRL_SHIFT);
+
return 0;
}
#endif
diff --git a/arch/arm/mach-tegra/cboot.c b/arch/arm/mach-tegra/cboot.c
index 0433081c6c..0762144ecf 100644
--- a/arch/arm/mach-tegra/cboot.c
+++ b/arch/arm/mach-tegra/cboot.c
@@ -495,7 +495,7 @@ static int cboot_get_ethaddr_legacy(const void *fdt, uint8_t mac[ETH_ALEN])
return -ENOENT;
}
- eth_parse_enetaddr(prop, mac);
+ string_to_enetaddr(prop, mac);
if (!is_valid_ethaddr(mac)) {
printf("Invalid MAC address: %s\n", prop);
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 01975d7c60..85e15ebffa 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -224,7 +224,7 @@ config XIP
config STACK_SIZE_SHIFT
int
- default 13
+ default 14
config SPL_LDSCRIPT
default "arch/riscv/cpu/u-boot-spl.lds"
diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig
index d411a79c21..8d8d71dcbf 100644
--- a/arch/riscv/cpu/ax25/Kconfig
+++ b/arch/riscv/cpu/ax25/Kconfig
@@ -6,7 +6,9 @@ config RISCV_NDS
imply RISCV_TIMER
imply ANDES_PLIC if (RISCV_MMODE || SPL_RISCV_MMODE)
imply ANDES_PLMT if (RISCV_MMODE || SPL_RISCV_MMODE)
- imply V5L2_CACHE
+ imply SPL_CPU_SUPPORT
+ imply SPL_OPENSBI
+ imply SPL_LOAD_FIT
help
Run U-Boot on AndeStar V5 platforms and use some specific features
which are provided by Andes Technology AndeStar V5 families.
diff --git a/arch/riscv/cpu/ax25/cache.c b/arch/riscv/cpu/ax25/cache.c
index 1455f2298f..9f424198b4 100644
--- a/arch/riscv/cpu/ax25/cache.c
+++ b/arch/riscv/cpu/ax25/cache.c
@@ -12,18 +12,46 @@
#include <asm/csr.h>
#ifdef CONFIG_RISCV_NDS_CACHE
+#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
/* mcctlcommand */
#define CCTL_REG_MCCTLCOMMAND_NUM 0x7cc
/* D-cache operation */
#define CCTL_L1D_WBINVAL_ALL 6
#endif
+#endif
+
+#ifdef CONFIG_V5L2_CACHE
+static void _cache_enable(void)
+{
+ struct udevice *dev = NULL;
+
+ uclass_find_first_device(UCLASS_CACHE, &dev);
+
+ if (dev)
+ cache_enable(dev);
+}
+
+static void _cache_disable(void)
+{
+ struct udevice *dev = NULL;
+
+ uclass_find_first_device(UCLASS_CACHE, &dev);
+
+ if (dev)
+ cache_disable(dev);
+}
+#endif
void flush_dcache_all(void)
{
+#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
#ifdef CONFIG_RISCV_NDS_CACHE
+#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
csr_write(CCTL_REG_MCCTLCOMMAND_NUM, CCTL_L1D_WBINVAL_ALL);
#endif
+#endif
+#endif
}
void flush_dcache_range(unsigned long start, unsigned long end)
@@ -40,6 +68,7 @@ void icache_enable(void)
{
#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
#ifdef CONFIG_RISCV_NDS_CACHE
+#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
asm volatile (
"csrr t1, mcache_ctl\n\t"
"ori t0, t1, 0x1\n\t"
@@ -47,12 +76,14 @@ void icache_enable(void)
);
#endif
#endif
+#endif
}
void icache_disable(void)
{
#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
#ifdef CONFIG_RISCV_NDS_CACHE
+#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
asm volatile (
"fence.i\n\t"
"csrr t1, mcache_ctl\n\t"
@@ -61,24 +92,23 @@ void icache_disable(void)
);
#endif
#endif
+#endif
}
void dcache_enable(void)
{
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
#ifdef CONFIG_RISCV_NDS_CACHE
- struct udevice *dev = NULL;
-
+#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
asm volatile (
"csrr t1, mcache_ctl\n\t"
"ori t0, t1, 0x2\n\t"
"csrw mcache_ctl, t0\n\t"
);
-
- uclass_find_first_device(UCLASS_CACHE, &dev);
-
- if (dev)
- cache_enable(dev);
+#endif
+#ifdef CONFIG_V5L2_CACHE
+ _cache_enable();
+#endif
#endif
#endif
}
@@ -87,19 +117,17 @@ void dcache_disable(void)
{
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
#ifdef CONFIG_RISCV_NDS_CACHE
- struct udevice *dev = NULL;
-
+#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
csr_write(CCTL_REG_MCCTLCOMMAND_NUM, CCTL_L1D_WBINVAL_ALL);
asm volatile (
"csrr t1, mcache_ctl\n\t"
"andi t0, t1, ~0x2\n\t"
"csrw mcache_ctl, t0\n\t"
);
-
- uclass_find_first_device(UCLASS_CACHE, &dev);
-
- if (dev)
- cache_disable(dev);
+#endif
+#ifdef CONFIG_V5L2_CACHE
+ _cache_disable();
+#endif
#endif
#endif
}
@@ -109,6 +137,7 @@ int icache_status(void)
int ret = 0;
#ifdef CONFIG_RISCV_NDS_CACHE
+#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
asm volatile (
"csrr t1, mcache_ctl\n\t"
"andi %0, t1, 0x01\n\t"
@@ -117,6 +146,7 @@ int icache_status(void)
: "memory"
);
#endif
+#endif
return ret;
}
@@ -126,6 +156,7 @@ int dcache_status(void)
int ret = 0;
#ifdef CONFIG_RISCV_NDS_CACHE
+#if CONFIG_IS_ENABLED(RISCV_MMODE) || CONFIG_IS_ENABLED(SPL_RISCV_MMODE)
asm volatile (
"csrr t1, mcache_ctl\n\t"
"andi %0, t1, 0x02\n\t"
@@ -134,6 +165,7 @@ int dcache_status(void)
: "memory"
);
#endif
+#endif
return ret;
}
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 0a2ce6d691..1a55b7d570 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -174,7 +174,7 @@ spl_clear_bss:
spl_clear_bss_loop:
SREG zero, 0(t0)
addi t0, t0, REGBYTES
- bne t0, t1, spl_clear_bss_loop
+ blt t0, t1, spl_clear_bss_loop
spl_stack_gd_setup:
jal spl_relocate_stack_gd
@@ -197,6 +197,7 @@ spl_secondary_hart_stack_gd_setup:
la a0, secondary_hart_relocate
mv a1, s0
mv a2, s0
+ mv a3, zero
jal smp_call_function
/* hang if relocation of secondary harts has failed */
@@ -324,7 +325,7 @@ clear_bss:
clbss_l:
SREG zero, 0(t0) /* clear loop... */
addi t0, t0, REGBYTES
- bne t0, t1, clbss_l
+ blt t0, t1, clbss_l
relocate_secondary_harts:
#ifdef CONFIG_SMP
@@ -337,6 +338,7 @@ relocate_secondary_harts:
mv a1, s2
mv a2, s3
+ mv a3, zero
jal smp_call_function
/* hang if relocation of secondary harts has failed */
diff --git a/arch/riscv/cpu/u-boot-spl.lds b/arch/riscv/cpu/u-boot-spl.lds
index 32255d58de..955dd3106d 100644
--- a/arch/riscv/cpu/u-boot-spl.lds
+++ b/arch/riscv/cpu/u-boot-spl.lds
@@ -76,7 +76,7 @@ SECTIONS
.bss : {
__bss_start = .;
*(.bss*)
- . = ALIGN(4);
+ . = ALIGN(8);
__bss_end = .;
} > .bss_mem
}
diff --git a/arch/riscv/cpu/u-boot.lds b/arch/riscv/cpu/u-boot.lds
index 11bc4a738b..838a844399 100644
--- a/arch/riscv/cpu/u-boot.lds
+++ b/arch/riscv/cpu/u-boot.lds
@@ -82,7 +82,7 @@ SECTIONS
.bss : {
__bss_start = .;
*(.bss*)
- . = ALIGN(4);
+ . = ALIGN(8);
__bss_end = .;
}
}
diff --git a/arch/riscv/dts/Makefile b/arch/riscv/dts/Makefile
index f9cd606a9a..4f30e6936f 100644
--- a/arch/riscv/dts/Makefile
+++ b/arch/riscv/dts/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
dtb-$(CONFIG_TARGET_AX25_AE350) += ae350_32.dtb ae350_64.dtb
+dtb-$(CONFIG_TARGET_SIFIVE_FU540) += hifive-unleashed-a00.dtb
targets += $(dtb-y)
diff --git a/arch/riscv/dts/ae350_32.dts b/arch/riscv/dts/ae350_32.dts
index 97b7cee983..3f8525fe56 100644
--- a/arch/riscv/dts/ae350_32.dts
+++ b/arch/riscv/dts/ae350_32.dts
@@ -62,6 +62,48 @@
compatible = "riscv,cpu-intc";
};
};
+ CPU2: cpu@2 {
+ device_type = "cpu";
+ reg = <2>;
+ 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>;
+ CPU2_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ };
+ };
+ CPU3: cpu@3 {
+ device_type = "cpu";
+ reg = <3>;
+ 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>;
+ CPU3_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ };
+ };
};
L2: l2-cache@e0500000 {
@@ -94,7 +136,10 @@
interrupt-controller;
reg = <0xe4000000 0x2000000>;
riscv,ndev=<71>;
- interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9 &CPU1_intc 11 &CPU1_intc 9>;
+ interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9
+ &CPU1_intc 11 &CPU1_intc 9
+ &CPU2_intc 11 &CPU2_intc 9
+ &CPU3_intc 11 &CPU3_intc 9>;
};
plic1: interrupt-controller@e6400000 {
@@ -104,12 +149,18 @@
interrupt-controller;
reg = <0xe6400000 0x400000>;
riscv,ndev=<2>;
- interrupts-extended = <&CPU0_intc 3 &CPU1_intc 3>;
+ interrupts-extended = <&CPU0_intc 3
+ &CPU1_intc 3
+ &CPU2_intc 3
+ &CPU3_intc 3>;
};
plmt0@e6000000 {
compatible = "riscv,plmt0";
- interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7>;
+ interrupts-extended = <&CPU0_intc 7
+ &CPU1_intc 7
+ &CPU2_intc 7
+ &CPU3_intc 7>;
reg = <0xe6000000 0x100000>;
};
};
@@ -245,8 +296,10 @@
};
nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
compatible = "cfi-flash";
- reg = <0x88000000 0x1000>;
+ reg = <0x88000000 0x4000000>;
bank-width = <2>;
device-width = <1>;
};
diff --git a/arch/riscv/dts/ae350_64.dts b/arch/riscv/dts/ae350_64.dts
index d8f00f8d3a..482c707503 100644
--- a/arch/riscv/dts/ae350_64.dts
+++ b/arch/riscv/dts/ae350_64.dts
@@ -62,6 +62,48 @@
compatible = "riscv,cpu-intc";
};
};
+ CPU2: cpu@2 {
+ device_type = "cpu";
+ reg = <2>;
+ 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>;
+ CPU2_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ };
+ };
+ CPU3: cpu@3 {
+ device_type = "cpu";
+ reg = <3>;
+ 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>;
+ CPU3_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ };
+ };
};
L2: l2-cache@e0500000 {
@@ -94,7 +136,10 @@
interrupt-controller;
reg = <0x0 0xe4000000 0x0 0x2000000>;
riscv,ndev=<71>;
- interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9 &CPU1_intc 11 &CPU1_intc 9>;
+ interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9
+ &CPU1_intc 11 &CPU1_intc 9
+ &CPU2_intc 11 &CPU2_intc 9
+ &CPU3_intc 11 &CPU3_intc 9>;
};
plic1: interrupt-controller@e6400000 {
@@ -104,12 +149,18 @@
interrupt-controller;
reg = <0x0 0xe6400000 0x0 0x400000>;
riscv,ndev=<2>;
- interrupts-extended = <&CPU0_intc 3 &CPU1_intc 3>;
+ interrupts-extended = <&CPU0_intc 3
+ &CPU1_intc 3
+ &CPU2_intc 3
+ &CPU3_intc 3>;
};
plmt0@e6000000 {
compatible = "riscv,plmt0";
- interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7>;
+ interrupts-extended = <&CPU0_intc 7
+ &CPU1_intc 7
+ &CPU2_intc 7
+ &CPU3_intc 7>;
reg = <0x0 0xe6000000 0x0 0x100000>;
};
};
@@ -245,8 +296,10 @@
};
nor@0,0 {
+ #address-cells = <2>;
+ #size-cells = <2>;
compatible = "cfi-flash";
- reg = <0x0 0x88000000 0x0 0x1000>;
+ reg = <0x0 0x88000000 0x0 0x4000000>;
bank-width = <2>;
device-width = <1>;
};
diff --git a/arch/riscv/dts/fu540-c000.dtsi b/arch/riscv/dts/fu540-c000.dtsi
new file mode 100644
index 0000000000..afa43c7ea3
--- /dev/null
+++ b/arch/riscv/dts/fu540-c000.dtsi
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2018-2019 SiFive, Inc */
+
+/dts-v1/;
+
+#include <dt-bindings/clock/sifive-fu540-prci.h>
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ compatible = "sifive,fu540-c000", "sifive,fu540";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ ethernet0 = &eth0;
+ };
+
+ chosen {
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu0: cpu@0 {
+ compatible = "sifive,e51", "sifive,rocket0", "riscv";
+ device_type = "cpu";
+ i-cache-block-size = <64>;
+ i-cache-sets = <128>;
+ i-cache-size = <16384>;
+ reg = <0>;
+ riscv,isa = "rv64imac";
+ status = "disabled";
+ cpu0_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ compatible = "riscv,cpu-intc";
+ interrupt-controller;
+ };
+ };
+ cpu1: cpu@1 {
+ compatible = "sifive,u54-mc", "sifive,rocket0", "riscv";
+ d-cache-block-size = <64>;
+ d-cache-sets = <64>;
+ d-cache-size = <32768>;
+ d-tlb-sets = <1>;
+ d-tlb-size = <32>;
+ device_type = "cpu";
+ i-cache-block-size = <64>;
+ i-cache-sets = <64>;
+ i-cache-size = <32768>;
+ i-tlb-sets = <1>;
+ i-tlb-size = <32>;
+ mmu-type = "riscv,sv39";
+ reg = <1>;
+ riscv,isa = "rv64imafdc";
+ tlb-split;
+ cpu1_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ compatible = "riscv,cpu-intc";
+ interrupt-controller;
+ };
+ };
+ cpu2: cpu@2 {
+ compatible = "sifive,u54-mc", "sifive,rocket0", "riscv";
+ d-cache-block-size = <64>;
+ d-cache-sets = <64>;
+ d-cache-size = <32768>;
+ d-tlb-sets = <1>;
+ d-tlb-size = <32>;
+ device_type = "cpu";
+ i-cache-block-size = <64>;
+ i-cache-sets = <64>;
+ i-cache-size = <32768>;
+ i-tlb-sets = <1>;
+ i-tlb-size = <32>;
+ mmu-type = "riscv,sv39";
+ reg = <2>;
+ riscv,isa = "rv64imafdc";
+ tlb-split;
+ cpu2_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ compatible = "riscv,cpu-intc";
+ interrupt-controller;
+ };
+ };
+ cpu3: cpu@3 {
+ compatible = "sifive,u54-mc", "sifive,rocket0", "riscv";
+ d-cache-block-size = <64>;
+ d-cache-sets = <64>;
+ d-cache-size = <32768>;
+ d-tlb-sets = <1>;
+ d-tlb-size = <32>;
+ device_type = "cpu";
+ i-cache-block-size = <64>;
+ i-cache-sets = <64>;
+ i-cache-size = <32768>;
+ i-tlb-sets = <1>;
+ i-tlb-size = <32>;
+ mmu-type = "riscv,sv39";
+ reg = <3>;
+ riscv,isa = "rv64imafdc";
+ tlb-split;
+ cpu3_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ compatible = "riscv,cpu-intc";
+ interrupt-controller;
+ };
+ };
+ cpu4: cpu@4 {
+ compatible = "sifive,u54-mc", "sifive,rocket0", "riscv";
+ d-cache-block-size = <64>;
+ d-cache-sets = <64>;
+ d-cache-size = <32768>;
+ d-tlb-sets = <1>;
+ d-tlb-size = <32>;
+ device_type = "cpu";
+ i-cache-block-size = <64>;
+ i-cache-sets = <64>;
+ i-cache-size = <32768>;
+ i-tlb-sets = <1>;
+ i-tlb-size = <32>;
+ mmu-type = "riscv,sv39";
+ reg = <4>;
+ riscv,isa = "rv64imafdc";
+ tlb-split;
+ cpu4_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ compatible = "riscv,cpu-intc";
+ interrupt-controller;
+ };
+ };
+ };
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ compatible = "sifive,fu540-c000", "sifive,fu540", "simple-bus";
+ ranges;
+ plic0: interrupt-controller@c000000 {
+ #interrupt-cells = <1>;
+ compatible = "sifive,plic-1.0.0";
+ reg = <0x0 0xc000000 0x0 0x4000000>;
+ riscv,ndev = <53>;
+ interrupt-controller;
+ interrupts-extended = <
+ &cpu0_intc 0xffffffff
+ &cpu1_intc 0xffffffff &cpu1_intc 9
+ &cpu2_intc 0xffffffff &cpu2_intc 9
+ &cpu3_intc 0xffffffff &cpu3_intc 9
+ &cpu4_intc 0xffffffff &cpu4_intc 9>;
+ };
+ prci: clock-controller@10000000 {
+ compatible = "sifive,fu540-c000-prci";
+ reg = <0x0 0x10000000 0x0 0x1000>;
+ clocks = <&hfclk>, <&rtcclk>;
+ #clock-cells = <1>;
+ };
+ uart0: serial@10010000 {
+ compatible = "sifive,fu540-c000-uart", "sifive,uart0";
+ reg = <0x0 0x10010000 0x0 0x1000>;
+ interrupt-parent = <&plic0>;
+ interrupts = <4>;
+ clocks = <&prci PRCI_CLK_TLCLK>;
+ status = "disabled";
+ };
+ uart1: serial@10011000 {
+ compatible = "sifive,fu540-c000-uart", "sifive,uart0";
+ reg = <0x0 0x10011000 0x0 0x1000>;
+ interrupt-parent = <&plic0>;
+ interrupts = <5>;
+ clocks = <&prci PRCI_CLK_TLCLK>;
+ status = "disabled";
+ };
+ i2c0: i2c@10030000 {
+ compatible = "sifive,fu540-c000-i2c", "sifive,i2c0";
+ reg = <0x0 0x10030000 0x0 0x1000>;
+ interrupt-parent = <&plic0>;
+ interrupts = <50>;
+ clocks = <&prci PRCI_CLK_TLCLK>;
+ reg-shift = <2>;
+ reg-io-width = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ qspi0: spi@10040000 {
+ compatible = "sifive,fu540-c000-spi", "sifive,spi0";
+ reg = <0x0 0x10040000 0x0 0x1000
+ 0x0 0x20000000 0x0 0x10000000>;
+ interrupt-parent = <&plic0>;
+ interrupts = <51>;
+ clocks = <&prci PRCI_CLK_TLCLK>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ qspi1: spi@10041000 {
+ compatible = "sifive,fu540-c000-spi", "sifive,spi0";
+ reg = <0x0 0x10041000 0x0 0x1000
+ 0x0 0x30000000 0x0 0x10000000>;
+ interrupt-parent = <&plic0>;
+ interrupts = <52>;
+ clocks = <&prci PRCI_CLK_TLCLK>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ qspi2: spi@10050000 {
+ compatible = "sifive,fu540-c000-spi", "sifive,spi0";
+ reg = <0x0 0x10050000 0x0 0x1000>;
+ interrupt-parent = <&plic0>;
+ interrupts = <6>;
+ clocks = <&prci PRCI_CLK_TLCLK>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ eth0: ethernet@10090000 {
+ compatible = "sifive,fu540-c000-gem";
+ interrupt-parent = <&plic0>;
+ interrupts = <53>;
+ reg = <0x0 0x10090000 0x0 0x2000
+ 0x0 0x100a0000 0x0 0x1000>;
+ local-mac-address = [00 00 00 00 00 00];
+ clock-names = "pclk", "hclk";
+ clocks = <&prci PRCI_CLK_GEMGXLPLL>,
+ <&prci PRCI_CLK_GEMGXLPLL>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ pwm0: pwm@10020000 {
+ compatible = "sifive,fu540-c000-pwm", "sifive,pwm0";
+ reg = <0x0 0x10020000 0x0 0x1000>;
+ interrupt-parent = <&plic0>;
+ interrupts = <42 43 44 45>;
+ clocks = <&prci PRCI_CLK_TLCLK>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+ pwm1: pwm@10021000 {
+ compatible = "sifive,fu540-c000-pwm", "sifive,pwm0";
+ reg = <0x0 0x10021000 0x0 0x1000>;
+ interrupt-parent = <&plic0>;
+ interrupts = <46 47 48 49>;
+ clocks = <&prci PRCI_CLK_TLCLK>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ };
+};
diff --git a/arch/riscv/dts/hifive-unleashed-a00.dts b/arch/riscv/dts/hifive-unleashed-a00.dts
new file mode 100644
index 0000000000..88cfcb96bf
--- /dev/null
+++ b/arch/riscv/dts/hifive-unleashed-a00.dts
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2018-2019 SiFive, Inc */
+
+#include "fu540-c000.dtsi"
+
+/* Clock frequency (in Hz) of the PCB crystal for rtcclk */
+#define RTCCLK_FREQ 1000000
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ model = "SiFive HiFive Unleashed A00";
+ compatible = "sifive,hifive-unleashed-a00", "sifive,fu540-c000";
+
+ chosen {
+ stdout-path = "serial0";
+ };
+
+ cpus {
+ timebase-frequency = <RTCCLK_FREQ>;
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x0 0x80000000 0x2 0x00000000>;
+ };
+
+ soc {
+ };
+
+ hfclk: hfclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <33333333>;
+ clock-output-names = "hfclk";
+ };
+
+ rtcclk: rtcclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <RTCCLK_FREQ>;
+ clock-output-names = "rtcclk";
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&qspi0 {
+ status = "okay";
+ flash@0 {
+ compatible = "issi,is25wp256", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <50000000>;
+ m25p,fast-read;
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+ };
+};
+
+&qspi2 {
+ status = "okay";
+ mmc@0 {
+ compatible = "mmc-spi-slot";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ voltage-ranges = <3300 3300>;
+ disable-wp;
+ };
+};
+
+&eth0 {
+ status = "okay";
+ phy-mode = "gmii";
+ phy-handle = <&phy0>;
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+};
+
+&pwm0 {
+ status = "okay";
+};
+
+&pwm1 {
+ status = "okay";
+};
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
index bc863fdbaf..74de92ed13 100644
--- a/arch/riscv/include/asm/smp.h
+++ b/arch/riscv/include/asm/smp.h
@@ -46,8 +46,9 @@ void handle_ipi(ulong hart);
* @addr: Address of function
* @arg0: First argument of function
* @arg1: Second argument of function
+ * @wait: Wait for harts to acknowledge request
* @return 0 if OK, -ve on error
*/
-int smp_call_function(ulong addr, ulong arg0, ulong arg1);
+int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait);
#endif
diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c
index 28568e4e2b..3868569a65 100644
--- a/arch/riscv/lib/andes_plic.c
+++ b/arch/riscv/lib/andes_plic.c
@@ -19,7 +19,7 @@
#include <cpu.h>
/* pending register */
-#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + (hart) * 8)
+#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + ((hart) / 4) * 4)
/* enable register */
#define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80)
/* claim register */
@@ -46,7 +46,7 @@ static int init_plic(void);
static int enable_ipi(int hart)
{
- int en;
+ unsigned int en;
en = ENABLE_HART_IPI >> hart;
writel(en, (void __iomem *)ENABLE_REG(gd->arch.plic, hart));
@@ -94,10 +94,13 @@ static int init_plic(void)
int riscv_send_ipi(int hart)
{
+ unsigned int ipi;
+
PLIC_BASE_GET();
- writel(SEND_IPI_TO_HART(hart),
- (void __iomem *)PENDING_REG(gd->arch.plic, gd->arch.boot_hart));
+ ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart));
+ writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plic,
+ gd->arch.boot_hart));
return 0;
}
@@ -114,6 +117,17 @@ int riscv_clear_ipi(int hart)
return 0;
}
+int riscv_get_ipi(int hart, int *pending)
+{
+ PLIC_BASE_GET();
+
+ *pending = readl((void __iomem *)PENDING_REG(gd->arch.plic,
+ gd->arch.boot_hart));
+ *pending = !!(*pending & SEND_IPI_TO_HART(hart));
+
+ return 0;
+}
+
static const struct udevice_id andes_plic_ids[] = {
{ .compatible = "riscv,plic1", .data = RISCV_SYSCON_PLIC },
{ }
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c
index efbd3e23e7..e96137a50c 100644
--- a/arch/riscv/lib/bootm.c
+++ b/arch/riscv/lib/bootm.c
@@ -99,7 +99,7 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
#ifdef CONFIG_SMP
ret = smp_call_function(images->ep,
- (ulong)images->ft_addr, 0);
+ (ulong)images->ft_addr, 0, 0);
if (ret)
hang();
#endif
diff --git a/arch/riscv/lib/sbi_ipi.c b/arch/riscv/lib/sbi_ipi.c
index 170346da68..9a698ce74e 100644
--- a/arch/riscv/lib/sbi_ipi.c
+++ b/arch/riscv/lib/sbi_ipi.c
@@ -23,3 +23,14 @@ int riscv_clear_ipi(int hart)
return 0;
}
+
+int riscv_get_ipi(int hart, int *pending)
+{
+ /*
+ * The SBI does not support reading the IPI status. We always return 0
+ * to indicate that no IPI is pending.
+ */
+ *pending = 0;
+
+ return 0;
+}
diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c
index d24e0d585b..d7899d16d7 100644
--- a/arch/riscv/lib/sifive_clint.c
+++ b/arch/riscv/lib/sifive_clint.c
@@ -71,6 +71,15 @@ int riscv_clear_ipi(int hart)
return 0;
}
+int riscv_get_ipi(int hart, int *pending)
+{
+ CLINT_BASE_GET();
+
+ *pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
+
+ return 0;
+}
+
static const struct udevice_id sifive_clint_ids[] = {
{ .compatible = "riscv,clint0", .data = RISCV_SYSCON_CLINT },
{ }
diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c
index 705437862a..17adb35730 100644
--- a/arch/riscv/lib/smp.c
+++ b/arch/riscv/lib/smp.c
@@ -32,11 +32,23 @@ extern int riscv_send_ipi(int hart);
*/
extern int riscv_clear_ipi(int hart);
-static int send_ipi_many(struct ipi_data *ipi)
+/**
+ * riscv_get_ipi() - Get status of inter-processor interrupt (IPI)
+ *
+ * Platform code must provide this function.
+ *
+ * @hart: Hart ID of hart to be checked
+ * @pending: Pointer to variable with result of the check,
+ * 1 if IPI is pending, 0 otherwise
+ * @return 0 if OK, -ve on error
+ */
+extern int riscv_get_ipi(int hart, int *pending);
+
+static int send_ipi_many(struct ipi_data *ipi, int wait)
{
ofnode node, cpus;
u32 reg;
- int ret;
+ int ret, pending;
cpus = ofnode_path("/cpus");
if (!ofnode_valid(cpus)) {
@@ -79,6 +91,15 @@ static int send_ipi_many(struct ipi_data *ipi)
pr_err("Cannot send IPI to hart %d\n", reg);
return ret;
}
+
+ if (wait) {
+ pending = 1;
+ while (pending) {
+ ret = riscv_get_ipi(reg, &pending);
+ if (ret)
+ return ret;
+ }
+ }
}
return 0;
@@ -92,21 +113,25 @@ void handle_ipi(ulong hart)
if (hart >= CONFIG_NR_CPUS)
return;
+ __smp_mb();
+
+ smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
+ invalidate_icache_all();
+
+ /*
+ * Clear the IPI to acknowledge the request before jumping to the
+ * requested function.
+ */
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 smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait)
{
int ret = 0;
struct ipi_data ipi;
@@ -115,7 +140,7 @@ int smp_call_function(ulong addr, ulong arg0, ulong arg1)
ipi.arg0 = arg0;
ipi.arg1 = arg1;
- ret = send_ipi_many(&ipi);
+ ret = send_ipi_many(&ipi, wait);
return ret;
}
diff --git a/arch/riscv/lib/spl.c b/arch/riscv/lib/spl.c
index a544df0a2b..dc7577f751 100644
--- a/arch/riscv/lib/spl.c
+++ b/arch/riscv/lib/spl.c
@@ -41,7 +41,7 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
debug("image entry point: 0x%lX\n", spl_image->entry_point);
#ifdef CONFIG_SMP
- ret = smp_call_function(spl_image->entry_point, (ulong)fdt_blob, 0);
+ ret = smp_call_function(spl_image->entry_point, (ulong)fdt_blob, 0, 0);
if (ret)
hang();
#endif
diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S
index 474efe4df5..54f4ff6662 100644
--- a/arch/x86/cpu/start16.S
+++ b/arch/x86/cpu/start16.S
@@ -13,8 +13,6 @@
#include <asm/processor-flags.h>
#define BOOT_SEG 0xffff0000 /* linear segment of boot code */
-#define a32 .byte 0x67;
-#define o32 .byte 0x66;
.section .start16, "ax"
.code16
@@ -33,8 +31,8 @@ start16:
wbinvd
/* load the temporary Global Descriptor Table */
-o32 cs lidt idt_ptr
-o32 cs lgdt gdt_ptr
+data32 cs lidt idt_ptr
+data32 cs lgdt gdt_ptr
/* Now, we enter protected mode */
movl %cr0, %eax
@@ -46,10 +44,8 @@ o32 cs lgdt gdt_ptr
ff:
/* Finally restore BIST and jump to the 32-bit initialization code */
- movw $code32start, %ax
- movw %ax, %bp
movl %ecx, %eax
-o32 cs ljmp *(%bp)
+data32 cs ljmp *code32start
/* 48-bit far pointer */
code32start:
diff --git a/board/AndesTech/ax25-ae350/Kconfig b/board/AndesTech/ax25-ae350/Kconfig
index 5e682b679d..321dd0cb10 100644
--- a/board/AndesTech/ax25-ae350/Kconfig
+++ b/board/AndesTech/ax25-ae350/Kconfig
@@ -21,9 +21,18 @@ config ENV_SIZE
config ENV_OFFSET
default 0x140000 if ENV_IS_IN_SPI_FLASH
+config SPL_TEXT_BASE
+ default 0x800000
+
+config SPL_OPENSBI_LOAD_ADDR
+ default 0x01000000
+
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
select RISCV_NDS
+ select SUPPORT_SPL
imply SMP
+ imply SPL_RAM_SUPPORT
+ imply SPL_RAM_DEVICE
endif
diff --git a/board/AndesTech/ax25-ae350/MAINTAINERS b/board/AndesTech/ax25-ae350/MAINTAINERS
index feed5d1298..eebee167c3 100644
--- a/board/AndesTech/ax25-ae350/MAINTAINERS
+++ b/board/AndesTech/ax25-ae350/MAINTAINERS
@@ -7,3 +7,7 @@ F: configs/ae350_rv32_defconfig
F: configs/ae350_rv64_defconfig
F: configs/ae350_rv32_xip_defconfig
F: configs/ae350_rv64_xip_defconfig
+F: configs/ae350_rv32_spl_defconfig
+F: configs/ae350_rv64_spl_defconfig
+F: configs/ae350_rv32_spl_xip_defconfig
+F: configs/ae350_rv64_spl_xip_defconfig
diff --git a/board/AndesTech/ax25-ae350/ax25-ae350.c b/board/AndesTech/ax25-ae350/ax25-ae350.c
index b43eebb7a6..47e6929365 100644
--- a/board/AndesTech/ax25-ae350/ax25-ae350.c
+++ b/board/AndesTech/ax25-ae350/ax25-ae350.c
@@ -12,6 +12,7 @@
#include <faraday/ftsmc020.h>
#include <fdtdec.h>
#include <dm.h>
+#include <spl.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -29,29 +30,12 @@ int board_init(void)
int dram_init(void)
{
- unsigned long sdram_base = PHYS_SDRAM_0;
- unsigned long expected_size = PHYS_SDRAM_0_SIZE + PHYS_SDRAM_1_SIZE;
- unsigned long actual_size;
-
- actual_size = get_ram_size((void *)sdram_base, expected_size);
- gd->ram_size = actual_size;
-
- if (expected_size != actual_size) {
- printf("Warning: Only %lu of %lu MiB SDRAM is working\n",
- actual_size >> 20, expected_size >> 20);
- }
-
- return 0;
+ return fdtdec_setup_mem_size_base();
}
int dram_init_banksize(void)
{
- gd->bd->bi_dram[0].start = PHYS_SDRAM_0;
- gd->bd->bi_dram[0].size = PHYS_SDRAM_0_SIZE;
- gd->bd->bi_dram[1].start = PHYS_SDRAM_1;
- gd->bd->bi_dram[1].size = PHYS_SDRAM_1_SIZE;
-
- return 0;
+ return fdtdec_setup_memory_banksize();
}
#if defined(CONFIG_FTMAC100) && !defined(CONFIG_DM_ETH)
@@ -110,3 +94,29 @@ int board_early_init_f(void)
return 0;
}
#endif
+
+#ifdef CONFIG_SPL
+void board_boot_order(u32 *spl_boot_list)
+{
+ u8 i;
+ u32 boot_devices[] = {
+#ifdef CONFIG_SPL_RAM_SUPPORT
+ BOOT_DEVICE_RAM,
+#endif
+#ifdef CONFIG_SPL_MMC_SUPPORT
+ BOOT_DEVICE_MMC1,
+#endif
+ };
+
+ for (i = 0; i < ARRAY_SIZE(boot_devices); i++)
+ spl_boot_list[i] = boot_devices[i];
+}
+#endif
+
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+ /* boot using first FIT config */
+ return 0;
+}
+#endif
diff --git a/board/renesas/sh7752evb/sh7752evb.c b/board/renesas/sh7752evb/sh7752evb.c
index d675f65c12..203eecf3d6 100644
--- a/board/renesas/sh7752evb/sh7752evb.c
+++ b/board/renesas/sh7752evb/sh7752evb.c
@@ -94,7 +94,7 @@ static void set_mac_to_sh_giga_eth_register(int channel, char *mac_string)
unsigned char mac[6];
unsigned long val;
- eth_parse_enetaddr(mac_string, mac);
+ string_to_enetaddr(mac_string, mac);
if (!channel)
ether = GETHER0_MAC_BASE;
diff --git a/board/renesas/sh7753evb/sh7753evb.c b/board/renesas/sh7753evb/sh7753evb.c
index 43e13829f3..0b118b2f65 100644
--- a/board/renesas/sh7753evb/sh7753evb.c
+++ b/board/renesas/sh7753evb/sh7753evb.c
@@ -101,7 +101,7 @@ static void set_mac_to_sh_giga_eth_register(int channel, char *mac_string)
unsigned char mac[6];
unsigned long val;
- eth_parse_enetaddr(mac_string, mac);
+ string_to_enetaddr(mac_string, mac);
if (!channel)
ether = GETHER0_MAC_BASE;
diff --git a/board/renesas/sh7757lcr/sh7757lcr.c b/board/renesas/sh7757lcr/sh7757lcr.c
index 1d7ed9977e..e8d1fdd03f 100644
--- a/board/renesas/sh7757lcr/sh7757lcr.c
+++ b/board/renesas/sh7757lcr/sh7757lcr.c
@@ -141,7 +141,7 @@ static void set_mac_to_sh_eth_register(int channel, char *mac_string)
unsigned char mac[6];
unsigned long val;
- eth_parse_enetaddr(mac_string, mac);
+ string_to_enetaddr(mac_string, mac);
if (!channel)
ether = ETHER0_MAC_BASE;
@@ -160,7 +160,7 @@ static void set_mac_to_sh_giga_eth_register(int channel, char *mac_string)
unsigned char mac[6];
unsigned long val;
- eth_parse_enetaddr(mac_string, mac);
+ string_to_enetaddr(mac_string, mac);
if (!channel)
ether = GETHER0_MAC_BASE;
diff --git a/board/rockchip/evb_px30/MAINTAINERS b/board/rockchip/evb_px30/MAINTAINERS
index cf13f2419e..4dc060c501 100644
--- a/board/rockchip/evb_px30/MAINTAINERS
+++ b/board/rockchip/evb_px30/MAINTAINERS
@@ -4,3 +4,4 @@ S: Maintained
F: board/rockchip/evb_px30
F: include/configs/evb_px30.h
F: configs/evb-px30_defconfig
+F: configs/firefly-px30_defconfig
diff --git a/board/softing/vining_2000/vining_2000.c b/board/softing/vining_2000/vining_2000.c
index 78692e9240..ef914b13a1 100644
--- a/board/softing/vining_2000/vining_2000.c
+++ b/board/softing/vining_2000/vining_2000.c
@@ -72,42 +72,23 @@ int dram_init(void)
return 0;
}
-static iomux_v3_cfg_t const fec1_pads[] = {
- MX6_PAD_ENET1_MDC__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_ENET1_MDIO__ENET1_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII1_RD0__ENET1_RX_DATA_0 | MUX_PAD_CTRL(ENET_RX_PAD_CTRL),
- MX6_PAD_RGMII1_RD1__ENET1_RX_DATA_1 | MUX_PAD_CTRL(ENET_RX_PAD_CTRL),
- MX6_PAD_RGMII1_TD0__ENET1_TX_DATA_0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII1_TD1__ENET1_TX_DATA_1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII1_RX_CTL__ENET1_RX_EN | MUX_PAD_CTRL(ENET_RX_PAD_CTRL),
- MX6_PAD_RGMII1_TX_CTL__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL) |
- MUX_MODE_SION,
- /* LAN8720 PHY Reset */
- MX6_PAD_RGMII1_TD3__GPIO5_IO_9 | MUX_PAD_CTRL(NO_PAD_CTRL),
-};
-
static iomux_v3_cfg_t const pwm_led_pads[] = {
MX6_PAD_RGMII2_RD2__PWM2_OUT | MUX_PAD_CTRL(NO_PAD_CTRL), /* green */
MX6_PAD_RGMII2_TD2__PWM6_OUT | MUX_PAD_CTRL(NO_PAD_CTRL), /* red */
MX6_PAD_RGMII2_RD3__PWM1_OUT | MUX_PAD_CTRL(NO_PAD_CTRL), /* blue */
};
-#define PHY_RESET IMX_GPIO_NR(5, 9)
-
-int board_eth_init(bd_t *bis)
+static int board_net_init(void)
{
struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
- int ret;
unsigned char eth1addr[6];
+ int ret;
- /* just to get secound mac address */
+ /* just to get second mac address */
imx_get_mac_from_fuse(1, eth1addr);
if (!env_get("eth1addr") && is_valid_ethaddr(eth1addr))
eth_env_set_enetaddr("eth1addr", eth1addr);
- imx_iomux_v3_setup_multiple_pads(fec1_pads, ARRAY_SIZE(fec1_pads));
-
/*
* Generate phy reference clock via pin IOMUX ENET_REF_CLK1/2 by erasing
* ENET1/2_TX_CLK_DIR gpr1[14:13], so that reference clock is driven by
@@ -123,15 +104,7 @@ int board_eth_init(bd_t *bis)
if (ret)
goto eth_fail;
- /* reset phy */
- gpio_request(PHY_RESET, "PHY-reset");
- gpio_direction_output(PHY_RESET, 0);
- mdelay(16);
- gpio_set_value(PHY_RESET, 1);
- mdelay(1);
-
- ret = fecmxc_initialize_multi(bis, 0, CONFIG_FEC_MXC_PHYADDR,
- IMX_FEC_BASE);
+ ret = enable_fec_anatop_clock(1, ENET_50MHZ);
if (ret)
goto eth_fail;
@@ -139,7 +112,6 @@ int board_eth_init(bd_t *bis)
eth_fail:
printf("FEC MXC: %s:failed (%i)\n", __func__, ret);
- gpio_set_value(PHY_RESET, 0);
return ret;
}
@@ -254,6 +226,9 @@ int power_init_board(void)
if (ret < 0)
return ret;
+ set_ldo_voltage(LDO_ARM, 1175); /* Set VDDARM to 1.175V */
+ set_ldo_voltage(LDO_SOC, 1175); /* Set VDDSOC to 1.175V */
+
return 0;
}
@@ -424,7 +399,7 @@ int board_init(void)
setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
#endif
- return 0;
+ return board_net_init();
}
int checkboard(void)
@@ -433,3 +408,218 @@ int checkboard(void)
return 0;
}
+
+#define PCIE_PHY_PUP_REQ BIT(7)
+
+void board_preboot_os(void)
+{
+ struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
+ struct gpc *gpc_regs = (struct gpc *)GPC_BASE_ADDR;
+
+ /* Bring the PCI power domain up, so that old vendorkernel works. */
+ setbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_TEST_POWERDOWN);
+ setbits_le32(&iomuxc_regs->gpr[5], IOMUXC_GPR5_PCIE_BTNRST);
+ setbits_le32(&gpc_regs->cntr, PCIE_PHY_PUP_REQ);
+}
+
+#ifdef CONFIG_SPL_BUILD
+#include <linux/libfdt.h>
+#include <spl.h>
+#include <asm/arch/mx6-ddr.h>
+
+static struct fsl_esdhc_cfg usdhc_cfg = { USDHC4_BASE_ADDR };
+
+static iomux_v3_cfg_t const pcie_pads[] = {
+ MX6_PAD_NAND_DATA02__GPIO4_IO_6 | MUX_PAD_CTRL(GPIO_PAD_CTRL),
+};
+
+static iomux_v3_cfg_t const uart_pads[] = {
+ MX6_PAD_GPIO1_IO04__UART1_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
+ MX6_PAD_GPIO1_IO05__UART1_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
+};
+
+static iomux_v3_cfg_t const usdhc4_pads[] = {
+ MX6_PAD_SD4_CLK__USDHC4_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ MX6_PAD_SD4_CMD__USDHC4_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ MX6_PAD_SD4_DATA0__USDHC4_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ MX6_PAD_SD4_DATA1__USDHC4_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ MX6_PAD_SD4_DATA2__USDHC4_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ MX6_PAD_SD4_DATA3__USDHC4_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ MX6_PAD_SD4_DATA4__USDHC4_DATA4 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ MX6_PAD_SD4_DATA5__USDHC4_DATA5 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ MX6_PAD_SD4_DATA6__USDHC4_DATA6 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ MX6_PAD_SD4_DATA7__USDHC4_DATA7 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+};
+
+static void vining2000_spl_setup_iomux_pcie(void)
+{
+ imx_iomux_v3_setup_multiple_pads(pcie_pads, ARRAY_SIZE(pcie_pads));
+}
+
+static void vining2000_spl_setup_iomux_uart(void)
+{
+ imx_iomux_v3_setup_multiple_pads(uart_pads, ARRAY_SIZE(uart_pads));
+}
+
+int board_mmc_init(bd_t *bis)
+{
+ struct src *src_regs = (struct src *)SRC_BASE_ADDR;
+ u32 val;
+ u32 port;
+
+ val = readl(&src_regs->sbmr1);
+
+ if ((val & 0xc0) != 0x40) {
+ printf("Not boot from USDHC!\n");
+ return -EINVAL;
+ }
+
+ port = (val >> 11) & 0x3;
+ printf("port %d\n", port);
+ switch (port) {
+ case 3:
+ imx_iomux_v3_setup_multiple_pads(
+ usdhc4_pads, ARRAY_SIZE(usdhc4_pads));
+ usdhc_cfg.sdhc_clk = mxc_get_clock(MXC_ESDHC4_CLK);
+ usdhc_cfg.esdhc_base = USDHC4_BASE_ADDR;
+ break;
+ }
+
+ gd->arch.sdhc_clk = usdhc_cfg.sdhc_clk;
+ return fsl_esdhc_initialize(bis, &usdhc_cfg);
+}
+
+int board_mmc_getcd(struct mmc *mmc)
+{
+ return 1;
+}
+
+const struct mx6sx_iomux_ddr_regs mx6_ddr_ioregs = {
+ .dram_dqm0 = 0x00000028,
+ .dram_dqm1 = 0x00000028,
+ .dram_dqm2 = 0x00000028,
+ .dram_dqm3 = 0x00000028,
+ .dram_ras = 0x00000028,
+ .dram_cas = 0x00000028,
+ .dram_odt0 = 0x00000028,
+ .dram_odt1 = 0x00000028,
+ .dram_sdba2 = 0x00000000,
+ .dram_sdcke0 = 0x00003000,
+ .dram_sdcke1 = 0x00003000,
+ .dram_sdclk_0 = 0x00000030,
+ .dram_sdqs0 = 0x00000028,
+ .dram_sdqs1 = 0x00000028,
+ .dram_sdqs2 = 0x00000028,
+ .dram_sdqs3 = 0x00000028,
+ .dram_reset = 0x00000028,
+};
+
+const struct mx6sx_iomux_grp_regs mx6_grp_ioregs = {
+ .grp_addds = 0x00000028,
+ .grp_b0ds = 0x00000028,
+ .grp_b1ds = 0x00000028,
+ .grp_b2ds = 0x00000028,
+ .grp_b3ds = 0x00000028,
+ .grp_ctlds = 0x00000028,
+ .grp_ddr_type = 0x000c0000,
+ .grp_ddrmode = 0x00020000,
+ .grp_ddrmode_ctl = 0x00020000,
+ .grp_ddrpke = 0x00000000,
+};
+
+const struct mx6_mmdc_calibration mx6_mmcd_calib = {
+ .p0_mpwldectrl0 = 0x0022001C,
+ .p0_mpwldectrl1 = 0x001F001A,
+ .p0_mpdgctrl0 = 0x01380134,
+ .p0_mpdgctrl1 = 0x0124011C,
+ .p0_mprddlctl = 0x42404444,
+ .p0_mpwrdlctl = 0x36383C38,
+};
+
+static struct mx6_ddr3_cfg mem_ddr = {
+ .mem_speed = 1600,
+ .density = 4,
+ .width = 32,
+ .banks = 8,
+ .rowaddr = 15,
+ .coladdr = 10,
+ .pagesz = 2,
+ .trcd = 1391,
+ .trcmin = 4875,
+ .trasmin = 3500,
+};
+
+static void ccgr_init(void)
+{
+ struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+
+ writel(0xF000000F, &ccm->CCGR0); /* AIPS_TZ{1,2,3} */
+ writel(0x303C0000, &ccm->CCGR1); /* GPT, OCRAM */
+ writel(0x00FFFCC0, &ccm->CCGR2); /* IPMUX, I2C1, I2C3 */
+ writel(0x3F300030, &ccm->CCGR3); /* OCRAM, MMDC, ENET */
+ writel(0x0000C003, &ccm->CCGR4); /* PCI, PL301 */
+ writel(0x0F0330C3, &ccm->CCGR5); /* UART, ROM */
+ writel(0x00000F00, &ccm->CCGR6); /* SDHI4, EIM */
+}
+
+static void vining2000_spl_dram_init(void)
+{
+ struct mx6_ddr_sysinfo sysinfo = {
+ .dsize = mem_ddr.width / 32,
+ .cs_density = 24,
+ .ncs = 1,
+ .cs1_mirror = 0,
+ .rtt_wr = 1, /* RTT_wr = RZQ/4 */
+ .rtt_nom = 1, /* RTT_Nom = RZQ/4 */
+ .walat = 1, /* Write additional latency */
+ .ralat = 5, /* Read additional latency */
+ .mif3_mode = 3, /* Command prediction working mode */
+ .bi_on = 1, /* Bank interleaving enabled */
+ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */
+ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */
+ .ddr_type = DDR_TYPE_DDR3,
+ .refsel = 1, /* Refresh cycles at 32KHz */
+ .refr = 7, /* 8 refresh commands per refresh cycle */
+ };
+
+ mx6sx_dram_iocfg(mem_ddr.width, &mx6_ddr_ioregs, &mx6_grp_ioregs);
+ mx6_dram_cfg(&sysinfo, &mx6_mmcd_calib, &mem_ddr);
+
+ /* Perform DDR DRAM calibration */
+ udelay(100);
+ mmdc_do_write_level_calibration(&sysinfo);
+ mmdc_do_dqs_calibration(&sysinfo);
+}
+
+void board_init_f(ulong dummy)
+{
+ /* setup AIPS and disable watchdog */
+ arch_cpu_init();
+
+ ccgr_init();
+
+ /* iomux setup */
+ vining2000_spl_setup_iomux_pcie();
+ vining2000_spl_setup_iomux_uart();
+
+ /* setup GP timer */
+ timer_init();
+
+ /* reset the PCIe device */
+ gpio_set_value(IMX_GPIO_NR(4, 6), 1);
+ udelay(50);
+ gpio_set_value(IMX_GPIO_NR(4, 6), 0);
+
+ /* UART clocks enabled and gd valid - init serial console */
+ preloader_console_init();
+
+ /* DDR initialization */
+ vining2000_spl_dram_init();
+
+ /* Clear the BSS. */
+ memset(__bss_start, 0, __bss_end - __bss_start);
+
+ /* load/boot image from boot device */
+ board_init_r(NULL, 0);
+}
+#endif
diff --git a/board/solidrun/mx6cuboxi/MAINTAINERS b/board/solidrun/mx6cuboxi/MAINTAINERS
index 81f82bc9b5..bd098b479f 100644
--- a/board/solidrun/mx6cuboxi/MAINTAINERS
+++ b/board/solidrun/mx6cuboxi/MAINTAINERS
@@ -1,4 +1,5 @@
MX6CUBOXI BOARD
+M: Baruch Siach <baruch@tkos.co.il>
M: Fabio Estevam <fabio.estevam@nxp.com>
S: Maintained
F: board/solidrun/mx6cuboxi/
diff --git a/board/toradex/colibri_imx7/colibri_imx7.c b/board/toradex/colibri_imx7/colibri_imx7.c
index c001316591..b0914a9ead 100644
--- a/board/toradex/colibri_imx7/colibri_imx7.c
+++ b/board/toradex/colibri_imx7/colibri_imx7.c
@@ -333,6 +333,43 @@ int checkboard(void)
#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
int ft_board_setup(void *blob, bd_t *bd)
{
+#if defined(CONFIG_IMX_BOOTAUX) && defined(CONFIG_ARCH_FIXUP_FDT_MEMORY)
+ int up;
+
+ up = arch_auxiliary_core_check_up(0);
+ if (up) {
+ int ret;
+ int areas = 1;
+ u64 start[2], size[2];
+
+ /*
+ * Reserve 1MB of memory for M4 (1MiB is also the minimum
+ * alignment for Linux due to MMU section size restrictions).
+ */
+ start[0] = gd->bd->bi_dram[0].start;
+ size[0] = SZ_256M - SZ_1M;
+
+ /* If needed, create a second entry for memory beyond 256M */
+ if (gd->bd->bi_dram[0].size > SZ_256M) {
+ start[1] = gd->bd->bi_dram[0].start + SZ_256M;
+ size[1] = gd->bd->bi_dram[0].size - SZ_256M;
+ areas = 2;
+ }
+
+ ret = fdt_set_usable_memory(blob, start, size, areas);
+ if (ret) {
+ eprintf("Cannot set usable memory\n");
+ return ret;
+ }
+ } else {
+ int off;
+
+ off = fdt_node_offset_by_compatible(blob, -1,
+ "fsl,imx7d-rpmsg");
+ if (off > 0)
+ fdt_status_disabled(blob, off);
+ }
+#endif
#if defined(CONFIG_FDT_FIXUP_PARTITIONS)
static const struct node_info nodes[] = {
{ "fsl,imx7d-gpmi-nand", MTD_DEV_TYPE_NAND, }, /* NAND flash */
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 3b3722feb4..1e4cf146c5 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1473,8 +1473,22 @@ config CMD_NFS
config CMD_MII
bool "mii"
+ imply CMD_MDIO
help
- Enable MII utility commands.
+ If set, allows 802.3(clause 22) MII Management functions interface access
+ The management interface specified in Clause 22 provides
+ a simple, two signal, serial interface to connect a
+ Station Management entity and a managed PHY for providing access
+ to management parameters and services.
+ The interface is referred to as the MII management interface.
+
+config CMD_MDIO
+ bool "mdio"
+ depends on PHYLIB
+ help
+ If set, allows Enable 802.3(clause 45) MDIO interface registers access
+ The MDIO interface is orthogonal to the MII interface and extends
+ it by adding access to more registers through indirect addressing.
config CMD_PING
bool "ping"
@@ -1625,6 +1639,7 @@ config CMD_LED
config CMD_DATE
bool "date"
default y if DM_RTC
+ select LIB_DATE
help
Enable the 'date' command for getting/setting the time/date in RTC
devices.
@@ -1671,6 +1686,12 @@ config CMD_SOUND
sound init - set up sound system
sound play - play a sound
+config CMD_SYSBOOT
+ bool "sysboot"
+ select MENU
+ help
+ Boot image via local extlinux.conf file
+
config CMD_QFW
bool "qfw"
select QFW
diff --git a/cmd/Makefile b/cmd/Makefile
index 36b3ceca39..3ac7104546 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -89,9 +89,7 @@ obj-$(CONFIG_CMD_MEMORY) += mem.o
obj-$(CONFIG_CMD_IO) += io.o
obj-$(CONFIG_CMD_MFSL) += mfsl.o
obj-$(CONFIG_CMD_MII) += mii.o
-ifdef CONFIG_PHYLIB
-obj-$(CONFIG_CMD_MII) += mdio.o
-endif
+obj-$(CONFIG_CMD_MDIO) += mdio.o
obj-$(CONFIG_CMD_MISC) += misc.o
obj-$(CONFIG_CMD_MMC) += mmc.o
obj-$(CONFIG_MP) += mp.o
@@ -111,7 +109,7 @@ ifdef CONFIG_PCI
obj-$(CONFIG_CMD_PCI) += pci.o
endif
obj-$(CONFIG_CMD_PINMUX) += pinmux.o
-obj-$(CONFIG_CMD_PXE) += pxe.o
+obj-$(CONFIG_CMD_PXE) += pxe.o pxe_utils.o
obj-$(CONFIG_CMD_WOL) += wol.o
obj-$(CONFIG_CMD_QFW) += qfw.o
obj-$(CONFIG_CMD_READ) += read.o
@@ -130,6 +128,7 @@ obj-$(CONFIG_CMD_SETEXPR) += setexpr.o
obj-$(CONFIG_CMD_SPI) += spi.o
obj-$(CONFIG_CMD_STRINGS) += strings.o
obj-$(CONFIG_CMD_SMC) += smccc.o
+obj-$(CONFIG_CMD_SYSBOOT) += sysboot.o pxe_utils.o
obj-$(CONFIG_CMD_TERMINAL) += terminal.o
obj-$(CONFIG_CMD_TIME) += time.o
obj-$(CONFIG_CMD_TRACE) += trace.o
diff --git a/cmd/ethsw.c b/cmd/ethsw.c
index 8846805799..8d271ce1f3 100644
--- a/cmd/ethsw.c
+++ b/cmd/ethsw.c
@@ -864,7 +864,7 @@ static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
return 0;
}
- eth_parse_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr);
+ string_to_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr);
if (is_broadcast_ethaddr(parsed_cmd->ethaddr)) {
memset(parsed_cmd->ethaddr, 0xFF, sizeof(parsed_cmd->ethaddr));
diff --git a/cmd/nvedit.c b/cmd/nvedit.c
index b5da375913..81d94cd193 100644
--- a/cmd/nvedit.c
+++ b/cmd/nvedit.c
@@ -361,7 +361,7 @@ ulong env_get_hex(const char *varname, ulong default_val)
int eth_env_get_enetaddr(const char *name, uint8_t *enetaddr)
{
- eth_parse_enetaddr(env_get(name), enetaddr);
+ string_to_enetaddr(env_get(name), enetaddr);
return is_valid_ethaddr(enetaddr);
}
@@ -682,6 +682,23 @@ char *env_get(const char *name)
}
/*
+ * Like env_get, but prints an error if envvar isn't defined in the
+ * environment. It always returns what env_get does, so it can be used in
+ * place of env_get without changing error handling otherwise.
+ */
+char *from_env(const char *envvar)
+{
+ char *ret;
+
+ ret = env_get(envvar);
+
+ if (!ret)
+ printf("missing environment variable: %s\n", envvar);
+
+ return ret;
+}
+
+/*
* Look up variable from environment for restricted C runtime env.
*/
int env_get_f(const char *name, char *buf, unsigned len)
diff --git a/cmd/pxe.c b/cmd/pxe.c
index 768e50aba6..73f1b4fbd3 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -6,23 +6,10 @@
#include <common.h>
#include <command.h>
-#include <env.h>
-#include <malloc.h>
-#include <mapmem.h>
-#include <lcd.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <errno.h>
-#include <linux/list.h>
-#include <fs.h>
-#include <splash.h>
-#include <asm/io.h>
-#include "menu.h"
-#include "cli.h"
-
-#define MAX_TFTP_PATH_LEN 127
+#include "pxe_utils.h"
+#ifdef CONFIG_CMD_NET
const char *pxe_default_paths[] = {
#ifdef CONFIG_SYS_SOC
#ifdef CONFIG_SYS_BOARD
@@ -35,102 +22,6 @@ const char *pxe_default_paths[] = {
NULL
};
-static bool is_pxe;
-
-/*
- * Like env_get, but prints an error if envvar isn't defined in the
- * environment. It always returns what env_get does, so it can be used in
- * place of env_get without changing error handling otherwise.
- */
-static char *from_env(const char *envvar)
-{
- char *ret;
-
- ret = env_get(envvar);
-
- if (!ret)
- printf("missing environment variable: %s\n", envvar);
-
- return ret;
-}
-
-#ifdef CONFIG_CMD_NET
-/*
- * Convert an ethaddr from the environment to the format used by pxelinux
- * filenames based on mac addresses. Convert's ':' to '-', and adds "01-" to
- * the beginning of the ethernet address to indicate a hardware type of
- * Ethernet. Also converts uppercase hex characters into lowercase, to match
- * pxelinux's behavior.
- *
- * Returns 1 for success, -ENOENT if 'ethaddr' is undefined in the
- * environment, or some other value < 0 on error.
- */
-static int format_mac_pxe(char *outbuf, size_t outbuf_len)
-{
- uchar ethaddr[6];
-
- if (outbuf_len < 21) {
- printf("outbuf is too small (%zd < 21)\n", outbuf_len);
-
- return -EINVAL;
- }
-
- if (!eth_env_get_enetaddr_by_index("eth", eth_get_dev_index(), ethaddr))
- return -ENOENT;
-
- sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x",
- ethaddr[0], ethaddr[1], ethaddr[2],
- ethaddr[3], ethaddr[4], ethaddr[5]);
-
- return 1;
-}
-#endif
-
-/*
- * Returns the directory the file specified in the bootfile env variable is
- * in. If bootfile isn't defined in the environment, return NULL, which should
- * be interpreted as "don't prepend anything to paths".
- */
-static int get_bootfile_path(const char *file_path, char *bootfile_path,
- size_t bootfile_path_size)
-{
- char *bootfile, *last_slash;
- size_t path_len = 0;
-
- /* Only syslinux allows absolute paths */
- if (file_path[0] == '/' && !is_pxe)
- goto ret;
-
- bootfile = from_env("bootfile");
-
- if (!bootfile)
- goto ret;
-
- last_slash = strrchr(bootfile, '/');
-
- if (last_slash == NULL)
- goto ret;
-
- path_len = (last_slash - bootfile) + 1;
-
- if (bootfile_path_size < path_len) {
- printf("bootfile_path too small. (%zd < %zd)\n",
- bootfile_path_size, path_len);
-
- return -1;
- }
-
- strncpy(bootfile_path, bootfile, path_len);
-
- ret:
- bootfile_path[path_len] = '\0';
-
- return 1;
-}
-
-static int (*do_getfile)(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr);
-
-#ifdef CONFIG_CMD_NET
static int do_get_tftp(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
{
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
@@ -143,156 +34,6 @@ static int do_get_tftp(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
return 1;
}
-#endif
-
-static char *fs_argv[5];
-
-static int do_get_ext2(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
-{
-#ifdef CONFIG_CMD_EXT2
- fs_argv[0] = "ext2load";
- fs_argv[3] = file_addr;
- fs_argv[4] = (void *)file_path;
-
- if (!do_ext2load(cmdtp, 0, 5, fs_argv))
- return 1;
-#endif
- return -ENOENT;
-}
-
-static int do_get_fat(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
-{
-#ifdef CONFIG_CMD_FAT
- fs_argv[0] = "fatload";
- fs_argv[3] = file_addr;
- fs_argv[4] = (void *)file_path;
-
- if (!do_fat_fsload(cmdtp, 0, 5, fs_argv))
- return 1;
-#endif
- return -ENOENT;
-}
-
-static int do_get_any(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
-{
-#ifdef CONFIG_CMD_FS_GENERIC
- fs_argv[0] = "load";
- fs_argv[3] = file_addr;
- fs_argv[4] = (void *)file_path;
-
- if (!do_load(cmdtp, 0, 5, fs_argv, FS_TYPE_ANY))
- return 1;
-#endif
- return -ENOENT;
-}
-
-/*
- * As in pxelinux, paths to files referenced from files we retrieve are
- * relative to the location of bootfile. get_relfile takes such a path and
- * joins it with the bootfile path to get the full path to the target file. If
- * the bootfile path is NULL, we use file_path as is.
- *
- * Returns 1 for success, or < 0 on error.
- */
-static int get_relfile(cmd_tbl_t *cmdtp, const char *file_path,
- unsigned long file_addr)
-{
- size_t path_len;
- char relfile[MAX_TFTP_PATH_LEN+1];
- char addr_buf[18];
- int err;
-
- err = get_bootfile_path(file_path, relfile, sizeof(relfile));
-
- if (err < 0)
- return err;
-
- path_len = strlen(file_path);
- path_len += strlen(relfile);
-
- if (path_len > MAX_TFTP_PATH_LEN) {
- printf("Base path too long (%s%s)\n",
- relfile,
- file_path);
-
- return -ENAMETOOLONG;
- }
-
- strcat(relfile, file_path);
-
- printf("Retrieving file: %s\n", relfile);
-
- sprintf(addr_buf, "%lx", file_addr);
-
- return do_getfile(cmdtp, relfile, addr_buf);
-}
-
-/*
- * Retrieve the file at 'file_path' to the locate given by 'file_addr'. If
- * 'bootfile' was specified in the environment, the path to bootfile will be
- * prepended to 'file_path' and the resulting path will be used.
- *
- * Returns 1 on success, or < 0 for error.
- */
-static int get_pxe_file(cmd_tbl_t *cmdtp, const char *file_path,
- unsigned long file_addr)
-{
- unsigned long config_file_size;
- char *tftp_filesize;
- int err;
- char *buf;
-
- err = get_relfile(cmdtp, file_path, file_addr);
-
- if (err < 0)
- return err;
-
- /*
- * the file comes without a NUL byte at the end, so find out its size
- * and add the NUL byte.
- */
- tftp_filesize = from_env("filesize");
-
- if (!tftp_filesize)
- return -ENOENT;
-
- if (strict_strtoul(tftp_filesize, 16, &config_file_size) < 0)
- return -EINVAL;
-
- buf = map_sysmem(file_addr + config_file_size, 1);
- *buf = '\0';
- unmap_sysmem(buf);
-
- return 1;
-}
-
-#ifdef CONFIG_CMD_NET
-
-#define PXELINUX_DIR "pxelinux.cfg/"
-
-/*
- * Retrieves a file in the 'pxelinux.cfg' folder. Since this uses get_pxe_file
- * to do the hard work, the location of the 'pxelinux.cfg' folder is generated
- * from the bootfile path, as described above.
- *
- * Returns 1 on success or < 0 on error.
- */
-static int get_pxelinux_path(cmd_tbl_t *cmdtp, const char *file,
- unsigned long pxefile_addr_r)
-{
- size_t base_len = strlen(PXELINUX_DIR);
- char path[MAX_TFTP_PATH_LEN+1];
-
- if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) {
- printf("path (%s%s) too long, skipping\n",
- PXELINUX_DIR, file);
- return -ENAMETOOLONG;
- }
-
- sprintf(path, PXELINUX_DIR "%s", file);
-
- return get_pxe_file(cmdtp, path, pxefile_addr_r);
-}
/*
* Looks for a pxe file with a name based on the pxeuuid environment variable.
@@ -355,7 +96,6 @@ static int pxe_ipaddr_paths(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
return -ENOENT;
}
-
/*
* Entry point for the 'pxe get' command.
* This Follows pxelinux's rules to download a config file from a tftp server.
@@ -388,7 +128,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return 1;
err = strict_strtoul(pxefile_addr_str, 16,
- (unsigned long *)&pxefile_addr_r);
+ (unsigned long *)&pxefile_addr_r);
if (err < 0)
return 1;
@@ -417,1224 +157,8 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return 1;
}
-#endif
-
-/*
- * Wrapper to make it easier to store the file at file_path in the location
- * specified by envaddr_name. file_path will be joined to the bootfile path,
- * if any is specified.
- *
- * Returns 1 on success or < 0 on error.
- */
-static int get_relfile_envaddr(cmd_tbl_t *cmdtp, const char *file_path, const char *envaddr_name)
-{
- unsigned long file_addr;
- char *envaddr;
-
- envaddr = from_env(envaddr_name);
-
- if (!envaddr)
- return -ENOENT;
-
- if (strict_strtoul(envaddr, 16, &file_addr) < 0)
- return -EINVAL;
-
- return get_relfile(cmdtp, file_path, file_addr);
-}
-
-/*
- * A note on the pxe file parser.
- *
- * We're parsing files that use syslinux grammar, which has a few quirks.
- * String literals must be recognized based on context - there is no
- * quoting or escaping support. There's also nothing to explicitly indicate
- * when a label section completes. We deal with that by ending a label
- * section whenever we see a line that doesn't include.
- *
- * As with the syslinux family, this same file format could be reused in the
- * future for non pxe purposes. The only action it takes during parsing that
- * would throw this off is handling of include files. It assumes we're using
- * pxe, and does a tftp download of a file listed as an include file in the
- * middle of the parsing operation. That could be handled by refactoring it to
- * take a 'include file getter' function.
- */
-
-/*
- * Describes a single label given in a pxe file.
- *
- * Create these with the 'label_create' function given below.
- *
- * name - the name of the menu as given on the 'menu label' line.
- * kernel - the path to the kernel file to use for this label.
- * append - kernel command line to use when booting this label
- * initrd - path to the initrd to use for this label.
- * attempted - 0 if we haven't tried to boot this label, 1 if we have.
- * localboot - 1 if this label specified 'localboot', 0 otherwise.
- * list - lets these form a list, which a pxe_menu struct will hold.
- */
-struct pxe_label {
- char num[4];
- char *name;
- char *menu;
- char *kernel;
- char *config;
- char *append;
- char *initrd;
- char *fdt;
- char *fdtdir;
- int ipappend;
- int attempted;
- int localboot;
- int localboot_val;
- struct list_head list;
-};
-
-/*
- * Describes a pxe menu as given via pxe files.
- *
- * title - the name of the menu as given by a 'menu title' line.
- * default_label - the name of the default label, if any.
- * bmp - the bmp file name which is displayed in background
- * timeout - time in tenths of a second to wait for a user key-press before
- * booting the default label.
- * prompt - if 0, don't prompt for a choice unless the timeout period is
- * interrupted. If 1, always prompt for a choice regardless of
- * timeout.
- * labels - a list of labels defined for the menu.
- */
-struct pxe_menu {
- char *title;
- char *default_label;
- char *bmp;
- int timeout;
- int prompt;
- struct list_head labels;
-};
-
-/*
- * Allocates memory for and initializes a pxe_label. This uses malloc, so the
- * result must be free()'d to reclaim the memory.
- *
- * Returns NULL if malloc fails.
- */
-static struct pxe_label *label_create(void)
-{
- struct pxe_label *label;
-
- label = malloc(sizeof(struct pxe_label));
-
- if (!label)
- return NULL;
-
- memset(label, 0, sizeof(struct pxe_label));
-
- return label;
-}
-
-/*
- * Free the memory used by a pxe_label, including that used by its name,
- * kernel, append and initrd members, if they're non NULL.
- *
- * So - be sure to only use dynamically allocated memory for the members of
- * the pxe_label struct, unless you want to clean it up first. These are
- * currently only created by the pxe file parsing code.
- */
-static void label_destroy(struct pxe_label *label)
-{
- if (label->name)
- free(label->name);
-
- if (label->kernel)
- free(label->kernel);
-
- if (label->config)
- free(label->config);
-
- if (label->append)
- free(label->append);
-
- if (label->initrd)
- free(label->initrd);
-
- if (label->fdt)
- free(label->fdt);
-
- if (label->fdtdir)
- free(label->fdtdir);
-
- free(label);
-}
-
-/*
- * Print a label and its string members if they're defined.
- *
- * This is passed as a callback to the menu code for displaying each
- * menu entry.
- */
-static void label_print(void *data)
-{
- struct pxe_label *label = data;
- const char *c = label->menu ? label->menu : label->name;
-
- printf("%s:\t%s\n", label->num, c);
-}
-
-/*
- * Boot a label that specified 'localboot'. This requires that the 'localcmd'
- * environment variable is defined. Its contents will be executed as U-Boot
- * command. If the label specified an 'append' line, its contents will be
- * used to overwrite the contents of the 'bootargs' environment variable prior
- * to running 'localcmd'.
- *
- * Returns 1 on success or < 0 on error.
- */
-static int label_localboot(struct pxe_label *label)
-{
- char *localcmd;
-
- localcmd = from_env("localcmd");
-
- if (!localcmd)
- return -ENOENT;
-
- if (label->append) {
- char bootargs[CONFIG_SYS_CBSIZE];
-
- cli_simple_process_macros(label->append, bootargs);
- env_set("bootargs", bootargs);
- }
-
- debug("running: %s\n", localcmd);
-
- return run_command_list(localcmd, strlen(localcmd), 0);
-}
-
-/*
- * Boot according to the contents of a pxe_label.
- *
- * If we can't boot for any reason, we return. A successful boot never
- * returns.
- *
- * The kernel will be stored in the location given by the 'kernel_addr_r'
- * environment variable.
- *
- * If the label specifies an initrd file, it will be stored in the location
- * given by the 'ramdisk_addr_r' environment variable.
- *
- * If the label specifies an 'append' line, its contents will overwrite that
- * of the 'bootargs' environment variable.
- */
-static int label_boot(cmd_tbl_t *cmdtp, struct pxe_label *label)
-{
- char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
- char initrd_str[28];
- char mac_str[29] = "";
- char ip_str[68] = "";
- char *fit_addr = NULL;
- int bootm_argc = 2;
- int len = 0;
- ulong kernel_addr;
- void *buf;
-
- label_print(label);
-
- label->attempted = 1;
-
- if (label->localboot) {
- if (label->localboot_val >= 0)
- label_localboot(label);
- return 0;
- }
-
- if (label->kernel == NULL) {
- printf("No kernel given, skipping %s\n",
- label->name);
- return 1;
- }
-
- if (label->initrd) {
- if (get_relfile_envaddr(cmdtp, label->initrd, "ramdisk_addr_r") < 0) {
- printf("Skipping %s for failure retrieving initrd\n",
- label->name);
- return 1;
- }
-
- bootm_argv[2] = initrd_str;
- strncpy(bootm_argv[2], env_get("ramdisk_addr_r"), 18);
- strcat(bootm_argv[2], ":");
- strncat(bootm_argv[2], env_get("filesize"), 9);
- bootm_argc = 3;
- }
-
- if (get_relfile_envaddr(cmdtp, label->kernel, "kernel_addr_r") < 0) {
- printf("Skipping %s for failure retrieving kernel\n",
- label->name);
- return 1;
- }
-
- if (label->ipappend & 0x1) {
- sprintf(ip_str, " ip=%s:%s:%s:%s",
- env_get("ipaddr"), env_get("serverip"),
- env_get("gatewayip"), env_get("netmask"));
- }
-
-#ifdef CONFIG_CMD_NET
- if (label->ipappend & 0x2) {
- int err;
- strcpy(mac_str, " BOOTIF=");
- err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8);
- if (err < 0)
- mac_str[0] = '\0';
- }
-#endif
-
- if ((label->ipappend & 0x3) || label->append) {
- char bootargs[CONFIG_SYS_CBSIZE] = "";
- char finalbootargs[CONFIG_SYS_CBSIZE];
-
- if (strlen(label->append ?: "") +
- strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) {
- printf("bootarg overflow %zd+%zd+%zd+1 > %zd\n",
- strlen(label->append ?: ""),
- strlen(ip_str), strlen(mac_str),
- sizeof(bootargs));
- return 1;
- } else {
- if (label->append)
- strncpy(bootargs, label->append,
- sizeof(bootargs));
- strcat(bootargs, ip_str);
- strcat(bootargs, mac_str);
-
- cli_simple_process_macros(bootargs, finalbootargs);
- env_set("bootargs", finalbootargs);
- printf("append: %s\n", finalbootargs);
- }
- }
-
- bootm_argv[1] = env_get("kernel_addr_r");
- /* for FIT, append the configuration identifier */
- if (label->config) {
- int len = strlen(bootm_argv[1]) + strlen(label->config) + 1;
-
- fit_addr = malloc(len);
- if (!fit_addr) {
- printf("malloc fail (FIT address)\n");
- return 1;
- }
- snprintf(fit_addr, len, "%s%s", bootm_argv[1], label->config);
- bootm_argv[1] = fit_addr;
- }
-
- /*
- * fdt usage is optional:
- * It handles the following scenarios. All scenarios are exclusive
- *
- * Scenario 1: If fdt_addr_r specified and "fdt" label is defined in
- * pxe file, retrieve fdt blob from server. Pass fdt_addr_r to bootm,
- * and adjust argc appropriately.
- *
- * Scenario 2: If there is an fdt_addr specified, pass it along to
- * bootm, and adjust argc appropriately.
- *
- * Scenario 3: fdt blob is not available.
- */
- bootm_argv[3] = env_get("fdt_addr_r");
-
- /* if fdt label is defined then get fdt from server */
- if (bootm_argv[3]) {
- char *fdtfile = NULL;
- char *fdtfilefree = NULL;
-
- if (label->fdt) {
- fdtfile = label->fdt;
- } else if (label->fdtdir) {
- char *f1, *f2, *f3, *f4, *slash;
-
- f1 = env_get("fdtfile");
- if (f1) {
- f2 = "";
- f3 = "";
- f4 = "";
- } else {
- /*
- * For complex cases where this code doesn't
- * generate the correct filename, the board
- * code should set $fdtfile during early boot,
- * or the boot scripts should set $fdtfile
- * before invoking "pxe" or "sysboot".
- */
- f1 = env_get("soc");
- f2 = "-";
- f3 = env_get("board");
- f4 = ".dtb";
- }
-
- len = strlen(label->fdtdir);
- if (!len)
- slash = "./";
- else if (label->fdtdir[len - 1] != '/')
- slash = "/";
- else
- slash = "";
-
- len = strlen(label->fdtdir) + strlen(slash) +
- strlen(f1) + strlen(f2) + strlen(f3) +
- strlen(f4) + 1;
- fdtfilefree = malloc(len);
- if (!fdtfilefree) {
- printf("malloc fail (FDT filename)\n");
- goto cleanup;
- }
-
- snprintf(fdtfilefree, len, "%s%s%s%s%s%s",
- label->fdtdir, slash, f1, f2, f3, f4);
- fdtfile = fdtfilefree;
- }
-
- if (fdtfile) {
- int err = get_relfile_envaddr(cmdtp, fdtfile, "fdt_addr_r");
- free(fdtfilefree);
- if (err < 0) {
- printf("Skipping %s for failure retrieving fdt\n",
- label->name);
- goto cleanup;
- }
- } else {
- bootm_argv[3] = NULL;
- }
- }
-
- if (!bootm_argv[3])
- bootm_argv[3] = env_get("fdt_addr");
-
- if (bootm_argv[3]) {
- if (!bootm_argv[2])
- bootm_argv[2] = "-";
- bootm_argc = 4;
- }
-
- kernel_addr = genimg_get_kernel_addr(bootm_argv[1]);
- buf = map_sysmem(kernel_addr, 0);
- /* Try bootm for legacy and FIT format image */
- if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID)
- do_bootm(cmdtp, 0, bootm_argc, bootm_argv);
-#ifdef CONFIG_CMD_BOOTI
- /* Try booting an AArch64 Linux kernel image */
- else
- do_booti(cmdtp, 0, bootm_argc, bootm_argv);
-#elif defined(CONFIG_CMD_BOOTZ)
- /* Try booting a Image */
- else
- do_bootz(cmdtp, 0, bootm_argc, bootm_argv);
-#endif
- unmap_sysmem(buf);
-
-cleanup:
- if (fit_addr)
- free(fit_addr);
- return 1;
-}
-
-/*
- * Tokens for the pxe file parser.
- */
-enum token_type {
- T_EOL,
- T_STRING,
- T_EOF,
- T_MENU,
- T_TITLE,
- T_TIMEOUT,
- T_LABEL,
- T_KERNEL,
- T_LINUX,
- T_APPEND,
- T_INITRD,
- T_LOCALBOOT,
- T_DEFAULT,
- T_PROMPT,
- T_INCLUDE,
- T_FDT,
- T_FDTDIR,
- T_ONTIMEOUT,
- T_IPAPPEND,
- T_BACKGROUND,
- T_INVALID
-};
-
-/*
- * A token - given by a value and a type.
- */
-struct token {
- char *val;
- enum token_type type;
-};
-
-/*
- * Keywords recognized.
- */
-static const struct token keywords[] = {
- {"menu", T_MENU},
- {"title", T_TITLE},
- {"timeout", T_TIMEOUT},
- {"default", T_DEFAULT},
- {"prompt", T_PROMPT},
- {"label", T_LABEL},
- {"kernel", T_KERNEL},
- {"linux", T_LINUX},
- {"localboot", T_LOCALBOOT},
- {"append", T_APPEND},
- {"initrd", T_INITRD},
- {"include", T_INCLUDE},
- {"devicetree", T_FDT},
- {"fdt", T_FDT},
- {"devicetreedir", T_FDTDIR},
- {"fdtdir", T_FDTDIR},
- {"ontimeout", T_ONTIMEOUT,},
- {"ipappend", T_IPAPPEND,},
- {"background", T_BACKGROUND,},
- {NULL, T_INVALID}
-};
-
-/*
- * Since pxe(linux) files don't have a token to identify the start of a
- * literal, we have to keep track of when we're in a state where a literal is
- * expected vs when we're in a state a keyword is expected.
- */
-enum lex_state {
- L_NORMAL = 0,
- L_KEYWORD,
- L_SLITERAL
-};
-
-/*
- * get_string retrieves a string from *p and stores it as a token in
- * *t.
- *
- * get_string used for scanning both string literals and keywords.
- *
- * Characters from *p are copied into t-val until a character equal to
- * delim is found, or a NUL byte is reached. If delim has the special value of
- * ' ', any whitespace character will be used as a delimiter.
- *
- * If lower is unequal to 0, uppercase characters will be converted to
- * lowercase in the result. This is useful to make keywords case
- * insensitive.
- *
- * The location of *p is updated to point to the first character after the end
- * of the token - the ending delimiter.
- *
- * On success, the new value of t->val is returned. Memory for t->val is
- * allocated using malloc and must be free()'d to reclaim it. If insufficient
- * memory is available, NULL is returned.
- */
-static char *get_string(char **p, struct token *t, char delim, int lower)
-{
- char *b, *e;
- size_t len, i;
-
- /*
- * b and e both start at the beginning of the input stream.
- *
- * e is incremented until we find the ending delimiter, or a NUL byte
- * is reached. Then, we take e - b to find the length of the token.
- */
- b = e = *p;
-
- while (*e) {
- if ((delim == ' ' && isspace(*e)) || delim == *e)
- break;
- e++;
- }
-
- len = e - b;
-
- /*
- * Allocate memory to hold the string, and copy it in, converting
- * characters to lowercase if lower is != 0.
- */
- t->val = malloc(len + 1);
- if (!t->val)
- return NULL;
-
- for (i = 0; i < len; i++, b++) {
- if (lower)
- t->val[i] = tolower(*b);
- else
- t->val[i] = *b;
- }
-
- t->val[len] = '\0';
-
- /*
- * Update *p so the caller knows where to continue scanning.
- */
- *p = e;
-
- t->type = T_STRING;
-
- return t->val;
-}
-
-/*
- * Populate a keyword token with a type and value.
- */
-static void get_keyword(struct token *t)
-{
- int i;
-
- for (i = 0; keywords[i].val; i++) {
- if (!strcmp(t->val, keywords[i].val)) {
- t->type = keywords[i].type;
- break;
- }
- }
-}
-
-/*
- * Get the next token. We have to keep track of which state we're in to know
- * if we're looking to get a string literal or a keyword.
- *
- * *p is updated to point at the first character after the current token.
- */
-static void get_token(char **p, struct token *t, enum lex_state state)
-{
- char *c = *p;
-
- t->type = T_INVALID;
-
- /* eat non EOL whitespace */
- while (isblank(*c))
- c++;
-
- /*
- * eat comments. note that string literals can't begin with #, but
- * can contain a # after their first character.
- */
- if (*c == '#') {
- while (*c && *c != '\n')
- c++;
- }
-
- if (*c == '\n') {
- t->type = T_EOL;
- c++;
- } else if (*c == '\0') {
- t->type = T_EOF;
- c++;
- } else if (state == L_SLITERAL) {
- get_string(&c, t, '\n', 0);
- } else if (state == L_KEYWORD) {
- /*
- * when we expect a keyword, we first get the next string
- * token delimited by whitespace, and then check if it
- * matches a keyword in our keyword list. if it does, it's
- * converted to a keyword token of the appropriate type, and
- * if not, it remains a string token.
- */
- get_string(&c, t, ' ', 1);
- get_keyword(t);
- }
-
- *p = c;
-}
-
-/*
- * Increment *c until we get to the end of the current line, or EOF.
- */
-static void eol_or_eof(char **c)
-{
- while (**c && **c != '\n')
- (*c)++;
-}
-
-/*
- * All of these parse_* functions share some common behavior.
- *
- * They finish with *c pointing after the token they parse, and return 1 on
- * success, or < 0 on error.
- */
-
-/*
- * Parse a string literal and store a pointer it at *dst. String literals
- * terminate at the end of the line.
- */
-static int parse_sliteral(char **c, char **dst)
-{
- struct token t;
- char *s = *c;
-
- get_token(c, &t, L_SLITERAL);
-
- if (t.type != T_STRING) {
- printf("Expected string literal: %.*s\n", (int)(*c - s), s);
- return -EINVAL;
- }
-
- *dst = t.val;
-
- return 1;
-}
-
-/*
- * Parse a base 10 (unsigned) integer and store it at *dst.
- */
-static int parse_integer(char **c, int *dst)
-{
- struct token t;
- char *s = *c;
-
- get_token(c, &t, L_SLITERAL);
-
- if (t.type != T_STRING) {
- printf("Expected string: %.*s\n", (int)(*c - s), s);
- return -EINVAL;
- }
-
- *dst = simple_strtol(t.val, NULL, 10);
-
- free(t.val);
-
- return 1;
-}
-
-static int parse_pxefile_top(cmd_tbl_t *cmdtp, char *p, unsigned long base,
- struct pxe_menu *cfg, int nest_level);
-
-/*
- * Parse an include statement, and retrieve and parse the file it mentions.
- *
- * base should point to a location where it's safe to store the file, and
- * nest_level should indicate how many nested includes have occurred. For this
- * include, nest_level has already been incremented and doesn't need to be
- * incremented here.
- */
-static int handle_include(cmd_tbl_t *cmdtp, char **c, unsigned long base,
- struct pxe_menu *cfg, int nest_level)
-{
- char *include_path;
- char *s = *c;
- int err;
- char *buf;
- int ret;
-
- err = parse_sliteral(c, &include_path);
-
- if (err < 0) {
- printf("Expected include path: %.*s\n",
- (int)(*c - s), s);
- return err;
- }
-
- err = get_pxe_file(cmdtp, include_path, base);
-
- if (err < 0) {
- printf("Couldn't retrieve %s\n", include_path);
- return err;
- }
-
- buf = map_sysmem(base, 0);
- ret = parse_pxefile_top(cmdtp, buf, base, cfg, nest_level);
- unmap_sysmem(buf);
-
- return ret;
-}
-
-/*
- * Parse lines that begin with 'menu'.
- *
- * base and nest are provided to handle the 'menu include' case.
- *
- * base should point to a location where it's safe to store the included file.
- *
- * nest_level should be 1 when parsing the top level pxe file, 2 when parsing
- * a file it includes, 3 when parsing a file included by that file, and so on.
- */
-static int parse_menu(cmd_tbl_t *cmdtp, char **c, struct pxe_menu *cfg,
- unsigned long base, int nest_level)
-{
- struct token t;
- char *s = *c;
- int err = 0;
-
- get_token(c, &t, L_KEYWORD);
-
- switch (t.type) {
- case T_TITLE:
- err = parse_sliteral(c, &cfg->title);
-
- break;
-
- case T_INCLUDE:
- err = handle_include(cmdtp, c, base, cfg,
- nest_level + 1);
- break;
-
- case T_BACKGROUND:
- err = parse_sliteral(c, &cfg->bmp);
- break;
-
- default:
- printf("Ignoring malformed menu command: %.*s\n",
- (int)(*c - s), s);
- }
-
- if (err < 0)
- return err;
-
- eol_or_eof(c);
-
- return 1;
-}
/*
- * Handles parsing a 'menu line' when we're parsing a label.
- */
-static int parse_label_menu(char **c, struct pxe_menu *cfg,
- struct pxe_label *label)
-{
- struct token t;
- char *s;
-
- s = *c;
-
- get_token(c, &t, L_KEYWORD);
-
- switch (t.type) {
- case T_DEFAULT:
- if (!cfg->default_label)
- cfg->default_label = strdup(label->name);
-
- if (!cfg->default_label)
- return -ENOMEM;
-
- break;
- case T_LABEL:
- parse_sliteral(c, &label->menu);
- break;
- default:
- printf("Ignoring malformed menu command: %.*s\n",
- (int)(*c - s), s);
- }
-
- eol_or_eof(c);
-
- return 0;
-}
-
-/*
- * Handles parsing a 'kernel' label.
- * expecting "filename" or "<fit_filename>#cfg"
- */
-static int parse_label_kernel(char **c, struct pxe_label *label)
-{
- char *s;
- int err;
-
- err = parse_sliteral(c, &label->kernel);
- if (err < 0)
- return err;
-
- s = strstr(label->kernel, "#");
- if (!s)
- return 1;
-
- label->config = malloc(strlen(s) + 1);
- if (!label->config)
- return -ENOMEM;
-
- strcpy(label->config, s);
- *s = 0;
-
- return 1;
-}
-
-/*
- * Parses a label and adds it to the list of labels for a menu.
- *
- * A label ends when we either get to the end of a file, or
- * get some input we otherwise don't have a handler defined
- * for.
- *
- */
-static int parse_label(char **c, struct pxe_menu *cfg)
-{
- struct token t;
- int len;
- char *s = *c;
- struct pxe_label *label;
- int err;
-
- label = label_create();
- if (!label)
- return -ENOMEM;
-
- err = parse_sliteral(c, &label->name);
- if (err < 0) {
- printf("Expected label name: %.*s\n", (int)(*c - s), s);
- label_destroy(label);
- return -EINVAL;
- }
-
- list_add_tail(&label->list, &cfg->labels);
-
- while (1) {
- s = *c;
- get_token(c, &t, L_KEYWORD);
-
- err = 0;
- switch (t.type) {
- case T_MENU:
- err = parse_label_menu(c, cfg, label);
- break;
-
- case T_KERNEL:
- case T_LINUX:
- err = parse_label_kernel(c, label);
- break;
-
- case T_APPEND:
- err = parse_sliteral(c, &label->append);
- if (label->initrd)
- break;
- s = strstr(label->append, "initrd=");
- if (!s)
- break;
- s += 7;
- len = (int)(strchr(s, ' ') - s);
- label->initrd = malloc(len + 1);
- strncpy(label->initrd, s, len);
- label->initrd[len] = '\0';
-
- break;
-
- case T_INITRD:
- if (!label->initrd)
- err = parse_sliteral(c, &label->initrd);
- break;
-
- case T_FDT:
- if (!label->fdt)
- err = parse_sliteral(c, &label->fdt);
- break;
-
- case T_FDTDIR:
- if (!label->fdtdir)
- err = parse_sliteral(c, &label->fdtdir);
- break;
-
- case T_LOCALBOOT:
- label->localboot = 1;
- err = parse_integer(c, &label->localboot_val);
- break;
-
- case T_IPAPPEND:
- err = parse_integer(c, &label->ipappend);
- break;
-
- case T_EOL:
- break;
-
- default:
- /*
- * put the token back! we don't want it - it's the end
- * of a label and whatever token this is, it's
- * something for the menu level context to handle.
- */
- *c = s;
- return 1;
- }
-
- if (err < 0)
- return err;
- }
-}
-
-/*
- * This 16 comes from the limit pxelinux imposes on nested includes.
- *
- * There is no reason at all we couldn't do more, but some limit helps prevent
- * infinite (until crash occurs) recursion if a file tries to include itself.
- */
-#define MAX_NEST_LEVEL 16
-
-/*
- * Entry point for parsing a menu file. nest_level indicates how many times
- * we've nested in includes. It will be 1 for the top level menu file.
- *
- * Returns 1 on success, < 0 on error.
- */
-static int parse_pxefile_top(cmd_tbl_t *cmdtp, char *p, unsigned long base,
- struct pxe_menu *cfg, int nest_level)
-{
- struct token t;
- char *s, *b, *label_name;
- int err;
-
- b = p;
-
- if (nest_level > MAX_NEST_LEVEL) {
- printf("Maximum nesting (%d) exceeded\n", MAX_NEST_LEVEL);
- return -EMLINK;
- }
-
- while (1) {
- s = p;
-
- get_token(&p, &t, L_KEYWORD);
-
- err = 0;
- switch (t.type) {
- case T_MENU:
- cfg->prompt = 1;
- err = parse_menu(cmdtp, &p, cfg,
- base + ALIGN(strlen(b) + 1, 4),
- nest_level);
- break;
-
- case T_TIMEOUT:
- err = parse_integer(&p, &cfg->timeout);
- break;
-
- case T_LABEL:
- err = parse_label(&p, cfg);
- break;
-
- case T_DEFAULT:
- case T_ONTIMEOUT:
- err = parse_sliteral(&p, &label_name);
-
- if (label_name) {
- if (cfg->default_label)
- free(cfg->default_label);
-
- cfg->default_label = label_name;
- }
-
- break;
-
- case T_INCLUDE:
- err = handle_include(cmdtp, &p,
- base + ALIGN(strlen(b), 4), cfg,
- nest_level + 1);
- break;
-
- case T_PROMPT:
- eol_or_eof(&p);
- break;
-
- case T_EOL:
- break;
-
- case T_EOF:
- return 1;
-
- default:
- printf("Ignoring unknown command: %.*s\n",
- (int)(p - s), s);
- eol_or_eof(&p);
- }
-
- if (err < 0)
- return err;
- }
-}
-
-/*
- * Free the memory used by a pxe_menu and its labels.
- */
-static void destroy_pxe_menu(struct pxe_menu *cfg)
-{
- struct list_head *pos, *n;
- struct pxe_label *label;
-
- if (cfg->title)
- free(cfg->title);
-
- if (cfg->default_label)
- free(cfg->default_label);
-
- list_for_each_safe(pos, n, &cfg->labels) {
- label = list_entry(pos, struct pxe_label, list);
-
- label_destroy(label);
- }
-
- free(cfg);
-}
-
-/*
- * Entry point for parsing a pxe file. This is only used for the top level
- * file.
- *
- * Returns NULL if there is an error, otherwise, returns a pointer to a
- * pxe_menu struct populated with the results of parsing the pxe file (and any
- * files it includes). The resulting pxe_menu struct can be free()'d by using
- * the destroy_pxe_menu() function.
- */
-static struct pxe_menu *parse_pxefile(cmd_tbl_t *cmdtp, unsigned long menucfg)
-{
- struct pxe_menu *cfg;
- char *buf;
- int r;
-
- cfg = malloc(sizeof(struct pxe_menu));
-
- if (!cfg)
- return NULL;
-
- memset(cfg, 0, sizeof(struct pxe_menu));
-
- INIT_LIST_HEAD(&cfg->labels);
-
- buf = map_sysmem(menucfg, 0);
- r = parse_pxefile_top(cmdtp, buf, menucfg, cfg, 1);
- unmap_sysmem(buf);
-
- if (r < 0) {
- destroy_pxe_menu(cfg);
- return NULL;
- }
-
- return cfg;
-}
-
-/*
- * Converts a pxe_menu struct into a menu struct for use with U-Boot's generic
- * menu code.
- */
-static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
-{
- struct pxe_label *label;
- struct list_head *pos;
- struct menu *m;
- int err;
- int i = 1;
- char *default_num = NULL;
-
- /*
- * Create a menu and add items for all the labels.
- */
- m = menu_create(cfg->title, DIV_ROUND_UP(cfg->timeout, 10),
- cfg->prompt, label_print, NULL, NULL);
-
- if (!m)
- return NULL;
-
- list_for_each(pos, &cfg->labels) {
- label = list_entry(pos, struct pxe_label, list);
-
- sprintf(label->num, "%d", i++);
- if (menu_item_add(m, label->num, label) != 1) {
- menu_destroy(m);
- return NULL;
- }
- if (cfg->default_label &&
- (strcmp(label->name, cfg->default_label) == 0))
- default_num = label->num;
-
- }
-
- /*
- * After we've created items for each label in the menu, set the
- * menu's default label if one was specified.
- */
- if (default_num) {
- err = menu_default_set(m, default_num);
- if (err != 1) {
- if (err != -ENOENT) {
- menu_destroy(m);
- return NULL;
- }
-
- printf("Missing default: %s\n", cfg->default_label);
- }
- }
-
- return m;
-}
-
-/*
- * Try to boot any labels we have yet to attempt to boot.
- */
-static void boot_unattempted_labels(cmd_tbl_t *cmdtp, struct pxe_menu *cfg)
-{
- struct list_head *pos;
- struct pxe_label *label;
-
- list_for_each(pos, &cfg->labels) {
- label = list_entry(pos, struct pxe_label, list);
-
- if (!label->attempted)
- label_boot(cmdtp, label);
- }
-}
-
-/*
- * Boot the system as prescribed by a pxe_menu.
- *
- * Use the menu system to either get the user's choice or the default, based
- * on config or user input. If there is no default or user's choice,
- * attempted to boot labels in the order they were given in pxe files.
- * If the default or user's choice fails to boot, attempt to boot other
- * labels in the order they were given in pxe files.
- *
- * If this function returns, there weren't any labels that successfully
- * booted, or the user interrupted the menu selection via ctrl+c.
- */
-static void handle_pxe_menu(cmd_tbl_t *cmdtp, struct pxe_menu *cfg)
-{
- void *choice;
- struct menu *m;
- int err;
-
-#ifdef CONFIG_CMD_BMP
- /* display BMP if available */
- if (cfg->bmp) {
- if (get_relfile(cmdtp, cfg->bmp, load_addr)) {
- run_command("cls", 0);
- bmp_display(load_addr,
- BMP_ALIGN_CENTER, BMP_ALIGN_CENTER);
- } else {
- printf("Skipping background bmp %s for failure\n",
- cfg->bmp);
- }
- }
-#endif
-
- m = pxe_menu_to_menu(cfg);
- if (!m)
- return;
-
- err = menu_get_choice(m, &choice);
-
- menu_destroy(m);
-
- /*
- * err == 1 means we got a choice back from menu_get_choice.
- *
- * err == -ENOENT if the menu was setup to select the default but no
- * default was set. in that case, we should continue trying to boot
- * labels that haven't been attempted yet.
- *
- * otherwise, the user interrupted or there was some other error and
- * we give up.
- */
-
- if (err == 1) {
- err = label_boot(cmdtp, choice);
- if (!err)
- return;
- } else if (err != -ENOENT) {
- return;
- }
-
- boot_unattempted_labels(cmdtp, cfg);
-}
-
-#ifdef CONFIG_CMD_NET
-/*
* Boots a system using a pxe file
*
* Returns 0 on success, 1 on error.
@@ -1666,7 +190,7 @@ do_pxe_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
cfg = parse_pxefile(cmdtp, pxefile_addr_r);
- if (cfg == NULL) {
+ if (!cfg) {
printf("Error parsing config file\n");
return 1;
}
@@ -1706,97 +230,9 @@ static int do_pxe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return CMD_RET_USAGE;
}
-U_BOOT_CMD(
- pxe, 3, 1, do_pxe,
- "commands to get and boot from pxe files",
- "get - try to retrieve a pxe file using tftp\npxe "
- "boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
+U_BOOT_CMD(pxe, 3, 1, do_pxe,
+ "commands to get and boot from pxe files",
+ "get - try to retrieve a pxe file using tftp\n"
+ "pxe boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
);
#endif
-
-/*
- * Boots a system using a local disk syslinux/extlinux file
- *
- * Returns 0 on success, 1 on error.
- */
-static int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
- unsigned long pxefile_addr_r;
- struct pxe_menu *cfg;
- char *pxefile_addr_str;
- char *filename;
- int prompt = 0;
-
- is_pxe = false;
-
- if (argc > 1 && strstr(argv[1], "-p")) {
- prompt = 1;
- argc--;
- argv++;
- }
-
- if (argc < 4)
- return cmd_usage(cmdtp);
-
- if (argc < 5) {
- pxefile_addr_str = from_env("pxefile_addr_r");
- if (!pxefile_addr_str)
- return 1;
- } else {
- pxefile_addr_str = argv[4];
- }
-
- if (argc < 6)
- filename = env_get("bootfile");
- else {
- filename = argv[5];
- env_set("bootfile", filename);
- }
-
- if (strstr(argv[3], "ext2"))
- do_getfile = do_get_ext2;
- else if (strstr(argv[3], "fat"))
- do_getfile = do_get_fat;
- else if (strstr(argv[3], "any"))
- do_getfile = do_get_any;
- else {
- printf("Invalid filesystem: %s\n", argv[3]);
- return 1;
- }
- fs_argv[1] = argv[1];
- fs_argv[2] = argv[2];
-
- if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
- printf("Invalid pxefile address: %s\n", pxefile_addr_str);
- return 1;
- }
-
- if (get_pxe_file(cmdtp, filename, pxefile_addr_r) < 0) {
- printf("Error reading config file\n");
- return 1;
- }
-
- cfg = parse_pxefile(cmdtp, pxefile_addr_r);
-
- if (cfg == NULL) {
- printf("Error parsing config file\n");
- return 1;
- }
-
- if (prompt)
- cfg->prompt = 1;
-
- handle_pxe_menu(cmdtp, cfg);
-
- destroy_pxe_menu(cfg);
-
- return 0;
-}
-
-U_BOOT_CMD(
- sysboot, 7, 1, do_sysboot,
- "command to get and boot from syslinux files",
- "[-p] <interface> <dev[:part]> <ext2|fat|any> [addr] [filename]\n"
- " - load and parse syslinux menu file 'filename' from ext2, fat\n"
- " or any filesystem on 'dev' on 'interface' to address 'addr'"
-);
diff --git a/cmd/pxe_utils.c b/cmd/pxe_utils.c
new file mode 100644
index 0000000000..a636346bb5
--- /dev/null
+++ b/cmd/pxe_utils.c
@@ -0,0 +1,1352 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2010-2011 Calxeda, Inc.
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ */
+
+#include <common.h>
+#include <env.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <lcd.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <errno.h>
+#include <linux/list.h>
+
+#include <splash.h>
+#include <asm/io.h>
+
+#include "menu.h"
+#include "cli.h"
+
+#include "pxe_utils.h"
+
+#define MAX_TFTP_PATH_LEN 512
+
+bool is_pxe;
+
+/*
+ * Convert an ethaddr from the environment to the format used by pxelinux
+ * filenames based on mac addresses. Convert's ':' to '-', and adds "01-" to
+ * the beginning of the ethernet address to indicate a hardware type of
+ * Ethernet. Also converts uppercase hex characters into lowercase, to match
+ * pxelinux's behavior.
+ *
+ * Returns 1 for success, -ENOENT if 'ethaddr' is undefined in the
+ * environment, or some other value < 0 on error.
+ */
+int format_mac_pxe(char *outbuf, size_t outbuf_len)
+{
+ uchar ethaddr[6];
+
+ if (outbuf_len < 21) {
+ printf("outbuf is too small (%zd < 21)\n", outbuf_len);
+
+ return -EINVAL;
+ }
+
+ if (!eth_env_get_enetaddr_by_index("eth", eth_get_dev_index(), ethaddr))
+ return -ENOENT;
+
+ sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x",
+ ethaddr[0], ethaddr[1], ethaddr[2],
+ ethaddr[3], ethaddr[4], ethaddr[5]);
+
+ return 1;
+}
+
+/*
+ * Returns the directory the file specified in the bootfile env variable is
+ * in. If bootfile isn't defined in the environment, return NULL, which should
+ * be interpreted as "don't prepend anything to paths".
+ */
+static int get_bootfile_path(const char *file_path, char *bootfile_path,
+ size_t bootfile_path_size)
+{
+ char *bootfile, *last_slash;
+ size_t path_len = 0;
+
+ /* Only syslinux allows absolute paths */
+ if (file_path[0] == '/' && !is_pxe)
+ goto ret;
+
+ bootfile = from_env("bootfile");
+
+ if (!bootfile)
+ goto ret;
+
+ last_slash = strrchr(bootfile, '/');
+
+ if (!last_slash)
+ goto ret;
+
+ path_len = (last_slash - bootfile) + 1;
+
+ if (bootfile_path_size < path_len) {
+ printf("bootfile_path too small. (%zd < %zd)\n",
+ bootfile_path_size, path_len);
+
+ return -1;
+ }
+
+ strncpy(bootfile_path, bootfile, path_len);
+
+ ret:
+ bootfile_path[path_len] = '\0';
+
+ return 1;
+}
+
+int (*do_getfile)(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr);
+
+/*
+ * As in pxelinux, paths to files referenced from files we retrieve are
+ * relative to the location of bootfile. get_relfile takes such a path and
+ * joins it with the bootfile path to get the full path to the target file. If
+ * the bootfile path is NULL, we use file_path as is.
+ *
+ * Returns 1 for success, or < 0 on error.
+ */
+static int get_relfile(cmd_tbl_t *cmdtp, const char *file_path,
+ unsigned long file_addr)
+{
+ size_t path_len;
+ char relfile[MAX_TFTP_PATH_LEN + 1];
+ char addr_buf[18];
+ int err;
+
+ err = get_bootfile_path(file_path, relfile, sizeof(relfile));
+
+ if (err < 0)
+ return err;
+
+ path_len = strlen(file_path);
+ path_len += strlen(relfile);
+
+ if (path_len > MAX_TFTP_PATH_LEN) {
+ printf("Base path too long (%s%s)\n", relfile, file_path);
+
+ return -ENAMETOOLONG;
+ }
+
+ strcat(relfile, file_path);
+
+ printf("Retrieving file: %s\n", relfile);
+
+ sprintf(addr_buf, "%lx", file_addr);
+
+ return do_getfile(cmdtp, relfile, addr_buf);
+}
+
+/*
+ * Retrieve the file at 'file_path' to the locate given by 'file_addr'. If
+ * 'bootfile' was specified in the environment, the path to bootfile will be
+ * prepended to 'file_path' and the resulting path will be used.
+ *
+ * Returns 1 on success, or < 0 for error.
+ */
+int get_pxe_file(cmd_tbl_t *cmdtp, const char *file_path,
+ unsigned long file_addr)
+{
+ unsigned long config_file_size;
+ char *tftp_filesize;
+ int err;
+ char *buf;
+
+ err = get_relfile(cmdtp, file_path, file_addr);
+
+ if (err < 0)
+ return err;
+
+ /*
+ * the file comes without a NUL byte at the end, so find out its size
+ * and add the NUL byte.
+ */
+ tftp_filesize = from_env("filesize");
+
+ if (!tftp_filesize)
+ return -ENOENT;
+
+ if (strict_strtoul(tftp_filesize, 16, &config_file_size) < 0)
+ return -EINVAL;
+
+ buf = map_sysmem(file_addr + config_file_size, 1);
+ *buf = '\0';
+ unmap_sysmem(buf);
+
+ return 1;
+}
+
+#define PXELINUX_DIR "pxelinux.cfg/"
+
+/*
+ * Retrieves a file in the 'pxelinux.cfg' folder. Since this uses get_pxe_file
+ * to do the hard work, the location of the 'pxelinux.cfg' folder is generated
+ * from the bootfile path, as described above.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+int get_pxelinux_path(cmd_tbl_t *cmdtp, const char *file,
+ unsigned long pxefile_addr_r)
+{
+ size_t base_len = strlen(PXELINUX_DIR);
+ char path[MAX_TFTP_PATH_LEN + 1];
+
+ if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) {
+ printf("path (%s%s) too long, skipping\n",
+ PXELINUX_DIR, file);
+ return -ENAMETOOLONG;
+ }
+
+ sprintf(path, PXELINUX_DIR "%s", file);
+
+ return get_pxe_file(cmdtp, path, pxefile_addr_r);
+}
+
+/*
+ * Wrapper to make it easier to store the file at file_path in the location
+ * specified by envaddr_name. file_path will be joined to the bootfile path,
+ * if any is specified.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static int get_relfile_envaddr(cmd_tbl_t *cmdtp, const char *file_path,
+ const char *envaddr_name)
+{
+ unsigned long file_addr;
+ char *envaddr;
+
+ envaddr = from_env(envaddr_name);
+
+ if (!envaddr)
+ return -ENOENT;
+
+ if (strict_strtoul(envaddr, 16, &file_addr) < 0)
+ return -EINVAL;
+
+ return get_relfile(cmdtp, file_path, file_addr);
+}
+
+/*
+ * Allocates memory for and initializes a pxe_label. This uses malloc, so the
+ * result must be free()'d to reclaim the memory.
+ *
+ * Returns NULL if malloc fails.
+ */
+static struct pxe_label *label_create(void)
+{
+ struct pxe_label *label;
+
+ label = malloc(sizeof(struct pxe_label));
+
+ if (!label)
+ return NULL;
+
+ memset(label, 0, sizeof(struct pxe_label));
+
+ return label;
+}
+
+/*
+ * Free the memory used by a pxe_label, including that used by its name,
+ * kernel, append and initrd members, if they're non NULL.
+ *
+ * So - be sure to only use dynamically allocated memory for the members of
+ * the pxe_label struct, unless you want to clean it up first. These are
+ * currently only created by the pxe file parsing code.
+ */
+static void label_destroy(struct pxe_label *label)
+{
+ if (label->name)
+ free(label->name);
+
+ if (label->kernel)
+ free(label->kernel);
+
+ if (label->config)
+ free(label->config);
+
+ if (label->append)
+ free(label->append);
+
+ if (label->initrd)
+ free(label->initrd);
+
+ if (label->fdt)
+ free(label->fdt);
+
+ if (label->fdtdir)
+ free(label->fdtdir);
+
+ free(label);
+}
+
+/*
+ * Print a label and its string members if they're defined.
+ *
+ * This is passed as a callback to the menu code for displaying each
+ * menu entry.
+ */
+static void label_print(void *data)
+{
+ struct pxe_label *label = data;
+ const char *c = label->menu ? label->menu : label->name;
+
+ printf("%s:\t%s\n", label->num, c);
+}
+
+/*
+ * Boot a label that specified 'localboot'. This requires that the 'localcmd'
+ * environment variable is defined. Its contents will be executed as U-Boot
+ * command. If the label specified an 'append' line, its contents will be
+ * used to overwrite the contents of the 'bootargs' environment variable prior
+ * to running 'localcmd'.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static int label_localboot(struct pxe_label *label)
+{
+ char *localcmd;
+
+ localcmd = from_env("localcmd");
+
+ if (!localcmd)
+ return -ENOENT;
+
+ if (label->append) {
+ char bootargs[CONFIG_SYS_CBSIZE];
+
+ cli_simple_process_macros(label->append, bootargs);
+ env_set("bootargs", bootargs);
+ }
+
+ debug("running: %s\n", localcmd);
+
+ return run_command_list(localcmd, strlen(localcmd), 0);
+}
+
+/*
+ * Boot according to the contents of a pxe_label.
+ *
+ * If we can't boot for any reason, we return. A successful boot never
+ * returns.
+ *
+ * The kernel will be stored in the location given by the 'kernel_addr_r'
+ * environment variable.
+ *
+ * If the label specifies an initrd file, it will be stored in the location
+ * given by the 'ramdisk_addr_r' environment variable.
+ *
+ * If the label specifies an 'append' line, its contents will overwrite that
+ * of the 'bootargs' environment variable.
+ */
+static int label_boot(cmd_tbl_t *cmdtp, struct pxe_label *label)
+{
+ char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
+ char initrd_str[28];
+ char mac_str[29] = "";
+ char ip_str[68] = "";
+ char *fit_addr = NULL;
+ int bootm_argc = 2;
+ int len = 0;
+ ulong kernel_addr;
+ void *buf;
+
+ label_print(label);
+
+ label->attempted = 1;
+
+ if (label->localboot) {
+ if (label->localboot_val >= 0)
+ label_localboot(label);
+ return 0;
+ }
+
+ if (!label->kernel) {
+ printf("No kernel given, skipping %s\n",
+ label->name);
+ return 1;
+ }
+
+ if (label->initrd) {
+ if (get_relfile_envaddr(cmdtp, label->initrd, "ramdisk_addr_r") < 0) {
+ printf("Skipping %s for failure retrieving initrd\n",
+ label->name);
+ return 1;
+ }
+
+ bootm_argv[2] = initrd_str;
+ strncpy(bootm_argv[2], env_get("ramdisk_addr_r"), 18);
+ strcat(bootm_argv[2], ":");
+ strncat(bootm_argv[2], env_get("filesize"), 9);
+ bootm_argc = 3;
+ }
+
+ if (get_relfile_envaddr(cmdtp, label->kernel, "kernel_addr_r") < 0) {
+ printf("Skipping %s for failure retrieving kernel\n",
+ label->name);
+ return 1;
+ }
+
+ if (label->ipappend & 0x1) {
+ sprintf(ip_str, " ip=%s:%s:%s:%s",
+ env_get("ipaddr"), env_get("serverip"),
+ env_get("gatewayip"), env_get("netmask"));
+ }
+
+#ifdef CONFIG_CMD_NET
+ if (label->ipappend & 0x2) {
+ int err;
+
+ strcpy(mac_str, " BOOTIF=");
+ err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8);
+ if (err < 0)
+ mac_str[0] = '\0';
+ }
+#endif
+
+ if ((label->ipappend & 0x3) || label->append) {
+ char bootargs[CONFIG_SYS_CBSIZE] = "";
+ char finalbootargs[CONFIG_SYS_CBSIZE];
+
+ if (strlen(label->append ?: "") +
+ strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) {
+ printf("bootarg overflow %zd+%zd+%zd+1 > %zd\n",
+ strlen(label->append ?: ""),
+ strlen(ip_str), strlen(mac_str),
+ sizeof(bootargs));
+ return 1;
+ }
+
+ if (label->append)
+ strncpy(bootargs, label->append, sizeof(bootargs));
+
+ strcat(bootargs, ip_str);
+ strcat(bootargs, mac_str);
+
+ cli_simple_process_macros(bootargs, finalbootargs);
+ env_set("bootargs", finalbootargs);
+ printf("append: %s\n", finalbootargs);
+ }
+
+ bootm_argv[1] = env_get("kernel_addr_r");
+ /* for FIT, append the configuration identifier */
+ if (label->config) {
+ int len = strlen(bootm_argv[1]) + strlen(label->config) + 1;
+
+ fit_addr = malloc(len);
+ if (!fit_addr) {
+ printf("malloc fail (FIT address)\n");
+ return 1;
+ }
+ snprintf(fit_addr, len, "%s%s", bootm_argv[1], label->config);
+ bootm_argv[1] = fit_addr;
+ }
+
+ /*
+ * fdt usage is optional:
+ * It handles the following scenarios. All scenarios are exclusive
+ *
+ * Scenario 1: If fdt_addr_r specified and "fdt" label is defined in
+ * pxe file, retrieve fdt blob from server. Pass fdt_addr_r to bootm,
+ * and adjust argc appropriately.
+ *
+ * Scenario 2: If there is an fdt_addr specified, pass it along to
+ * bootm, and adjust argc appropriately.
+ *
+ * Scenario 3: fdt blob is not available.
+ */
+ bootm_argv[3] = env_get("fdt_addr_r");
+
+ /* if fdt label is defined then get fdt from server */
+ if (bootm_argv[3]) {
+ char *fdtfile = NULL;
+ char *fdtfilefree = NULL;
+
+ if (label->fdt) {
+ fdtfile = label->fdt;
+ } else if (label->fdtdir) {
+ char *f1, *f2, *f3, *f4, *slash;
+
+ f1 = env_get("fdtfile");
+ if (f1) {
+ f2 = "";
+ f3 = "";
+ f4 = "";
+ } else {
+ /*
+ * For complex cases where this code doesn't
+ * generate the correct filename, the board
+ * code should set $fdtfile during early boot,
+ * or the boot scripts should set $fdtfile
+ * before invoking "pxe" or "sysboot".
+ */
+ f1 = env_get("soc");
+ f2 = "-";
+ f3 = env_get("board");
+ f4 = ".dtb";
+ }
+
+ len = strlen(label->fdtdir);
+ if (!len)
+ slash = "./";
+ else if (label->fdtdir[len - 1] != '/')
+ slash = "/";
+ else
+ slash = "";
+
+ len = strlen(label->fdtdir) + strlen(slash) +
+ strlen(f1) + strlen(f2) + strlen(f3) +
+ strlen(f4) + 1;
+ fdtfilefree = malloc(len);
+ if (!fdtfilefree) {
+ printf("malloc fail (FDT filename)\n");
+ goto cleanup;
+ }
+
+ snprintf(fdtfilefree, len, "%s%s%s%s%s%s",
+ label->fdtdir, slash, f1, f2, f3, f4);
+ fdtfile = fdtfilefree;
+ }
+
+ if (fdtfile) {
+ int err = get_relfile_envaddr(cmdtp, fdtfile,
+ "fdt_addr_r");
+
+ free(fdtfilefree);
+ if (err < 0) {
+ printf("Skipping %s for failure retrieving fdt\n",
+ label->name);
+ goto cleanup;
+ }
+ } else {
+ bootm_argv[3] = NULL;
+ }
+ }
+
+ if (!bootm_argv[3])
+ bootm_argv[3] = env_get("fdt_addr");
+
+ if (bootm_argv[3]) {
+ if (!bootm_argv[2])
+ bootm_argv[2] = "-";
+ bootm_argc = 4;
+ }
+
+ kernel_addr = genimg_get_kernel_addr(bootm_argv[1]);
+ buf = map_sysmem(kernel_addr, 0);
+ /* Try bootm for legacy and FIT format image */
+ if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID)
+ do_bootm(cmdtp, 0, bootm_argc, bootm_argv);
+#ifdef CONFIG_CMD_BOOTI
+ /* Try booting an AArch64 Linux kernel image */
+ else
+ do_booti(cmdtp, 0, bootm_argc, bootm_argv);
+#elif defined(CONFIG_CMD_BOOTZ)
+ /* Try booting a Image */
+ else
+ do_bootz(cmdtp, 0, bootm_argc, bootm_argv);
+#endif
+ unmap_sysmem(buf);
+
+cleanup:
+ if (fit_addr)
+ free(fit_addr);
+ return 1;
+}
+
+/*
+ * Tokens for the pxe file parser.
+ */
+enum token_type {
+ T_EOL,
+ T_STRING,
+ T_EOF,
+ T_MENU,
+ T_TITLE,
+ T_TIMEOUT,
+ T_LABEL,
+ T_KERNEL,
+ T_LINUX,
+ T_APPEND,
+ T_INITRD,
+ T_LOCALBOOT,
+ T_DEFAULT,
+ T_PROMPT,
+ T_INCLUDE,
+ T_FDT,
+ T_FDTDIR,
+ T_ONTIMEOUT,
+ T_IPAPPEND,
+ T_BACKGROUND,
+ T_INVALID
+};
+
+/*
+ * A token - given by a value and a type.
+ */
+struct token {
+ char *val;
+ enum token_type type;
+};
+
+/*
+ * Keywords recognized.
+ */
+static const struct token keywords[] = {
+ {"menu", T_MENU},
+ {"title", T_TITLE},
+ {"timeout", T_TIMEOUT},
+ {"default", T_DEFAULT},
+ {"prompt", T_PROMPT},
+ {"label", T_LABEL},
+ {"kernel", T_KERNEL},
+ {"linux", T_LINUX},
+ {"localboot", T_LOCALBOOT},
+ {"append", T_APPEND},
+ {"initrd", T_INITRD},
+ {"include", T_INCLUDE},
+ {"devicetree", T_FDT},
+ {"fdt", T_FDT},
+ {"devicetreedir", T_FDTDIR},
+ {"fdtdir", T_FDTDIR},
+ {"ontimeout", T_ONTIMEOUT,},
+ {"ipappend", T_IPAPPEND,},
+ {"background", T_BACKGROUND,},
+ {NULL, T_INVALID}
+};
+
+/*
+ * Since pxe(linux) files don't have a token to identify the start of a
+ * literal, we have to keep track of when we're in a state where a literal is
+ * expected vs when we're in a state a keyword is expected.
+ */
+enum lex_state {
+ L_NORMAL = 0,
+ L_KEYWORD,
+ L_SLITERAL
+};
+
+/*
+ * get_string retrieves a string from *p and stores it as a token in
+ * *t.
+ *
+ * get_string used for scanning both string literals and keywords.
+ *
+ * Characters from *p are copied into t-val until a character equal to
+ * delim is found, or a NUL byte is reached. If delim has the special value of
+ * ' ', any whitespace character will be used as a delimiter.
+ *
+ * If lower is unequal to 0, uppercase characters will be converted to
+ * lowercase in the result. This is useful to make keywords case
+ * insensitive.
+ *
+ * The location of *p is updated to point to the first character after the end
+ * of the token - the ending delimiter.
+ *
+ * On success, the new value of t->val is returned. Memory for t->val is
+ * allocated using malloc and must be free()'d to reclaim it. If insufficient
+ * memory is available, NULL is returned.
+ */
+static char *get_string(char **p, struct token *t, char delim, int lower)
+{
+ char *b, *e;
+ size_t len, i;
+
+ /*
+ * b and e both start at the beginning of the input stream.
+ *
+ * e is incremented until we find the ending delimiter, or a NUL byte
+ * is reached. Then, we take e - b to find the length of the token.
+ */
+ b = *p;
+ e = *p;
+
+ while (*e) {
+ if ((delim == ' ' && isspace(*e)) || delim == *e)
+ break;
+ e++;
+ }
+
+ len = e - b;
+
+ /*
+ * Allocate memory to hold the string, and copy it in, converting
+ * characters to lowercase if lower is != 0.
+ */
+ t->val = malloc(len + 1);
+ if (!t->val)
+ return NULL;
+
+ for (i = 0; i < len; i++, b++) {
+ if (lower)
+ t->val[i] = tolower(*b);
+ else
+ t->val[i] = *b;
+ }
+
+ t->val[len] = '\0';
+
+ /*
+ * Update *p so the caller knows where to continue scanning.
+ */
+ *p = e;
+
+ t->type = T_STRING;
+
+ return t->val;
+}
+
+/*
+ * Populate a keyword token with a type and value.
+ */
+static void get_keyword(struct token *t)
+{
+ int i;
+
+ for (i = 0; keywords[i].val; i++) {
+ if (!strcmp(t->val, keywords[i].val)) {
+ t->type = keywords[i].type;
+ break;
+ }
+ }
+}
+
+/*
+ * Get the next token. We have to keep track of which state we're in to know
+ * if we're looking to get a string literal or a keyword.
+ *
+ * *p is updated to point at the first character after the current token.
+ */
+static void get_token(char **p, struct token *t, enum lex_state state)
+{
+ char *c = *p;
+
+ t->type = T_INVALID;
+
+ /* eat non EOL whitespace */
+ while (isblank(*c))
+ c++;
+
+ /*
+ * eat comments. note that string literals can't begin with #, but
+ * can contain a # after their first character.
+ */
+ if (*c == '#') {
+ while (*c && *c != '\n')
+ c++;
+ }
+
+ if (*c == '\n') {
+ t->type = T_EOL;
+ c++;
+ } else if (*c == '\0') {
+ t->type = T_EOF;
+ c++;
+ } else if (state == L_SLITERAL) {
+ get_string(&c, t, '\n', 0);
+ } else if (state == L_KEYWORD) {
+ /*
+ * when we expect a keyword, we first get the next string
+ * token delimited by whitespace, and then check if it
+ * matches a keyword in our keyword list. if it does, it's
+ * converted to a keyword token of the appropriate type, and
+ * if not, it remains a string token.
+ */
+ get_string(&c, t, ' ', 1);
+ get_keyword(t);
+ }
+
+ *p = c;
+}
+
+/*
+ * Increment *c until we get to the end of the current line, or EOF.
+ */
+static void eol_or_eof(char **c)
+{
+ while (**c && **c != '\n')
+ (*c)++;
+}
+
+/*
+ * All of these parse_* functions share some common behavior.
+ *
+ * They finish with *c pointing after the token they parse, and return 1 on
+ * success, or < 0 on error.
+ */
+
+/*
+ * Parse a string literal and store a pointer it at *dst. String literals
+ * terminate at the end of the line.
+ */
+static int parse_sliteral(char **c, char **dst)
+{
+ struct token t;
+ char *s = *c;
+
+ get_token(c, &t, L_SLITERAL);
+
+ if (t.type != T_STRING) {
+ printf("Expected string literal: %.*s\n", (int)(*c - s), s);
+ return -EINVAL;
+ }
+
+ *dst = t.val;
+
+ return 1;
+}
+
+/*
+ * Parse a base 10 (unsigned) integer and store it at *dst.
+ */
+static int parse_integer(char **c, int *dst)
+{
+ struct token t;
+ char *s = *c;
+
+ get_token(c, &t, L_SLITERAL);
+
+ if (t.type != T_STRING) {
+ printf("Expected string: %.*s\n", (int)(*c - s), s);
+ return -EINVAL;
+ }
+
+ *dst = simple_strtol(t.val, NULL, 10);
+
+ free(t.val);
+
+ return 1;
+}
+
+static int parse_pxefile_top(cmd_tbl_t *cmdtp, char *p, unsigned long base,
+ struct pxe_menu *cfg, int nest_level);
+
+/*
+ * Parse an include statement, and retrieve and parse the file it mentions.
+ *
+ * base should point to a location where it's safe to store the file, and
+ * nest_level should indicate how many nested includes have occurred. For this
+ * include, nest_level has already been incremented and doesn't need to be
+ * incremented here.
+ */
+static int handle_include(cmd_tbl_t *cmdtp, char **c, unsigned long base,
+ struct pxe_menu *cfg, int nest_level)
+{
+ char *include_path;
+ char *s = *c;
+ int err;
+ char *buf;
+ int ret;
+
+ err = parse_sliteral(c, &include_path);
+
+ if (err < 0) {
+ printf("Expected include path: %.*s\n", (int)(*c - s), s);
+ return err;
+ }
+
+ err = get_pxe_file(cmdtp, include_path, base);
+
+ if (err < 0) {
+ printf("Couldn't retrieve %s\n", include_path);
+ return err;
+ }
+
+ buf = map_sysmem(base, 0);
+ ret = parse_pxefile_top(cmdtp, buf, base, cfg, nest_level);
+ unmap_sysmem(buf);
+
+ return ret;
+}
+
+/*
+ * Parse lines that begin with 'menu'.
+ *
+ * base and nest are provided to handle the 'menu include' case.
+ *
+ * base should point to a location where it's safe to store the included file.
+ *
+ * nest_level should be 1 when parsing the top level pxe file, 2 when parsing
+ * a file it includes, 3 when parsing a file included by that file, and so on.
+ */
+static int parse_menu(cmd_tbl_t *cmdtp, char **c, struct pxe_menu *cfg,
+ unsigned long base, int nest_level)
+{
+ struct token t;
+ char *s = *c;
+ int err = 0;
+
+ get_token(c, &t, L_KEYWORD);
+
+ switch (t.type) {
+ case T_TITLE:
+ err = parse_sliteral(c, &cfg->title);
+
+ break;
+
+ case T_INCLUDE:
+ err = handle_include(cmdtp, c, base, cfg, nest_level + 1);
+ break;
+
+ case T_BACKGROUND:
+ err = parse_sliteral(c, &cfg->bmp);
+ break;
+
+ default:
+ printf("Ignoring malformed menu command: %.*s\n",
+ (int)(*c - s), s);
+ }
+
+ if (err < 0)
+ return err;
+
+ eol_or_eof(c);
+
+ return 1;
+}
+
+/*
+ * Handles parsing a 'menu line' when we're parsing a label.
+ */
+static int parse_label_menu(char **c, struct pxe_menu *cfg,
+ struct pxe_label *label)
+{
+ struct token t;
+ char *s;
+
+ s = *c;
+
+ get_token(c, &t, L_KEYWORD);
+
+ switch (t.type) {
+ case T_DEFAULT:
+ if (!cfg->default_label)
+ cfg->default_label = strdup(label->name);
+
+ if (!cfg->default_label)
+ return -ENOMEM;
+
+ break;
+ case T_LABEL:
+ parse_sliteral(c, &label->menu);
+ break;
+ default:
+ printf("Ignoring malformed menu command: %.*s\n",
+ (int)(*c - s), s);
+ }
+
+ eol_or_eof(c);
+
+ return 0;
+}
+
+/*
+ * Handles parsing a 'kernel' label.
+ * expecting "filename" or "<fit_filename>#cfg"
+ */
+static int parse_label_kernel(char **c, struct pxe_label *label)
+{
+ char *s;
+ int err;
+
+ err = parse_sliteral(c, &label->kernel);
+ if (err < 0)
+ return err;
+
+ s = strstr(label->kernel, "#");
+ if (!s)
+ return 1;
+
+ label->config = malloc(strlen(s) + 1);
+ if (!label->config)
+ return -ENOMEM;
+
+ strcpy(label->config, s);
+ *s = 0;
+
+ return 1;
+}
+
+/*
+ * Parses a label and adds it to the list of labels for a menu.
+ *
+ * A label ends when we either get to the end of a file, or
+ * get some input we otherwise don't have a handler defined
+ * for.
+ *
+ */
+static int parse_label(char **c, struct pxe_menu *cfg)
+{
+ struct token t;
+ int len;
+ char *s = *c;
+ struct pxe_label *label;
+ int err;
+
+ label = label_create();
+ if (!label)
+ return -ENOMEM;
+
+ err = parse_sliteral(c, &label->name);
+ if (err < 0) {
+ printf("Expected label name: %.*s\n", (int)(*c - s), s);
+ label_destroy(label);
+ return -EINVAL;
+ }
+
+ list_add_tail(&label->list, &cfg->labels);
+
+ while (1) {
+ s = *c;
+ get_token(c, &t, L_KEYWORD);
+
+ err = 0;
+ switch (t.type) {
+ case T_MENU:
+ err = parse_label_menu(c, cfg, label);
+ break;
+
+ case T_KERNEL:
+ case T_LINUX:
+ err = parse_label_kernel(c, label);
+ break;
+
+ case T_APPEND:
+ err = parse_sliteral(c, &label->append);
+ if (label->initrd)
+ break;
+ s = strstr(label->append, "initrd=");
+ if (!s)
+ break;
+ s += 7;
+ len = (int)(strchr(s, ' ') - s);
+ label->initrd = malloc(len + 1);
+ strncpy(label->initrd, s, len);
+ label->initrd[len] = '\0';
+
+ break;
+
+ case T_INITRD:
+ if (!label->initrd)
+ err = parse_sliteral(c, &label->initrd);
+ break;
+
+ case T_FDT:
+ if (!label->fdt)
+ err = parse_sliteral(c, &label->fdt);
+ break;
+
+ case T_FDTDIR:
+ if (!label->fdtdir)
+ err = parse_sliteral(c, &label->fdtdir);
+ break;
+
+ case T_LOCALBOOT:
+ label->localboot = 1;
+ err = parse_integer(c, &label->localboot_val);
+ break;
+
+ case T_IPAPPEND:
+ err = parse_integer(c, &label->ipappend);
+ break;
+
+ case T_EOL:
+ break;
+
+ default:
+ /*
+ * put the token back! we don't want it - it's the end
+ * of a label and whatever token this is, it's
+ * something for the menu level context to handle.
+ */
+ *c = s;
+ return 1;
+ }
+
+ if (err < 0)
+ return err;
+ }
+}
+
+/*
+ * This 16 comes from the limit pxelinux imposes on nested includes.
+ *
+ * There is no reason at all we couldn't do more, but some limit helps prevent
+ * infinite (until crash occurs) recursion if a file tries to include itself.
+ */
+#define MAX_NEST_LEVEL 16
+
+/*
+ * Entry point for parsing a menu file. nest_level indicates how many times
+ * we've nested in includes. It will be 1 for the top level menu file.
+ *
+ * Returns 1 on success, < 0 on error.
+ */
+static int parse_pxefile_top(cmd_tbl_t *cmdtp, char *p, unsigned long base,
+ struct pxe_menu *cfg, int nest_level)
+{
+ struct token t;
+ char *s, *b, *label_name;
+ int err;
+
+ b = p;
+
+ if (nest_level > MAX_NEST_LEVEL) {
+ printf("Maximum nesting (%d) exceeded\n", MAX_NEST_LEVEL);
+ return -EMLINK;
+ }
+
+ while (1) {
+ s = p;
+
+ get_token(&p, &t, L_KEYWORD);
+
+ err = 0;
+ switch (t.type) {
+ case T_MENU:
+ cfg->prompt = 1;
+ err = parse_menu(cmdtp, &p, cfg,
+ base + ALIGN(strlen(b) + 1, 4),
+ nest_level);
+ break;
+
+ case T_TIMEOUT:
+ err = parse_integer(&p, &cfg->timeout);
+ break;
+
+ case T_LABEL:
+ err = parse_label(&p, cfg);
+ break;
+
+ case T_DEFAULT:
+ case T_ONTIMEOUT:
+ err = parse_sliteral(&p, &label_name);
+
+ if (label_name) {
+ if (cfg->default_label)
+ free(cfg->default_label);
+
+ cfg->default_label = label_name;
+ }
+
+ break;
+
+ case T_INCLUDE:
+ err = handle_include(cmdtp, &p,
+ base + ALIGN(strlen(b), 4), cfg,
+ nest_level + 1);
+ break;
+
+ case T_PROMPT:
+ eol_or_eof(&p);
+ break;
+
+ case T_EOL:
+ break;
+
+ case T_EOF:
+ return 1;
+
+ default:
+ printf("Ignoring unknown command: %.*s\n",
+ (int)(p - s), s);
+ eol_or_eof(&p);
+ }
+
+ if (err < 0)
+ return err;
+ }
+}
+
+/*
+ * Free the memory used by a pxe_menu and its labels.
+ */
+void destroy_pxe_menu(struct pxe_menu *cfg)
+{
+ struct list_head *pos, *n;
+ struct pxe_label *label;
+
+ if (cfg->title)
+ free(cfg->title);
+
+ if (cfg->default_label)
+ free(cfg->default_label);
+
+ list_for_each_safe(pos, n, &cfg->labels) {
+ label = list_entry(pos, struct pxe_label, list);
+
+ label_destroy(label);
+ }
+
+ free(cfg);
+}
+
+/*
+ * Entry point for parsing a pxe file. This is only used for the top level
+ * file.
+ *
+ * Returns NULL if there is an error, otherwise, returns a pointer to a
+ * pxe_menu struct populated with the results of parsing the pxe file (and any
+ * files it includes). The resulting pxe_menu struct can be free()'d by using
+ * the destroy_pxe_menu() function.
+ */
+struct pxe_menu *parse_pxefile(cmd_tbl_t *cmdtp, unsigned long menucfg)
+{
+ struct pxe_menu *cfg;
+ char *buf;
+ int r;
+
+ cfg = malloc(sizeof(struct pxe_menu));
+
+ if (!cfg)
+ return NULL;
+
+ memset(cfg, 0, sizeof(struct pxe_menu));
+
+ INIT_LIST_HEAD(&cfg->labels);
+
+ buf = map_sysmem(menucfg, 0);
+ r = parse_pxefile_top(cmdtp, buf, menucfg, cfg, 1);
+ unmap_sysmem(buf);
+
+ if (r < 0) {
+ destroy_pxe_menu(cfg);
+ return NULL;
+ }
+
+ return cfg;
+}
+
+/*
+ * Converts a pxe_menu struct into a menu struct for use with U-Boot's generic
+ * menu code.
+ */
+static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
+{
+ struct pxe_label *label;
+ struct list_head *pos;
+ struct menu *m;
+ int err;
+ int i = 1;
+ char *default_num = NULL;
+
+ /*
+ * Create a menu and add items for all the labels.
+ */
+ m = menu_create(cfg->title, DIV_ROUND_UP(cfg->timeout, 10),
+ cfg->prompt, label_print, NULL, NULL);
+
+ if (!m)
+ return NULL;
+
+ list_for_each(pos, &cfg->labels) {
+ label = list_entry(pos, struct pxe_label, list);
+
+ sprintf(label->num, "%d", i++);
+ if (menu_item_add(m, label->num, label) != 1) {
+ menu_destroy(m);
+ return NULL;
+ }
+ if (cfg->default_label &&
+ (strcmp(label->name, cfg->default_label) == 0))
+ default_num = label->num;
+ }
+
+ /*
+ * After we've created items for each label in the menu, set the
+ * menu's default label if one was specified.
+ */
+ if (default_num) {
+ err = menu_default_set(m, default_num);
+ if (err != 1) {
+ if (err != -ENOENT) {
+ menu_destroy(m);
+ return NULL;
+ }
+
+ printf("Missing default: %s\n", cfg->default_label);
+ }
+ }
+
+ return m;
+}
+
+/*
+ * Try to boot any labels we have yet to attempt to boot.
+ */
+static void boot_unattempted_labels(cmd_tbl_t *cmdtp, struct pxe_menu *cfg)
+{
+ struct list_head *pos;
+ struct pxe_label *label;
+
+ list_for_each(pos, &cfg->labels) {
+ label = list_entry(pos, struct pxe_label, list);
+
+ if (!label->attempted)
+ label_boot(cmdtp, label);
+ }
+}
+
+/*
+ * Boot the system as prescribed by a pxe_menu.
+ *
+ * Use the menu system to either get the user's choice or the default, based
+ * on config or user input. If there is no default or user's choice,
+ * attempted to boot labels in the order they were given in pxe files.
+ * If the default or user's choice fails to boot, attempt to boot other
+ * labels in the order they were given in pxe files.
+ *
+ * If this function returns, there weren't any labels that successfully
+ * booted, or the user interrupted the menu selection via ctrl+c.
+ */
+void handle_pxe_menu(cmd_tbl_t *cmdtp, struct pxe_menu *cfg)
+{
+ void *choice;
+ struct menu *m;
+ int err;
+
+#ifdef CONFIG_CMD_BMP
+ /* display BMP if available */
+ if (cfg->bmp) {
+ if (get_relfile(cmdtp, cfg->bmp, load_addr)) {
+ run_command("cls", 0);
+ bmp_display(load_addr,
+ BMP_ALIGN_CENTER, BMP_ALIGN_CENTER);
+ } else {
+ printf("Skipping background bmp %s for failure\n",
+ cfg->bmp);
+ }
+ }
+#endif
+
+ m = pxe_menu_to_menu(cfg);
+ if (!m)
+ return;
+
+ err = menu_get_choice(m, &choice);
+
+ menu_destroy(m);
+
+ /*
+ * err == 1 means we got a choice back from menu_get_choice.
+ *
+ * err == -ENOENT if the menu was setup to select the default but no
+ * default was set. in that case, we should continue trying to boot
+ * labels that haven't been attempted yet.
+ *
+ * otherwise, the user interrupted or there was some other error and
+ * we give up.
+ */
+
+ if (err == 1) {
+ err = label_boot(cmdtp, choice);
+ if (!err)
+ return;
+ } else if (err != -ENOENT) {
+ return;
+ }
+
+ boot_unattempted_labels(cmdtp, cfg);
+}
diff --git a/cmd/pxe_utils.h b/cmd/pxe_utils.h
new file mode 100644
index 0000000000..a38ac81a47
--- /dev/null
+++ b/cmd/pxe_utils.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __PXE_UTILS_H
+#define __PXE_UTILS_H
+
+/*
+ * A note on the pxe file parser.
+ *
+ * We're parsing files that use syslinux grammar, which has a few quirks.
+ * String literals must be recognized based on context - there is no
+ * quoting or escaping support. There's also nothing to explicitly indicate
+ * when a label section completes. We deal with that by ending a label
+ * section whenever we see a line that doesn't include.
+ *
+ * As with the syslinux family, this same file format could be reused in the
+ * future for non pxe purposes. The only action it takes during parsing that
+ * would throw this off is handling of include files. It assumes we're using
+ * pxe, and does a tftp download of a file listed as an include file in the
+ * middle of the parsing operation. That could be handled by refactoring it to
+ * take a 'include file getter' function.
+ */
+
+/*
+ * Describes a single label given in a pxe file.
+ *
+ * Create these with the 'label_create' function given below.
+ *
+ * name - the name of the menu as given on the 'menu label' line.
+ * kernel - the path to the kernel file to use for this label.
+ * append - kernel command line to use when booting this label
+ * initrd - path to the initrd to use for this label.
+ * attempted - 0 if we haven't tried to boot this label, 1 if we have.
+ * localboot - 1 if this label specified 'localboot', 0 otherwise.
+ * list - lets these form a list, which a pxe_menu struct will hold.
+ */
+struct pxe_label {
+ char num[4];
+ char *name;
+ char *menu;
+ char *kernel;
+ char *config;
+ char *append;
+ char *initrd;
+ char *fdt;
+ char *fdtdir;
+ int ipappend;
+ int attempted;
+ int localboot;
+ int localboot_val;
+ struct list_head list;
+};
+
+/*
+ * Describes a pxe menu as given via pxe files.
+ *
+ * title - the name of the menu as given by a 'menu title' line.
+ * default_label - the name of the default label, if any.
+ * bmp - the bmp file name which is displayed in background
+ * timeout - time in tenths of a second to wait for a user key-press before
+ * booting the default label.
+ * prompt - if 0, don't prompt for a choice unless the timeout period is
+ * interrupted. If 1, always prompt for a choice regardless of
+ * timeout.
+ * labels - a list of labels defined for the menu.
+ */
+struct pxe_menu {
+ char *title;
+ char *default_label;
+ char *bmp;
+ int timeout;
+ int prompt;
+ struct list_head labels;
+};
+
+extern bool is_pxe;
+
+extern int (*do_getfile)(cmd_tbl_t *cmdtp, const char *file_path,
+ char *file_addr);
+void destroy_pxe_menu(struct pxe_menu *cfg);
+int get_pxe_file(cmd_tbl_t *cmdtp, const char *file_path,
+ unsigned long file_addr);
+int get_pxelinux_path(cmd_tbl_t *cmdtp, const char *file,
+ unsigned long pxefile_addr_r);
+void handle_pxe_menu(cmd_tbl_t *cmdtp, struct pxe_menu *cfg);
+struct pxe_menu *parse_pxefile(cmd_tbl_t *cmdtp, unsigned long menucfg);
+int format_mac_pxe(char *outbuf, size_t outbuf_len);
+
+#endif /* __PXE_UTILS_H */
diff --git a/cmd/sysboot.c b/cmd/sysboot.c
new file mode 100644
index 0000000000..793d67d2f5
--- /dev/null
+++ b/cmd/sysboot.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <command.h>
+#include <env.h>
+#include <fs.h>
+#include "pxe_utils.h"
+
+static char *fs_argv[5];
+
+static int do_get_ext2(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
+{
+#ifdef CONFIG_CMD_EXT2
+ fs_argv[0] = "ext2load";
+ fs_argv[3] = file_addr;
+ fs_argv[4] = (void *)file_path;
+
+ if (!do_ext2load(cmdtp, 0, 5, fs_argv))
+ return 1;
+#endif
+ return -ENOENT;
+}
+
+static int do_get_fat(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
+{
+#ifdef CONFIG_CMD_FAT
+ fs_argv[0] = "fatload";
+ fs_argv[3] = file_addr;
+ fs_argv[4] = (void *)file_path;
+
+ if (!do_fat_fsload(cmdtp, 0, 5, fs_argv))
+ return 1;
+#endif
+ return -ENOENT;
+}
+
+static int do_get_any(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
+{
+#ifdef CONFIG_CMD_FS_GENERIC
+ fs_argv[0] = "load";
+ fs_argv[3] = file_addr;
+ fs_argv[4] = (void *)file_path;
+
+ if (!do_load(cmdtp, 0, 5, fs_argv, FS_TYPE_ANY))
+ return 1;
+#endif
+ return -ENOENT;
+}
+
+/*
+ * Boots a system using a local disk syslinux/extlinux file
+ *
+ * Returns 0 on success, 1 on error.
+ */
+static int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long pxefile_addr_r;
+ struct pxe_menu *cfg;
+ char *pxefile_addr_str;
+ char *filename;
+ int prompt = 0;
+
+ is_pxe = false;
+
+ if (argc > 1 && strstr(argv[1], "-p")) {
+ prompt = 1;
+ argc--;
+ argv++;
+ }
+
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ if (argc < 5) {
+ pxefile_addr_str = from_env("pxefile_addr_r");
+ if (!pxefile_addr_str)
+ return 1;
+ } else {
+ pxefile_addr_str = argv[4];
+ }
+
+ if (argc < 6) {
+ filename = env_get("bootfile");
+ } else {
+ filename = argv[5];
+ env_set("bootfile", filename);
+ }
+
+ if (strstr(argv[3], "ext2")) {
+ do_getfile = do_get_ext2;
+ } else if (strstr(argv[3], "fat")) {
+ do_getfile = do_get_fat;
+ } else if (strstr(argv[3], "any")) {
+ do_getfile = do_get_any;
+ } else {
+ printf("Invalid filesystem: %s\n", argv[3]);
+ return 1;
+ }
+ fs_argv[1] = argv[1];
+ fs_argv[2] = argv[2];
+
+ if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
+ printf("Invalid pxefile address: %s\n", pxefile_addr_str);
+ return 1;
+ }
+
+ if (get_pxe_file(cmdtp, filename, pxefile_addr_r) < 0) {
+ printf("Error reading config file\n");
+ return 1;
+ }
+
+ cfg = parse_pxefile(cmdtp, pxefile_addr_r);
+
+ if (!cfg) {
+ printf("Error parsing config file\n");
+ return 1;
+ }
+
+ if (prompt)
+ cfg->prompt = 1;
+
+ handle_pxe_menu(cmdtp, cfg);
+
+ destroy_pxe_menu(cfg);
+
+ return 0;
+}
+
+U_BOOT_CMD(sysboot, 7, 1, do_sysboot,
+ "command to get and boot from syslinux files",
+ "[-p] <interface> <dev[:part]> <ext2|fat|any> [addr] [filename]\n"
+ " - load and parse syslinux menu file 'filename' from ext2, fat\n"
+ " or any filesystem on 'dev' on 'interface' to address 'addr'"
+);
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 6834399039..02cf5c6241 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -467,6 +467,41 @@ int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
}
return 0;
}
+
+int fdt_set_usable_memory(void *blob, u64 start[], u64 size[], int areas)
+{
+ int err, nodeoffset;
+ int len;
+ u8 tmp[8 * 16]; /* Up to 64-bit address + 64-bit size */
+
+ if (areas > 8) {
+ printf("%s: num areas %d exceeds hardcoded limit %d\n",
+ __func__, areas, 8);
+ return -1;
+ }
+
+ err = fdt_check_header(blob);
+ if (err < 0) {
+ printf("%s: %s\n", __func__, fdt_strerror(err));
+ return err;
+ }
+
+ /* find or create "/memory" node. */
+ nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory");
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ len = fdt_pack_reg(blob, tmp, start, size, areas);
+
+ err = fdt_setprop(blob, nodeoffset, "linux,usable-memory", tmp, len);
+ if (err < 0) {
+ printf("WARNING: could not set %s %s.\n",
+ "reg", fdt_strerror(err));
+ return err;
+ }
+
+ return 0;
+}
#endif
int fdt_fixup_memory(void *blob, u64 start, u64 size)
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index c8cb715c3a..a72412718b 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -439,6 +439,13 @@ config SPL_FIT_IMAGE_TINY
ensure this information is available to the next image
invoked).
+config SPL_CACHE_SUPPORT
+ bool "Support CACHE drivers"
+ help
+ Enable CACHE drivers in SPL. These drivers can keep data so that
+ future requests for that data can be served faster. Enable this option
+ to build the drivers in drivers/cache as part of an SPL build.
+
config SPL_CPU_SUPPORT
bool "Support CPU drivers"
help
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 24da164b43..d51dbe9942 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -264,9 +264,9 @@ int spl_parse_image_header(struct spl_image_info *spl_image,
spl_image->entry_point = image_get_ep(header);
spl_image->size = image_get_data_size(header);
} else {
- spl_image->entry_point = image_get_ep(header);
+ spl_image->entry_point = image_get_load(header);
/* Load including the header */
- spl_image->load_addr = image_get_load(header) -
+ spl_image->load_addr = spl_image->entry_point -
header_size;
spl_image->size = image_get_data_size(header) +
header_size;
diff --git a/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c
index 2345f949f0..6404373eca 100644
--- a/common/spl/spl_opensbi.c
+++ b/common/spl/spl_opensbi.c
@@ -70,14 +70,25 @@ void spl_invoke_opensbi(struct spl_image_info *spl_image)
opensbi_info.next_addr = uboot_entry;
opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S;
opensbi_info.options = SBI_SCRATCH_NO_BOOT_PRINTS;
+ opensbi_info.boot_hart = gd->arch.boot_hart;
opensbi_entry = (void (*)(ulong, ulong, ulong))spl_image->entry_point;
invalidate_icache_all();
#ifdef CONFIG_SMP
+ /*
+ * Start OpenSBI on all secondary harts and wait for acknowledgment.
+ *
+ * OpenSBI first relocates itself to its link address. This is done by
+ * the main hart. To make sure no hart is still running U-Boot SPL
+ * during relocation, we wait for all secondary harts to acknowledge
+ * the call-function request before entering OpenSBI on the main hart.
+ * Otherwise, code corruption can occur if the link address ranges of
+ * U-Boot SPL and OpenSBI overlap.
+ */
ret = smp_call_function((ulong)spl_image->entry_point,
(ulong)spl_image->fdt_addr,
- (ulong)&opensbi_info);
+ (ulong)&opensbi_info, 1);
if (ret)
hang();
#endif
diff --git a/configs/ae350_rv32_spl_defconfig b/configs/ae350_rv32_spl_defconfig
new file mode 100644
index 0000000000..8bd6a2638b
--- /dev/null
+++ b/configs/ae350_rv32_spl_defconfig
@@ -0,0 +1,38 @@
+CONFIG_RISCV=y
+CONFIG_SPL=y
+CONFIG_RISCV_SMODE=y
+CONFIG_SYS_TEXT_BASE=0x01200000
+CONFIG_NR_DRAM_BANKS=2
+CONFIG_TARGET_AX25_AE350=y
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_FIT=y
+CONFIG_BOOTDELAY=3
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SYS_PROMPT="RISC-V # "
+CONFIG_CMD_IMLS=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SF_TEST=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_BOOTP_PREFER_SERVERIP=y
+CONFIG_CMD_CACHE=y
+CONFIG_OF_PRIOR_STAGE=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_MMC=y
+CONFIG_FTSDC010=y
+CONFIG_FTSDC010_SDIO=y
+CONFIG_MTD_NOR_FLASH=y
+CONFIG_FLASH_CFI_DRIVER=y
+CONFIG_CFI_FLASH=y
+CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
+CONFIG_SYS_FLASH_CFI=y
+CONFIG_SPI_FLASH=y
+CONFIG_SF_DEFAULT_MODE=0x0
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_FTMAC100=y
+CONFIG_BAUDRATE=38400
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_ATCSPI200_SPI=y
diff --git a/configs/ae350_rv32_spl_xip_defconfig b/configs/ae350_rv32_spl_xip_defconfig
new file mode 100644
index 0000000000..9c605fe907
--- /dev/null
+++ b/configs/ae350_rv32_spl_xip_defconfig
@@ -0,0 +1,40 @@
+CONFIG_RISCV=y
+CONFIG_SPL=y
+CONFIG_RISCV_SMODE=y
+CONFIG_SPL_TEXT_BASE=0x80000000
+CONFIG_SYS_TEXT_BASE=0x01200000
+CONFIG_NR_DRAM_BANKS=2
+CONFIG_TARGET_AX25_AE350=y
+CONFIG_XIP=y
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_FIT=y
+CONFIG_BOOTDELAY=3
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SYS_PROMPT="RISC-V # "
+CONFIG_CMD_IMLS=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SF_TEST=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_BOOTP_PREFER_SERVERIP=y
+CONFIG_CMD_CACHE=y
+CONFIG_OF_BOARD=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_MMC=y
+CONFIG_FTSDC010=y
+CONFIG_FTSDC010_SDIO=y
+CONFIG_MTD_NOR_FLASH=y
+CONFIG_FLASH_CFI_DRIVER=y
+CONFIG_CFI_FLASH=y
+CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
+CONFIG_SYS_FLASH_CFI=y
+CONFIG_SPI_FLASH=y
+CONFIG_SF_DEFAULT_MODE=0x0
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_FTMAC100=y
+CONFIG_BAUDRATE=38400
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_ATCSPI200_SPI=y
diff --git a/configs/ae350_rv64_spl_defconfig b/configs/ae350_rv64_spl_defconfig
new file mode 100644
index 0000000000..806f327610
--- /dev/null
+++ b/configs/ae350_rv64_spl_defconfig
@@ -0,0 +1,39 @@
+CONFIG_RISCV=y
+CONFIG_SPL=y
+CONFIG_RISCV_SMODE=y
+CONFIG_SYS_TEXT_BASE=0x01200000
+CONFIG_NR_DRAM_BANKS=2
+CONFIG_TARGET_AX25_AE350=y
+CONFIG_ARCH_RV64I=y
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_FIT=y
+CONFIG_BOOTDELAY=3
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SYS_PROMPT="RISC-V # "
+CONFIG_CMD_IMLS=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SF_TEST=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_BOOTP_PREFER_SERVERIP=y
+CONFIG_CMD_CACHE=y
+CONFIG_OF_PRIOR_STAGE=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_MMC=y
+CONFIG_FTSDC010=y
+CONFIG_FTSDC010_SDIO=y
+CONFIG_MTD_NOR_FLASH=y
+CONFIG_FLASH_CFI_DRIVER=y
+CONFIG_CFI_FLASH=y
+CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
+CONFIG_SYS_FLASH_CFI=y
+CONFIG_SPI_FLASH=y
+CONFIG_SF_DEFAULT_MODE=0x0
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_FTMAC100=y
+CONFIG_BAUDRATE=38400
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_ATCSPI200_SPI=y
diff --git a/configs/ae350_rv64_spl_xip_defconfig b/configs/ae350_rv64_spl_xip_defconfig
new file mode 100644
index 0000000000..1bacc5f36b
--- /dev/null
+++ b/configs/ae350_rv64_spl_xip_defconfig
@@ -0,0 +1,41 @@
+CONFIG_RISCV=y
+CONFIG_SPL=y
+CONFIG_RISCV_SMODE=y
+CONFIG_SPL_TEXT_BASE=0x80000000
+CONFIG_SYS_TEXT_BASE=0x01200000
+CONFIG_NR_DRAM_BANKS=2
+CONFIG_TARGET_AX25_AE350=y
+CONFIG_ARCH_RV64I=y
+CONFIG_XIP=y
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_FIT=y
+CONFIG_BOOTDELAY=3
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SYS_PROMPT="RISC-V # "
+CONFIG_CMD_IMLS=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SF_TEST=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_BOOTP_PREFER_SERVERIP=y
+CONFIG_CMD_CACHE=y
+CONFIG_OF_BOARD=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_MMC=y
+CONFIG_FTSDC010=y
+CONFIG_FTSDC010_SDIO=y
+CONFIG_MTD_NOR_FLASH=y
+CONFIG_FLASH_CFI_DRIVER=y
+CONFIG_CFI_FLASH=y
+CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
+CONFIG_SYS_FLASH_CFI=y
+CONFIG_SPI_FLASH=y
+CONFIG_SF_DEFAULT_MODE=0x0
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_FTMAC100=y
+CONFIG_BAUDRATE=38400
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_ATCSPI200_SPI=y
diff --git a/configs/evb-px5_defconfig b/configs/evb-px5_defconfig
index f9b17be10e..2d18da6cc8 100644
--- a/configs/evb-px5_defconfig
+++ b/configs/evb-px5_defconfig
@@ -45,7 +45,7 @@ CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names interrupt-parent"
CONFIG_TPL_OF_PLATDATA=y
CONFIG_ENV_IS_IN_MMC=y
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
-CONFIG_NET_RANDOM_ETHADDR=y
+# CONFIG_NET is not set
CONFIG_TPL_DM=y
CONFIG_REGMAP=y
CONFIG_SPL_REGMAP=y
diff --git a/configs/firefly-px30_defconfig b/configs/firefly-px30_defconfig
new file mode 100644
index 0000000000..fa4ac75b09
--- /dev/null
+++ b/configs/firefly-px30_defconfig
@@ -0,0 +1,113 @@
+CONFIG_ARM=y
+CONFIG_ARCH_ROCKCHIP=y
+CONFIG_SYS_TEXT_BASE=0x00200000
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_ROCKCHIP_PX30=y
+CONFIG_TARGET_EVB_PX30=y
+CONFIG_TPL_LIBGENERIC_SUPPORT=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_SPL_STACK_R_ADDR=0x600000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_DEBUG_UART_BASE=0xFF160000
+CONFIG_DEBUG_UART_CLOCK=24000000
+CONFIG_DEBUG_UART=y
+CONFIG_SPL_TEXT_BASE=0x00000000
+CONFIG_TPL_SYS_MALLOC_F_LEN=0x600
+# CONFIG_ANDROID_BOOT_IMAGE is not set
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_SPL_LOAD_FIT=y
+# CONFIG_CONSOLE_MUX is not set
+CONFIG_DEFAULT_FDT_FILE="rockchip/px30-evb.dtb"
+CONFIG_MISC_INIT_R=y
+# CONFIG_DISPLAY_CPUINFO is not set
+CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_SPL_BOOTROM_SUPPORT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
+CONFIG_SPL_STACK_R=y
+# CONFIG_TPL_BANNER_PRINT is not set
+CONFIG_SPL_CRC32_SUPPORT=y
+CONFIG_SPL_ATF=y
+# CONFIG_TPL_FRAMEWORK is not set
+# CONFIG_CMD_BOOTD is not set
+CONFIG_DEBUG_UART2_CHANNEL=1
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_LZMADEC is not set
+# CONFIG_CMD_UNZIP is not set
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPT=y
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_USB_MASS_STORAGE=y
+# CONFIG_CMD_ITEST is not set
+# CONFIG_CMD_SETEXPR is not set
+# CONFIG_CMD_MISC is not set
+# CONFIG_SPL_DOS_PARTITION is not set
+# CONFIG_ISO_PARTITION is not set
+CONFIG_EFI_PARTITION_ENTRIES_NUMBERS=64
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_OF_LIVE=y
+CONFIG_DEFAULT_DEVICE_TREE="px30-evb"
+CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
+CONFIG_CLK=y
+CONFIG_SPL_CLK=y
+CONFIG_FASTBOOT_BUF_ADDR=0x800800
+CONFIG_FASTBOOT_BUF_SIZE=0x04000000
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=0
+CONFIG_ROCKCHIP_GPIO=y
+CONFIG_SYS_I2C_ROCKCHIP=y
+CONFIG_MISC=y
+CONFIG_ROCKCHIP_OTP=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_ROCKCHIP=y
+CONFIG_PHY_REALTEK=y
+CONFIG_DM_ETH=y
+CONFIG_ETH_DESIGNWARE=y
+CONFIG_GMAC_ROCKCHIP=y
+CONFIG_PINCTRL=y
+CONFIG_DM_PMIC=y
+CONFIG_PMIC_RK8XX=y
+CONFIG_REGULATOR_PWM=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_REGULATOR_RK8XX=y
+CONFIG_PWM_ROCKCHIP=y
+CONFIG_RAM=y
+CONFIG_SPL_RAM=y
+CONFIG_TPL_RAM=y
+CONFIG_ROCKCHIP_SDRAM_COMMON=y
+CONFIG_DM_RESET=y
+# CONFIG_SPECIFY_CONSOLE_INDEX is not set
+# CONFIG_TPL_DM_SERIAL is not set
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_DEBUG_UART_SKIP_INIT=y
+CONFIG_SOUND=y
+CONFIG_SYSRESET=y
+CONFIG_OPTEE=y
+CONFIG_DM_THERMAL=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_GENERIC=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DWC2_OTG=y
+CONFIG_DM_VIDEO=y
+CONFIG_DISPLAY=y
+CONFIG_LCD=y
+CONFIG_SPL_TINY_MEMSET=y
+CONFIG_TPL_TINY_MEMSET=y
+CONFIG_LZ4=y
+CONFIG_LZO=y
+CONFIG_ERRNO_STR=y
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig
index 61d28db803..daa661384d 100644
--- a/configs/j721e_evm_a72_defconfig
+++ b/configs/j721e_evm_a72_defconfig
@@ -51,6 +51,7 @@ CONFIG_DEFAULT_DEVICE_TREE="k3-j721e-common-proc-board"
CONFIG_SPL_MULTI_DTB_FIT=y
CONFIG_SPL_MULTI_DTB_FIT_NO_COMPRESSION=y
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_DM=y
CONFIG_SPL_DM=y
CONFIG_SPL_DM_SEQ_ALIAS=y
@@ -61,6 +62,8 @@ CONFIG_SPL_OF_TRANSLATE=y
CONFIG_CLK=y
CONFIG_SPL_CLK=y
CONFIG_CLK_TI_SCI=y
+CONFIG_DMA_CHANNELS=y
+CONFIG_TI_K3_NAVSS_UDMA=y
CONFIG_TI_SCI_PROTOCOL=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
@@ -79,6 +82,10 @@ CONFIG_SYS_FLASH_CFI=y
CONFIG_HBMC_AM654=y
CONFIG_DM_SPI_FLASH=y
CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_PHY_TI=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_TI_AM65_CPSW_NUSS=y
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_GENERIC is not set
CONFIG_SPL_PINCTRL=y
@@ -93,6 +100,7 @@ CONFIG_RESET_TI_SCI=y
CONFIG_SCSI=y
CONFIG_DM_SCSI=y
CONFIG_DM_SERIAL=y
+CONFIG_SOC_TI=y
CONFIG_SPI=y
CONFIG_DM_SPI=y
CONFIG_CADENCE_QSPI=y
diff --git a/configs/rock64-rk3328_defconfig b/configs/rock64-rk3328_defconfig
index 14c77b0a4e..720b5e0424 100644
--- a/configs/rock64-rk3328_defconfig
+++ b/configs/rock64-rk3328_defconfig
@@ -19,6 +19,7 @@ CONFIG_FIT=y
CONFIG_FIT_VERBOSE=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_DEFAULT_FDT_FILE="rockchip/rk3328-rock64.dtb"
+CONFIG_MISC_INIT_R=y
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_DISPLAY_BOARDINFO_LATE=y
# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
diff --git a/configs/sifive_fu540_defconfig b/configs/sifive_fu540_defconfig
index 48eccd766b..7d38ec9a70 100644
--- a/configs/sifive_fu540_defconfig
+++ b/configs/sifive_fu540_defconfig
@@ -7,8 +7,9 @@ CONFIG_RISCV_SMODE=y
CONFIG_DISTRO_DEFAULTS=y
CONFIG_FIT=y
CONFIG_MISC_INIT_R=y
+CONFIG_DEFAULT_DEVICE_TREE="hifive-unleashed-a00"
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y
-CONFIG_OF_PRIOR_STAGE=y
+CONFIG_OF_SEPARATE=y
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_DM_MTD=y
diff --git a/configs/vining_2000_defconfig b/configs/vining_2000_defconfig
index 1ff5acb730..c1542fe5d3 100644
--- a/configs/vining_2000_defconfig
+++ b/configs/vining_2000_defconfig
@@ -1,18 +1,32 @@
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_SYS_TEXT_BASE=0x87800000
+CONFIG_SPL_GPIO_SUPPORT=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_MX6_DDRCAL=y
CONFIG_TARGET_SOFTING_VINING_2000=y
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_SPL_SERIAL_SUPPORT=y
CONFIG_ENV_SIZE=0x2000
CONFIG_ENV_OFFSET=0x80000
CONFIG_NR_DRAM_BANKS=1
+CONFIG_SPL=y
+CONFIG_SPL_LIBDISK_SUPPORT=y
# CONFIG_CMD_BMODE is not set
+CONFIG_SPL_TEXT_BASE=0x00908000
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/softing/vining_2000/imximage.cfg"
CONFIG_BOOTDELAY=0
CONFIG_SYS_CONSOLE_IS_IN_ENV=y
CONFIG_SUPPORT_RAW_INITRD=y
CONFIG_BOUNCE_BUFFER=y
CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SPL_FS_EXT4=y
+CONFIG_SPL_I2C_SUPPORT=y
+CONFIG_SPL_WATCHDOG_SUPPORT=y
CONFIG_HUSH_PARSER=y
CONFIG_CMD_BOOTZ=y
CONFIG_CMD_GPIO=y
@@ -46,13 +60,15 @@ CONFIG_SUPPORT_EMMC_RPMB=y
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_FSL_USDHC=y
CONFIG_PHYLIB=y
+CONFIG_PHY_SMSC=y
+CONFIG_DM_ETH=y
+CONFIG_FEC_MXC=y
CONFIG_MII=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_IMX6=y
CONFIG_PWM_IMX=y
-CONFIG_SPECIFY_CONSOLE_INDEX=y
CONFIG_DM_SERIAL=y
CONFIG_MXC_UART=y
CONFIG_USB=y
diff --git a/configs/warp7_defconfig b/configs/warp7_defconfig
index eb58077e5d..d31ca28fff 100644
--- a/configs/warp7_defconfig
+++ b/configs/warp7_defconfig
@@ -3,7 +3,7 @@ CONFIG_ARCH_MX7=y
CONFIG_SYS_TEXT_BASE=0x87800000
CONFIG_TARGET_WARP7=y
CONFIG_ENV_SIZE=0x2000
-CONFIG_ENV_OFFSET=0x80000
+CONFIG_ENV_OFFSET=0xC0000
CONFIG_NR_DRAM_BANKS=1
CONFIG_ARMV7_BOOT_SEC_DEFAULT=y
# CONFIG_ARMV7_VIRT is not set
diff --git a/doc/README.asn1 b/doc/README.asn1
new file mode 100644
index 0000000000..1359b93aef
--- /dev/null
+++ b/doc/README.asn1
@@ -0,0 +1,40 @@
+ASN1
+====
+
+Abstract Syntax Notation One (or ASN1) is a standard by ITU-T and ISO/IEC
+and used as a description language for defining data structure in
+an independent manner.
+Any data described in ASN1 notation can be serialized (or encoded) and
+de-serialized (or decoded) with well-defined encoding rules.
+
+A combination of ASN1 compiler and ASN1 decoder library function will
+provide a function interface for parsing encoded binary into specific
+data structure:
+1) define data structure in a text file (*.asn1)
+2) define "action" routines for specific "tags" defined in (1)
+3) generate bytecode as a C file (*.asn1.[ch]) from *.asn1 file
+ with ASN1 compiler (tools/asn1_compiler)
+4) call a ASN1 decoder (asn1_ber_decoder()) with bytecode and data
+
+Usage of ASN1 compiler
+----------------------
+ asn1_compiler [-v] [-d] <grammar-file> <c-file> <hdr-file>
+
+ <grammar-file>: ASN1 input file
+ <c-file>: generated C file
+ <hdr-file>: generated include file
+
+Usage of ASN1 decoder
+---------------------
+ int asn1_ber_decoder(const struct asn1_decoder *decoder, void *context,
+ const unsigned char *data, size_t datalen);
+
+ @decoder: bytecode binary
+ @context: context for decoder
+ @data: data to be parsed
+ @datalen: size of data
+
+
+As of writing this, ASN1 compiler and decoder are used to implement
+X509 certificate parser, pcks7 message parser and RSA public key parser
+for UEFI secure boot.
diff --git a/doc/README.enetaddr b/doc/README.enetaddr
index f926485986..5baa9f2179 100644
--- a/doc/README.enetaddr
+++ b/doc/README.enetaddr
@@ -76,12 +76,12 @@ To assist in the management of these layers, a few helper functions exist. You
should use these rather than attempt to do any kind of parsing/manipulation
yourself as many common errors have arisen in the past.
- * void eth_parse_enetaddr(const char *addr, uchar *enetaddr);
+ * void string_to_enetaddr(const char *addr, uchar *enetaddr);
Convert a string representation of a MAC address to the binary version.
char *addr = "00:11:22:33:44:55";
uchar enetaddr[6];
-eth_parse_enetaddr(addr, enetaddr);
+string_to_enetaddr(addr, enetaddr);
/* enetaddr now equals { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } */
* int eth_env_get_enetaddr(char *name, uchar *enetaddr);
diff --git a/doc/README.rockchip b/doc/README.rockchip
index 67c14006a3..dae4ebc8e4 100644
--- a/doc/README.rockchip
+++ b/doc/README.rockchip
@@ -108,7 +108,6 @@ For example:
=> export BL31=/path/to/rkbin/bin/rk33/rk3308_bl31_v2.22.elf
=> make roc-rk3308-cc_defconfig
=> make CROSS_COMPILE=aarch64-linux-gnu- all
- => make CROSS_COMPILE=aarch64-linux-gnu- u-boot.itb
=> ./tools/mkimage -n rk3308 -T rksd -d /path/to/rkbin/bin/rk33/rk3308_ddr_589MHz_uart2_m0_v1.26.bin idbloader.img
=> cat spl/u-boot-spl.bin >> idbloader.img
diff --git a/doc/board/AndesTech/ax25-ae350.rst b/doc/board/AndesTech/ax25-ae350.rst
index 7a0189382d..a7bd1a75e8 100644
--- a/doc/board/AndesTech/ax25-ae350.rst
+++ b/doc/board/AndesTech/ax25-ae350.rst
@@ -324,6 +324,209 @@ Boot bbl and riscv-linux via U-Boot on QEMU
/ #
-TODO
-----
-Boot bbl and riscv-linux via U-Boot on AE350 board
+Running U-Boot SPL
+------------------
+The U-Boot SPL will boot in M mode and load the FIT image which include
+OpenSBI and U-Boot proper images. After loading progress, it will jump
+to OpenSBI first and then U-Boot proper which will run in S mode.
+
+
+How to build U-Boot SPL
+-----------------------
+Before building U-Boot SPL, OpenSBI must be build first. OpenSBI can be
+cloned and build for AE350 as below:
+
+git clone https://github.com/riscv/opensbi.git
+cd opensbi
+make PLATFORM=andes/ae350
+
+Copy OpenSBI FW_DYNAMIC image (build\platform\andes\ae350\firmware\fw_dynamic.bin)
+into U-Boot root directory
+
+
+How to build U-Boot SPL booting from RAM
+----------------------------------------
+With ae350_rv[32|64]_spl_defconfigs:
+
+U-Boot SPL will be loaded by gdb or FSBL and runs in RAM in machine mode
+and then load FIT image from RAM device on AE350.
+
+
+How to build U-Boot SPL booting from ROM
+----------------------------------------
+With ae350_rv[32|64]_spl_xip_defconfigs:
+
+U-Boot SPL can be burned into SPI flash and run in flash in machine mode
+and then load FIT image from SPI flash or MMC device on AE350.
+
+
+Messages of U-Boot SPL boots Kernel on AE350 board
+--------------------------------------------------
+
+.. code-block:: none
+
+U-Boot SPL 2020.01-rc1-00292-g67a3313-dirty (Nov 14 2019 - 11:26:21 +0800)
+Trying to boot from RAM
+
+OpenSBI v0.5-1-gdd8ef28 (Nov 14 2019 11:08:39)
+ ____ _____ ____ _____
+ / __ \ / ____| _ \_ _|
+ | | | |_ __ ___ _ __ | (___ | |_) || |
+ | | | | '_ \ / _ \ '_ \ \___ \| _ < | |
+ | |__| | |_) | __/ | | |____) | |_) || |_
+ \____/| .__/ \___|_| |_|_____/|____/_____|
+ | |
+ |_|
+
+Platform Name : Andes AE350
+Platform HART Features : RV64ACIMSUX
+Platform Max HARTs : 4
+Current Hart : 0
+Firmware Base : 0x0
+Firmware Size : 84 KB
+Runtime SBI Version : 0.2
+
+PMP0: 0x0000000000000000-0x000000000001ffff (A)
+PMP1: 0x0000000000000000-0x00000001ffffffff (A,R,W,X)
+
+
+U-Boot 2020.01-rc1-00292-g67a3313-dirty (Nov 14 2019 - 11:26:21 +0800)
+
+DRAM: 1 GiB
+Flash: 64 MiB
+MMC: mmc@f0e00000: 0
+Loading Environment from SPI Flash... SF: Detected mx25u1635e with page size 256 Bytes, erase size 4 KiB, total 2 MiB
+OK
+In: serial@f0300000
+Out: serial@f0300000
+Err: serial@f0300000
+Net: no alias for ethernet0
+
+Warning: mac@e0100000 (eth0) using random MAC address - a2:ae:93:7b:cc:8f
+eth0: mac@e0100000
+Hit any key to stop autoboot: 0
+6455 bytes read in 31 ms (203.1 KiB/s)
+20421684 bytes read in 8647 ms (2.3 MiB/s)
+## Booting kernel from Legacy Image at 00600000 ...
+ Image Name:
+ Image Type: RISC-V Linux Kernel Image (uncompressed)
+ Data Size: 20421620 Bytes = 19.5 MiB
+ Load Address: 00200000
+ Entry Point: 00200000
+ Verifying Checksum ... OK
+## Flattened Device Tree blob at 20000000
+ Booting using the fdt blob at 0x20000000
+ Loading Kernel Image
+ Loading Device Tree to 000000001effb000, end 000000001efff936 ... OK
+
+Starting kernel ...
+
+OF: fdt: Ignoring memory range 0x0 - 0x200000
+Linux version 4.17.0-00253-g49136e10bcb2 (sqa@atcsqa07) (gcc version 7.3.0 (2019-04-06_nds64le-linux-glibc-v5_experimental)) #1 SMP PREEMPT Sat Apr 6 23:41:49 CST 2019
+bootconsole [early0] enabled
+Initial ramdisk at: 0x (ptrval) (13665712 bytes)
+Zone ranges:
+ DMA32 [mem 0x0000000000200000-0x000000003fffffff]
+ Normal empty
+Movable zone start for each node
+Early memory node ranges
+ node 0: [mem 0x0000000000200000-0x000000003fffffff]
+Initmem setup node 0 [mem 0x0000000000200000-0x000000003fffffff]
+software IO TLB [mem 0x3b1f8000-0x3f1f8000] (64MB) mapped at [ (ptrval)- (ptrval)]
+elf_platform is rv64i2p0m2p0a2p0c2p0xv5-0p0
+compatible privileged spec version 1.10
+percpu: Embedded 16 pages/cpu @ (ptrval) s28184 r8192 d29160 u65536
+Built 1 zonelists, mobility grouping on. Total pages: 258055
+Kernel command line: console=ttyS0,38400n8 debug loglevel=7
+log_buf_len individual max cpu contribution: 4096 bytes
+log_buf_len total cpu_extra contributions: 12288 bytes
+log_buf_len min size: 16384 bytes
+log_buf_len: 32768 bytes
+early log buf free: 14608(89%)
+Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes)
+Inode-cache hash table entries: 65536 (order: 7, 524288 bytes)
+Sorting __ex_table...
+Memory: 944428K/1046528K available (3979K kernel code, 246K rwdata, 1490K rodata, 13523K init, 688K bss, 102100K reserved, 0K cma-reserved)
+SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
+Preemptible hierarchical RCU implementation.
+ Tasks RCU enabled.
+NR_IRQS: 72, nr_irqs: 72, preallocated irqs: 0
+riscv,cpu_intc,0: 64 local interrupts mapped
+riscv,cpu_intc,1: 64 local interrupts mapped
+riscv,cpu_intc,2: 64 local interrupts mapped
+riscv,cpu_intc,3: 64 local interrupts mapped
+riscv,plic0,e4000000: mapped 71 interrupts to 8/8 handlers
+clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x1bacf917bf, max_idle_ns: 881590412290 ns
+sched_clock: 64 bits at 60MHz, resolution 16ns, wraps every 4398046511098ns
+Console: colour dummy device 40x30
+Calibrating delay loop (skipped), value calculated using timer frequency.. 120.00 BogoMIPS (lpj=600000)
+pid_max: default: 32768 minimum: 301
+Mount-cache hash table entries: 2048 (order: 2, 16384 bytes)
+Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes)
+Hierarchical SRCU implementation.
+smp: Bringing up secondary CPUs ...
+CPU0: online
+CPU2: online
+CPU3: online
+smp: Brought up 1 node, 4 CPUs
+devtmpfs: initialized
+random: get_random_u32 called from bucket_table_alloc+0x198/0x1d8 with crng_init=0
+clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
+futex hash table entries: 1024 (order: 4, 65536 bytes)
+NET: Registered protocol family 16
+Advanced Linux Sound Architecture Driver Initialized.
+clocksource: Switched to clocksource riscv_clocksource
+NET: Registered protocol family 2
+tcp_listen_portaddr_hash hash table entries: 512 (order: 1, 8192 bytes)
+TCP established hash table entries: 8192 (order: 4, 65536 bytes)
+TCP bind hash table entries: 8192 (order: 5, 131072 bytes)
+TCP: Hash tables configured (established 8192 bind 8192)
+UDP hash table entries: 512 (order: 2, 16384 bytes)
+UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
+NET: Registered protocol family 1
+RPC: Registered named UNIX socket transport module.
+RPC: Registered udp transport module.
+RPC: Registered tcp transport module.
+RPC: Registered tcp NFSv4.1 backchannel transport module.
+Unpacking initramfs...
+workingset: timestamp_bits=62 max_order=18 bucket_order=0
+NFS: Registering the id_resolver key type
+Key type id_resolver registered
+Key type id_legacy registered
+nfs4filelayout_init: NFSv4 File Layout Driver Registering...
+io scheduler noop registered
+io scheduler cfq registered (default)
+io scheduler mq-deadline registered
+io scheduler kyber registered
+Console: switching to colour frame buffer device 40x30
+Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
+console [ttyS0] disabled
+f0300000.serial: ttyS0 at MMIO 0xf0300020 (irq = 20, base_baud = 1228800) is a 16550A
+console [ttyS0] enabled
+console [ttyS0] enabled
+bootconsole [early0] disabled
+bootconsole [early0] disabled
+loop: module loaded
+tun: Universal TUN/TAP device driver, 1.6
+ftmac100: Loading version 0.2 ...
+ftmac100 e0100000.mac eth0: irq 21, mapped at (ptrval)
+ftmac100 e0100000.mac eth0: generated random MAC address 4e:fd:bd:f3:04:fc
+ftsdc010 f0e00000.mmc: mmc0 - using hw SDIO IRQ
+mmc0: new SDHC card at address d555
+ftssp010 card registered!
+mmcblk0: mmc0:d555 SD04G 3.79 GiB
+NET: Registered protocol family 10
+ mmcblk0: p1
+Segment Routing with IPv6
+sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
+NET: Registered protocol family 17
+NET: Registered protocol family 15
+ALSA device list:
+ #0: ftssp_ac97 controller
+Freeing unused kernel memory: 13520K
+This architecture does not have kernel memory protection.
+Sysinit starting
+Sat Apr 6 23:33:53 CST 2019
+nfs4flexfilelayout_init: NFSv4 Flexfile Layout Driver Registering...
+
+~ #
diff --git a/doc/board/sifive/fu540.rst b/doc/board/sifive/fu540.rst
index 7807f5b2c1..3937222c6c 100644
--- a/doc/board/sifive/fu540.rst
+++ b/doc/board/sifive/fu540.rst
@@ -58,10 +58,7 @@ firmware. We need to compile OpenSBI with below command:
.. code-block:: none
- make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<path to u-boot.bin> FW_PAYLOAD_FDT_PATH=<path to hifive-unleashed-a00.dtb from Linux>
-
-(Note: Prefer hifive-unleashed-a00.dtb from Linux-5.3 or higher)
-(Note: Linux-5.2 is also fine but it does not have ethernet DT node)
+make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<path to u-boot-dtb.bin>
More detailed description of steps required to build FW_PAYLOAD firmware
is beyond the scope of this document. Please refer OpenSBI documenation.
diff --git a/doc/device-tree-bindings/net/aquantia-phy.txt b/doc/device-tree-bindings/net/aquantia-phy.txt
new file mode 100644
index 0000000000..89ce61e05b
--- /dev/null
+++ b/doc/device-tree-bindings/net/aquantia-phy.txt
@@ -0,0 +1,25 @@
+PHY nodes for Aquantia devices.
+
+This text describes properties that are applicable to Aquantia PHY nodes in
+addition to the bindings in phy.txt.
+
+Aquantia PHYs allow some flexibility in the way they are wired in a system,
+they allow MDI pins to be reversed, LEDs linked up in different weays, have an
+I2C slave interface that can be used for debug. Normally the configuration
+corresponding to these is driven by the PHY firmware with the downside that
+a custom firmware is needed for each integration of a PHY.
+Several optional bindings are defined that allow these configuration points to
+be driven by the PHY driver and reduce dependency on specific FW versions.
+
+Optional properties:
+mdi-reversal: 0 or 1 indicating that reversal must be disabled/enabled.
+ Firmware default is used if the property is missing.
+smb-addr: I2C/SMBus address to use, firmware default is used if the property
+ is missing.
+
+Example node:
+phy@00 {
+ reg = <0x00>;
+ mdi-reversal = <1>;
+ smb-addr = <0x25>;
+};
diff --git a/doc/device-tree-bindings/net/phy.txt b/doc/device-tree-bindings/net/phy.txt
new file mode 100644
index 0000000000..6599c667b5
--- /dev/null
+++ b/doc/device-tree-bindings/net/phy.txt
@@ -0,0 +1,24 @@
+PHY nodes
+
+If the device tree is used to describe networking interfaces, U-Boot expects a
+node for each PHY. Parent node for such a PHY node is expected to correspond to
+a MDIO bus and the bus is used to access the PHY.
+
+Required properties:
+
+ - reg : The ID number for the phy, usually a small integer
+
+Example:
+
+ethernet-phy@0 {
+ compatible = "ethernet-phy-id0141.0e90", "ethernet-phy-ieee802.3-c22";
+ interrupt-parent = <&PIC>;
+ interrupts = <35 IRQ_TYPE_EDGE_RISING>;
+ reg = <0>;
+
+ resets = <&rst 8>;
+ reset-names = "phy";
+ reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+ reset-assert-us = <1000>;
+ reset-deassert-us = <2000>;
+};
diff --git a/doc/device-tree-bindings/net/ti,dp83867.txt b/doc/device-tree-bindings/net/ti,dp83867.txt
index 034146f5f8..268220964a 100644
--- a/doc/device-tree-bindings/net/ti,dp83867.txt
+++ b/doc/device-tree-bindings/net/ti,dp83867.txt
@@ -12,8 +12,10 @@ Required properties:
compensate for the board being designed with the lanes swapped.
- enet-phy-no-lane-swap - Indicates that PHY will disable swap of the
TX/RX lanes.
- - ti,clk-output-sel - Clock output select - see dt-bindings/net/ti-dp83867.h
- for applicable values
+ - ti,clk-output-sel - Muxing option for CLK_OUT pin. See dt-bindings/net/ti-dp83867.h
+ for applicable values. The CLK_OUT pin can also
+ be disabled by this property. When omitted, the
+ PHY's default will be left as is.
Default child nodes are standard Ethernet PHY device
nodes as described in doc/devicetree/bindings/net/ethernet.txt
diff --git a/drivers/Makefile b/drivers/Makefile
index 0d1d6bd851..e977f19af6 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -30,6 +30,7 @@ ifndef CONFIG_TPL_BUILD
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_BOOTCOUNT_LIMIT) += bootcount/
+obj-$(CONFIG_SPL_CACHE_SUPPORT) += cache/
obj-$(CONFIG_SPL_CPU_SUPPORT) += cpu/
obj-$(CONFIG_SPL_CRYPTO_SUPPORT) += crypto/
obj-$(CONFIG_SPL_MPC8XXX_INIT_DDR_SUPPORT) += ddr/fsl/
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
index 091b092bbb..a05dac7c7a 100644
--- a/drivers/clk/imx/clk-imx8mm.c
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -74,7 +74,7 @@ static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
static const char *imx8mm_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m",
"sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", };
-static const char *imx8mm_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m", "sys_pll1_400m",
+static const char *imx8mm_ahb_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_800m", "sys_pll1_400m",
"sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", "video_pll1_out", };
static const char *imx8mm_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_250m",
diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
index 0ff56f7e88..5598bca21c 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -187,6 +187,18 @@ int dma_send(struct dma *dma, void *src, size_t len, void *metadata)
return ops->send(dma, src, len, metadata);
}
+
+int dma_get_cfg(struct dma *dma, u32 cfg_id, void **cfg_data)
+{
+ struct dma_ops *ops = dma_dev_ops(dma->dev);
+
+ debug("%s(dma=%p)\n", __func__, dma);
+
+ if (!ops->get_cfg)
+ return -ENOSYS;
+
+ return ops->get_cfg(dma, cfg_id, cfg_data);
+}
#endif /* CONFIG_DMA_CHANNELS */
int dma_get_device(u32 transfer_type, struct udevice **devp)
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index 2e64d338ca..f7128610c5 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -104,6 +104,8 @@ struct udma_chan {
struct udma_rchan *rchan;
struct udma_rflow *rflow;
+ struct ti_udma_drv_chan_cfg_data cfg_data;
+
u32 bcnt; /* number of bytes completed since the start of the channel */
bool pkt_mode; /* TR or packet */
@@ -1407,6 +1409,11 @@ static int udma_request(struct dma *dma)
uc->desc_rx_cur = 0;
uc->num_rx_bufs = 0;
+ if (uc->dir == DMA_DEV_TO_MEM) {
+ uc->cfg_data.flow_id_base = uc->rflow->id;
+ uc->cfg_data.flow_id_cnt = 1;
+ }
+
return 0;
}
@@ -1689,6 +1696,26 @@ int udma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size)
return 0;
}
+static int udma_get_cfg(struct dma *dma, u32 id, void **data)
+{
+ struct udma_dev *ud = dev_get_priv(dma->dev);
+ struct udma_chan *uc;
+
+ if (dma->id >= (ud->rchan_cnt + ud->tchan_cnt)) {
+ dev_err(dma->dev, "invalid dma ch_id %lu\n", dma->id);
+ return -EINVAL;
+ }
+
+ switch (id) {
+ case TI_UDMA_CHAN_PRIV_INFO:
+ uc = &ud->channels[dma->id];
+ *data = &uc->cfg_data;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static const struct dma_ops udma_ops = {
.transfer = udma_transfer,
.of_xlate = udma_of_xlate,
@@ -1699,10 +1726,12 @@ static const struct dma_ops udma_ops = {
.send = udma_send,
.receive = udma_receive,
.prepare_rcv_buf = udma_prepare_rcv_buf,
+ .get_cfg = udma_get_cfg,
};
static const struct udevice_id udma_ids[] = {
{ .compatible = "ti,k3-navss-udmap" },
+ { .compatible = "ti,j721e-navss-mcu-udmap" },
{ }
};
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 4182897d89..142a2c6953 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -298,6 +298,8 @@ config MVPP2
bool "Marvell Armada 375/7K/8K network interface support"
depends on ARMADA_375 || ARMADA_8K
select PHYLIB
+ select MVMDIO
+ select DM_MDIO
help
This driver supports the network interface units in the
Marvell ARMADA 375, 7K and 8K SoCs.
diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
index 0ca7e838a8..02c1ee70d9 100644
--- a/drivers/net/fsl_enetc.c
+++ b/drivers/net/fsl_enetc.c
@@ -156,19 +156,14 @@ static void enetc_start_pcs(struct udevice *dev)
priv->if_type = PHY_INTERFACE_MODE_NONE;
- /* check internal mdio capability, not all ports need it */
+ /* register internal MDIO for debug purposes */
if (enetc_read_port(priv, ENETC_PCAPR0) & ENETC_PCAPRO_MDIO) {
- /*
- * set up internal MDIO, this is part of ETH PCI function and is
- * used to access serdes / internal SoC PHYs.
- * We don't currently register it as a MDIO bus as it goes away
- * when the interface is removed, so it can't practically be
- * used in the console.
- */
priv->imdio.read = enetc_mdio_read;
priv->imdio.write = enetc_mdio_write;
priv->imdio.priv = priv->port_regs + ENETC_PM_IMDIO_BASE;
strncpy(priv->imdio.name, dev->name, MDIO_NAME_LEN);
+ if (!miiphy_get_dev_by_name(priv->imdio.name))
+ mdio_register(&priv->imdio);
}
if (!ofnode_valid(dev->node)) {
@@ -190,70 +185,30 @@ static void enetc_start_pcs(struct udevice *dev)
case PHY_INTERFACE_MODE_SGMII_2500:
enetc_init_sgmii(dev);
break;
- case PHY_INTERFACE_MODE_RGMII:
- case PHY_INTERFACE_MODE_RGMII_ID:
- case PHY_INTERFACE_MODE_RGMII_RXID:
- case PHY_INTERFACE_MODE_RGMII_TXID:
- enetc_init_rgmii(dev);
- break;
case PHY_INTERFACE_MODE_XGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_XFI:
enetc_init_sxgmii(dev);
break;
};
}
/* Configure the actual/external ethernet PHY, if one is found */
-static void enetc_start_phy(struct udevice *dev)
+static void enetc_config_phy(struct udevice *dev)
{
struct enetc_priv *priv = dev_get_priv(dev);
- struct udevice *miidev;
- struct phy_device *phy;
- u32 phandle, phy_id;
- ofnode phy_node;
int supported;
- if (!ofnode_valid(dev->node)) {
- enetc_dbg(dev, "no enetc ofnode found, skipping PHY set-up\n");
- return;
- }
+ priv->phy = dm_eth_phy_connect(dev);
- if (ofnode_read_u32(dev->node, "phy-handle", &phandle)) {
- enetc_dbg(dev, "phy-handle not found, skipping PHY set-up\n");
+ if (!priv->phy)
return;
- }
- phy_node = ofnode_get_by_phandle(phandle);
- if (!ofnode_valid(phy_node)) {
- enetc_dbg(dev, "invalid phy node, skipping PHY set-up\n");
- return;
- }
- enetc_dbg(dev, "phy node: %s\n", ofnode_get_name(phy_node));
-
- if (ofnode_read_u32(phy_node, "reg", &phy_id)) {
- enetc_dbg(dev,
- "missing reg in PHY node, skipping PHY set-up\n");
- return;
- }
+ supported = PHY_GBIT_FEATURES | SUPPORTED_2500baseX_Full;
+ priv->phy->supported &= supported;
+ priv->phy->advertising &= supported;
- if (uclass_get_device_by_ofnode(UCLASS_MDIO,
- ofnode_get_parent(phy_node),
- &miidev)) {
- enetc_dbg(dev, "can't find MDIO bus for node %s\n",
- ofnode_get_name(ofnode_get_parent(phy_node)));
- return;
- }
-
- phy = dm_mdio_phy_connect(miidev, phy_id, dev, priv->if_type);
- if (!phy) {
- enetc_dbg(dev, "dm_mdio_phy_connect returned null\n");
- return;
- }
-
- supported = GENMASK(6, 0); /* speeds up to 1G & AN */
- phy->advertising = phy->supported & supported;
- phy->node = phy_node;
- phy_config(phy);
- phy_startup(phy);
+ phy_config(priv->phy);
}
/*
@@ -292,6 +247,9 @@ static int enetc_probe(struct udevice *dev)
dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+ enetc_start_pcs(dev);
+ enetc_config_phy(dev);
+
return 0;
}
@@ -467,8 +425,14 @@ static int enetc_start(struct udevice *dev)
enetc_setup_tx_bdr(dev);
enetc_setup_rx_bdr(dev);
- enetc_start_pcs(dev);
- enetc_start_phy(dev);
+ if (priv->if_type == PHY_INTERFACE_MODE_RGMII ||
+ priv->if_type == PHY_INTERFACE_MODE_RGMII_ID ||
+ priv->if_type == PHY_INTERFACE_MODE_RGMII_RXID ||
+ priv->if_type == PHY_INTERFACE_MODE_RGMII_TXID)
+ enetc_init_rgmii(dev);
+
+ if (priv->phy)
+ phy_startup(priv->phy);
return 0;
}
@@ -482,6 +446,10 @@ static void enetc_stop(struct udevice *dev)
{
/* FLR is sufficient to quiesce the device */
dm_pci_flr(dev);
+ /* leave the BARs accessible after we stop, this is needed to use
+ * internal MDIO in command line.
+ */
+ dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
}
/*
diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h
index 0bb4cdff47..9a36cdad80 100644
--- a/drivers/net/fsl_enetc.h
+++ b/drivers/net/fsl_enetc.h
@@ -154,6 +154,7 @@ struct enetc_priv {
int if_type;
struct mii_dev imdio;
+ struct phy_device *phy;
};
/* register accessors */
diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c
index b4463a58a5..47257a6cf6 100644
--- a/drivers/net/fsl_enetc_mdio.c
+++ b/drivers/net/fsl_enetc_mdio.c
@@ -17,8 +17,13 @@
static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv)
{
- while (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY)
+ int to = 10000;
+
+ while ((enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY) &&
+ --to)
cpu_relax();
+ if (!to)
+ printf("T");
}
int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index b6b8a93bb5..ebb74339b2 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -72,8 +72,8 @@ enum ftgmac100_model {
struct ftgmac100_data {
struct ftgmac100 *iobase;
- struct ftgmac100_txdes txdes[PKTBUFSTX];
- struct ftgmac100_rxdes rxdes[PKTBUFSRX];
+ struct ftgmac100_txdes txdes[PKTBUFSTX] __aligned(ARCH_DMA_MINALIGN);
+ struct ftgmac100_rxdes rxdes[PKTBUFSRX] __aligned(ARCH_DMA_MINALIGN);
int tx_index;
int rx_index;
@@ -310,7 +310,7 @@ static int ftgmac100_start(struct udevice *dev)
}
priv->txdes[PKTBUFSTX - 1].txdes0 = priv->txdes0_edotr_mask;
- start = (ulong)&priv->txdes[0];
+ start = ((ulong)&priv->txdes[0]) & ~(ARCH_DMA_MINALIGN - 1);
end = start + roundup(sizeof(priv->txdes), ARCH_DMA_MINALIGN);
flush_dcache_range(start, end);
@@ -320,7 +320,7 @@ static int ftgmac100_start(struct udevice *dev)
}
priv->rxdes[PKTBUFSRX - 1].rxdes0 = priv->rxdes0_edorr_mask;
- start = (ulong)&priv->rxdes[0];
+ start = ((ulong)&priv->rxdes[0]) & ~(ARCH_DMA_MINALIGN - 1);
end = start + roundup(sizeof(priv->rxdes), ARCH_DMA_MINALIGN);
flush_dcache_range(start, end);
@@ -370,7 +370,7 @@ static int ftgmac100_free_pkt(struct udevice *dev, uchar *packet, int length)
{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index];
- ulong des_start = (ulong)curr_des;
+ ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1);
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
@@ -392,7 +392,7 @@ static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp)
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index];
unsigned short rxlen;
- ulong des_start = (ulong)curr_des;
+ ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1);
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start = curr_des->rxdes3;
@@ -427,7 +427,7 @@ static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp)
static u32 ftgmac100_read_txdesc(const void *desc)
{
const struct ftgmac100_txdes *txdes = desc;
- ulong des_start = (ulong)txdes;
+ ulong des_start = ((ulong)txdes) & ~(ARCH_DMA_MINALIGN - 1);
ulong des_end = des_start + roundup(sizeof(*txdes), ARCH_DMA_MINALIGN);
invalidate_dcache_range(des_start, des_end);
@@ -445,7 +445,7 @@ static int ftgmac100_send(struct udevice *dev, void *packet, int length)
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = priv->iobase;
struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
- ulong des_start = (ulong)curr_des;
+ ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1);
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start;
diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c
index d2c52b4c46..e152faf083 100644
--- a/drivers/net/gmac_rockchip.c
+++ b/drivers/net/gmac_rockchip.c
@@ -17,6 +17,7 @@
#include <asm/arch-rockchip/grf_px30.h>
#include <asm/arch-rockchip/grf_rk322x.h>
#include <asm/arch-rockchip/grf_rk3288.h>
+#include <asm/arch-rk3308/grf_rk3308.h>
#include <asm/arch-rockchip/grf_rk3328.h>
#include <asm/arch-rockchip/grf_rk3368.h>
#include <asm/arch-rockchip/grf_rk3399.h>
@@ -173,6 +174,47 @@ static int rk3288_gmac_fix_mac_speed(struct dw_eth_dev *priv)
return 0;
}
+static int rk3308_gmac_fix_mac_speed(struct dw_eth_dev *priv)
+{
+ struct rk3308_grf *grf;
+ struct clk clk_speed;
+ int speed, ret;
+ enum {
+ RK3308_GMAC_SPEED_SHIFT = 0x0,
+ RK3308_GMAC_SPEED_MASK = BIT(0),
+ RK3308_GMAC_SPEED_10M = 0,
+ RK3308_GMAC_SPEED_100M = BIT(0),
+ };
+
+ ret = clk_get_by_name(priv->phydev->dev, "clk_mac_speed",
+ &clk_speed);
+ if (ret)
+ return ret;
+
+ switch (priv->phydev->speed) {
+ case 10:
+ speed = RK3308_GMAC_SPEED_10M;
+ ret = clk_set_rate(&clk_speed, 2500000);
+ if (ret)
+ return ret;
+ break;
+ case 100:
+ speed = RK3308_GMAC_SPEED_100M;
+ ret = clk_set_rate(&clk_speed, 25000000);
+ if (ret)
+ return ret;
+ break;
+ default:
+ debug("Unknown phy speed: %d\n", priv->phydev->speed);
+ return -EINVAL;
+ }
+
+ grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ rk_clrsetreg(&grf->mac_con0, RK3308_GMAC_SPEED_MASK, speed);
+
+ return 0;
+}
+
static int rk3328_gmac_fix_mac_speed(struct dw_eth_dev *priv)
{
struct rk3328_grf_regs *grf;
@@ -377,6 +419,22 @@ static void rk3288_gmac_set_to_rgmii(struct gmac_rockchip_platdata *pdata)
pdata->tx_delay << RK3288_CLK_TX_DL_CFG_GMAC_SHIFT);
}
+static void rk3308_gmac_set_to_rmii(struct gmac_rockchip_platdata *pdata)
+{
+ struct rk3308_grf *grf;
+ enum {
+ RK3308_GMAC_PHY_INTF_SEL_SHIFT = 2,
+ RK3308_GMAC_PHY_INTF_SEL_MASK = GENMASK(4, 2),
+ RK3308_GMAC_PHY_INTF_SEL_RMII = BIT(4),
+ };
+
+ grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+
+ rk_clrsetreg(&grf->mac_con0,
+ RK3308_GMAC_PHY_INTF_SEL_MASK,
+ RK3308_GMAC_PHY_INTF_SEL_RMII);
+}
+
static void rk3328_gmac_set_to_rgmii(struct gmac_rockchip_platdata *pdata)
{
struct rk3328_grf_regs *grf;
@@ -646,6 +704,11 @@ const struct rk_gmac_ops rk3288_gmac_ops = {
.set_to_rgmii = rk3288_gmac_set_to_rgmii,
};
+const struct rk_gmac_ops rk3308_gmac_ops = {
+ .fix_mac_speed = rk3308_gmac_fix_mac_speed,
+ .set_to_rmii = rk3308_gmac_set_to_rmii,
+};
+
const struct rk_gmac_ops rk3328_gmac_ops = {
.fix_mac_speed = rk3328_gmac_fix_mac_speed,
.set_to_rgmii = rk3328_gmac_set_to_rgmii,
@@ -673,6 +736,8 @@ static const struct udevice_id rockchip_gmac_ids[] = {
.data = (ulong)&rk3228_gmac_ops },
{ .compatible = "rockchip,rk3288-gmac",
.data = (ulong)&rk3288_gmac_ops },
+ { .compatible = "rockchip,rk3308-mac",
+ .data = (ulong)&rk3308_gmac_ops },
{ .compatible = "rockchip,rk3328-gmac",
.data = (ulong)&rk3328_gmac_ops },
{ .compatible = "rockchip,rk3368-gmac",
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index f809f3eb07..8359425378 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -165,7 +165,8 @@ static int gem_is_gigabit_capable(struct macb_device *macb)
return macb_is_gem(macb) && !cpu_is_sama5d2() && !cpu_is_sama5d4();
}
-static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
+static void macb_mdio_write(struct macb_device *macb, u8 phy_adr, u8 reg,
+ u16 value)
{
unsigned long netctl;
unsigned long netstat;
@@ -177,7 +178,7 @@ static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
frame = (MACB_BF(SOF, 1)
| MACB_BF(RW, 1)
- | MACB_BF(PHYA, macb->phy_addr)
+ | MACB_BF(PHYA, phy_adr)
| MACB_BF(REGA, reg)
| MACB_BF(CODE, 2)
| MACB_BF(DATA, value));
@@ -192,7 +193,7 @@ static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
macb_writel(macb, NCR, netctl);
}
-static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
+static u16 macb_mdio_read(struct macb_device *macb, u8 phy_adr, u8 reg)
{
unsigned long netctl;
unsigned long netstat;
@@ -204,7 +205,7 @@ static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
frame = (MACB_BF(SOF, 1)
| MACB_BF(RW, 2)
- | MACB_BF(PHYA, macb->phy_addr)
+ | MACB_BF(PHYA, phy_adr)
| MACB_BF(REGA, reg)
| MACB_BF(CODE, 2));
macb_writel(macb, MAN, frame);
@@ -240,11 +241,8 @@ int macb_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg)
struct macb_device *macb = to_macb(dev);
#endif
- if (macb->phy_addr != phy_adr)
- return -1;
-
arch_get_mdio_control(bus->name);
- value = macb_mdio_read(macb, reg);
+ value = macb_mdio_read(macb, phy_adr, reg);
return value;
}
@@ -260,11 +258,8 @@ int macb_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg,
struct macb_device *macb = to_macb(dev);
#endif
- if (macb->phy_addr != phy_adr)
- return -1;
-
arch_get_mdio_control(bus->name);
- macb_mdio_write(macb, reg, value);
+ macb_mdio_write(macb, phy_adr, reg, value);
return 0;
}
@@ -451,13 +446,13 @@ static void macb_phy_reset(struct macb_device *macb, const char *name)
u16 status, adv;
adv = ADVERTISE_CSMA | ADVERTISE_ALL;
- macb_mdio_write(macb, MII_ADVERTISE, adv);
+ macb_mdio_write(macb, macb->phy_addr, MII_ADVERTISE, adv);
printf("%s: Starting autonegotiation...\n", name);
- macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
+ macb_mdio_write(macb, macb->phy_addr, MII_BMCR, (BMCR_ANENABLE
| BMCR_ANRESTART));
for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) {
- status = macb_mdio_read(macb, MII_BMSR);
+ status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR);
if (status & BMSR_ANEGCOMPLETE)
break;
udelay(100);
@@ -478,7 +473,7 @@ static int macb_phy_find(struct macb_device *macb, const char *name)
/* Search for PHY... */
for (i = 0; i < 32; i++) {
macb->phy_addr = i;
- phy_id = macb_mdio_read(macb, MII_PHYSID1);
+ phy_id = macb_mdio_read(macb, macb->phy_addr, MII_PHYSID1);
if (phy_id != 0xffff) {
printf("%s: PHY present at %d\n", name, i);
return 0;
@@ -596,7 +591,7 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
return ret;
/* Check if the PHY is up to snuff... */
- phy_id = macb_mdio_read(macb, MII_PHYSID1);
+ phy_id = macb_mdio_read(macb, macb->phy_addr, MII_PHYSID1);
if (phy_id == 0xffff) {
printf("%s: No PHY present\n", name);
return -ENODEV;
@@ -619,13 +614,13 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
phy_config(macb->phydev);
#endif
- status = macb_mdio_read(macb, MII_BMSR);
+ status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR);
if (!(status & BMSR_LSTATUS)) {
/* Try to re-negotiate if we don't have link already. */
macb_phy_reset(macb, name);
for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) {
- status = macb_mdio_read(macb, MII_BMSR);
+ status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR);
if (status & BMSR_LSTATUS) {
/*
* Delay a bit after the link is established,
@@ -646,7 +641,7 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
/* First check for GMAC and that it is GiB capable */
if (gem_is_gigabit_capable(macb)) {
- lpa = macb_mdio_read(macb, MII_STAT1000);
+ lpa = macb_mdio_read(macb, macb->phy_addr, MII_STAT1000);
if (lpa & (LPA_1000FULL | LPA_1000HALF | LPA_1000XFULL |
LPA_1000XHALF)) {
@@ -680,8 +675,8 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
}
/* fall back for EMAC checking */
- adv = macb_mdio_read(macb, MII_ADVERTISE);
- lpa = macb_mdio_read(macb, MII_LPA);
+ adv = macb_mdio_read(macb, macb->phy_addr, MII_ADVERTISE);
+ lpa = macb_mdio_read(macb, macb->phy_addr, MII_LPA);
media = mii_nway_result(lpa & adv);
speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
? 1 : 0);
diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c
index 8148c03d22..c5d1f9cf9f 100644
--- a/drivers/net/mvpp2.c
+++ b/drivers/net/mvpp2.c
@@ -33,6 +33,7 @@
#include <linux/mbus.h>
#include <asm-generic/gpio.h>
#include <fdt_support.h>
+#include <linux/mdio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -63,8 +64,6 @@ do { \
#define MTU 1500
#define RX_BUFFER_SIZE (ALIGN(MTU + WRAP, ARCH_DMA_MINALIGN))
-#define MVPP2_SMI_TIMEOUT 10000
-
/* RX Fifo Registers */
#define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port))
#define MVPP2_RX_ATTR_FIFO_SIZE_REG(port) (0x20 + 4 * (port))
@@ -491,23 +490,8 @@ do { \
#define MVPP2_QUEUE_NEXT_DESC(q, index) \
(((index) < (q)->last_desc) ? ((index) + 1) : 0)
-/* SMI: 0xc0054 -> offset 0x54 to lms_base */
-#define MVPP21_SMI 0x0054
/* PP2.2: SMI: 0x12a200 -> offset 0x1200 to iface_base */
#define MVPP22_SMI 0x1200
-#define MVPP2_PHY_REG_MASK 0x1f
-/* SMI register fields */
-#define MVPP2_SMI_DATA_OFFS 0 /* Data */
-#define MVPP2_SMI_DATA_MASK (0xffff << MVPP2_SMI_DATA_OFFS)
-#define MVPP2_SMI_DEV_ADDR_OFFS 16 /* PHY device address */
-#define MVPP2_SMI_REG_ADDR_OFFS 21 /* PHY device reg addr*/
-#define MVPP2_SMI_OPCODE_OFFS 26 /* Write/Read opcode */
-#define MVPP2_SMI_OPCODE_READ (1 << MVPP2_SMI_OPCODE_OFFS)
-#define MVPP2_SMI_READ_VALID (1 << 27) /* Read Valid */
-#define MVPP2_SMI_BUSY (1 << 28) /* Busy */
-
-#define MVPP2_PHY_ADDR_MASK 0x1f
-#define MVPP2_PHY_REG_MASK 0x1f
/* Additional PPv2.2 offsets */
#define MVPP22_MPCS 0x007000
@@ -953,7 +937,6 @@ struct mvpp2_port {
/* Per-port registers' base address */
void __iomem *base;
- void __iomem *mdio_base;
struct mvpp2_rx_queue **rxqs;
struct mvpp2_tx_queue **txqs;
@@ -974,9 +957,8 @@ struct mvpp2_port {
struct phy_device *phy_dev;
phy_interface_t phy_interface;
- int phy_node;
int phyaddr;
- struct mii_dev *bus;
+ struct udevice *mdio_dev;
#ifdef CONFIG_DM_GPIO
struct gpio_desc phy_reset_gpio;
struct gpio_desc phy_tx_disable_gpio;
@@ -4495,17 +4477,40 @@ static void mvpp2_stop_dev(struct mvpp2_port *port)
gop_port_enable(port, 0);
}
-static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port)
+static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port)
{
struct phy_device *phy_dev;
if (!port->init || port->link == 0) {
- phy_dev = phy_connect(port->bus, port->phyaddr, dev,
- port->phy_interface);
+ phy_dev = dm_mdio_phy_connect(port->mdio_dev, port->phyaddr,
+ dev, port->phy_interface);
+
+ /*
+ * If the phy doesn't match with any existing u-boot drivers the
+ * phy framework will connect it to generic one which
+ * uid == 0xffffffff. In this case act as if the phy wouldn't be
+ * declared in dts. Otherwise in case of 3310 (for which the
+ * driver doesn't exist) the link will not be correctly
+ * detected. Removing phy entry from dts in case of 3310 is not
+ * an option because it is required for the phy_fw_down
+ * procedure.
+ */
+ if (phy_dev &&
+ phy_dev->drv->uid == 0xffffffff) {/* Generic phy */
+ netdev_warn(port->dev,
+ "Marking phy as invalid, link will not be checked\n");
+ /* set phy_addr to invalid value */
+ port->phyaddr = PHY_MAX_ADDR;
+ mvpp2_egress_enable(port);
+ mvpp2_ingress_enable(port);
+
+ return;
+ }
+
port->phy_dev = phy_dev;
if (!phy_dev) {
netdev_err(port->dev, "cannot connect to phy\n");
- return -ENODEV;
+ return;
}
phy_dev->supported &= PHY_GBIT_FEATURES;
phy_dev->advertising = phy_dev->supported;
@@ -4517,18 +4522,14 @@ static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port)
phy_config(phy_dev);
phy_startup(phy_dev);
- if (!phy_dev->link) {
+ if (!phy_dev->link)
printf("%s: No link\n", phy_dev->dev->name);
- return -1;
- }
-
- port->init = 1;
+ else
+ port->init = 1;
} else {
mvpp2_egress_enable(port);
mvpp2_ingress_enable(port);
}
-
- return 0;
}
static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port)
@@ -4567,11 +4568,8 @@ static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port)
return err;
}
- if (port->phy_node) {
- err = mvpp2_phy_connect(dev, port);
- if (err < 0)
- return err;
-
+ if (port->phyaddr < PHY_MAX_ADDR) {
+ mvpp2_phy_connect(dev, port);
mvpp2_link_event(port);
} else {
mvpp2_egress_enable(port);
@@ -4709,35 +4707,25 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port)
u32 id;
u32 phyaddr = 0;
int phy_mode = -1;
-
- /* Default mdio_base from the same eth base */
- if (port->priv->hw_version == MVPP21)
- port->mdio_base = port->priv->lms_base + MVPP21_SMI;
- else
- port->mdio_base = port->priv->iface_base + MVPP22_SMI;
+ int ret;
phy_node = fdtdec_lookup_phandle(gd->fdt_blob, port_node, "phy");
if (phy_node > 0) {
- ofnode phy_ofnode;
- fdt_addr_t phy_base;
-
+ int parent;
phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0);
if (phyaddr < 0) {
dev_err(&pdev->dev, "could not find phy address\n");
return -1;
}
-
- phy_ofnode = ofnode_get_parent(offset_to_ofnode(phy_node));
- phy_base = ofnode_get_addr(phy_ofnode);
- port->mdio_base = (void *)phy_base;
-
- if (port->mdio_base < 0) {
- dev_err(&pdev->dev, "could not find mdio base address\n");
- return -1;
- }
+ parent = fdt_parent_offset(gd->fdt_blob, phy_node);
+ ret = uclass_get_device_by_of_offset(UCLASS_MDIO, parent,
+ &port->mdio_dev);
+ if (ret)
+ return ret;
} else {
- phy_node = 0;
+ /* phy_addr is set to invalid value */
+ phyaddr = PHY_MAX_ADDR;
}
phy_mode_str = fdt_getprop(gd->fdt_blob, port_node, "phy-mode", NULL);
@@ -4775,7 +4763,6 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port)
port->first_rxq = port->id * rxq_number;
else
port->first_rxq = port->id * port->priv->max_port_rxqs;
- port->phy_node = phy_node;
port->phy_interface = phy_mode;
port->phyaddr = phyaddr;
@@ -5052,118 +5039,6 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv)
return 0;
}
-/* SMI / MDIO functions */
-
-static int smi_wait_ready(struct mvpp2_port *priv)
-{
- u32 timeout = MVPP2_SMI_TIMEOUT;
- u32 smi_reg;
-
- /* wait till the SMI is not busy */
- do {
- /* read smi register */
- smi_reg = readl(priv->mdio_base);
- if (timeout-- == 0) {
- printf("Error: SMI busy timeout\n");
- return -EFAULT;
- }
- } while (smi_reg & MVPP2_SMI_BUSY);
-
- return 0;
-}
-
-/*
- * mpp2_mdio_read - miiphy_read callback function.
- *
- * Returns 16bit phy register value, or 0xffff on error
- */
-static int mpp2_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
-{
- struct mvpp2_port *priv = bus->priv;
- u32 smi_reg;
- u32 timeout;
-
- /* check parameters */
- if (addr > MVPP2_PHY_ADDR_MASK) {
- printf("Error: Invalid PHY address %d\n", addr);
- return -EFAULT;
- }
-
- if (reg > MVPP2_PHY_REG_MASK) {
- printf("Err: Invalid register offset %d\n", reg);
- return -EFAULT;
- }
-
- /* wait till the SMI is not busy */
- if (smi_wait_ready(priv) < 0)
- return -EFAULT;
-
- /* fill the phy address and regiser offset and read opcode */
- smi_reg = (addr << MVPP2_SMI_DEV_ADDR_OFFS)
- | (reg << MVPP2_SMI_REG_ADDR_OFFS)
- | MVPP2_SMI_OPCODE_READ;
-
- /* write the smi register */
- writel(smi_reg, priv->mdio_base);
-
- /* wait till read value is ready */
- timeout = MVPP2_SMI_TIMEOUT;
-
- do {
- /* read smi register */
- smi_reg = readl(priv->mdio_base);
- if (timeout-- == 0) {
- printf("Err: SMI read ready timeout\n");
- return -EFAULT;
- }
- } while (!(smi_reg & MVPP2_SMI_READ_VALID));
-
- /* Wait for the data to update in the SMI register */
- for (timeout = 0; timeout < MVPP2_SMI_TIMEOUT; timeout++)
- ;
-
- return readl(priv->mdio_base) & MVPP2_SMI_DATA_MASK;
-}
-
-/*
- * mpp2_mdio_write - miiphy_write callback function.
- *
- * Returns 0 if write succeed, -EINVAL on bad parameters
- * -ETIME on timeout
- */
-static int mpp2_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
- u16 value)
-{
- struct mvpp2_port *priv = bus->priv;
- u32 smi_reg;
-
- /* check parameters */
- if (addr > MVPP2_PHY_ADDR_MASK) {
- printf("Error: Invalid PHY address %d\n", addr);
- return -EFAULT;
- }
-
- if (reg > MVPP2_PHY_REG_MASK) {
- printf("Err: Invalid register offset %d\n", reg);
- return -EFAULT;
- }
-
- /* wait till the SMI is not busy */
- if (smi_wait_ready(priv) < 0)
- return -EFAULT;
-
- /* fill the phy addr and reg offset and write opcode and data */
- smi_reg = value << MVPP2_SMI_DATA_OFFS;
- smi_reg |= (addr << MVPP2_SMI_DEV_ADDR_OFFS)
- | (reg << MVPP2_SMI_REG_ADDR_OFFS);
- smi_reg &= ~MVPP2_SMI_OPCODE_READ;
-
- /* write the smi register */
- writel(smi_reg, priv->mdio_base);
-
- return 0;
-}
-
static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp)
{
struct mvpp2_port *port = dev_get_priv(dev);
@@ -5176,6 +5051,10 @@ static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp)
struct mvpp2_rx_queue *rxq;
u8 *data;
+ if (port->phyaddr < PHY_MAX_ADDR)
+ if (!port->phy_dev->link)
+ return 0;
+
/* Process RX packets */
rxq = port->rxqs[0];
@@ -5241,6 +5120,10 @@ static int mvpp2_send(struct udevice *dev, void *packet, int length)
int tx_done;
int timeout;
+ if (port->phyaddr < PHY_MAX_ADDR)
+ if (!port->phy_dev->link)
+ return 0;
+
txq = port->txqs[0];
aggr_txq = &port->priv->aggr_txqs[smp_processor_id()];
@@ -5421,31 +5304,13 @@ static int mvpp2_probe(struct udevice *dev)
{
struct mvpp2_port *port = dev_get_priv(dev);
struct mvpp2 *priv = dev_get_priv(dev->parent);
- struct mii_dev *bus;
int err;
/* Only call the probe function for the parent once */
if (!priv->probe_done)
err = mvpp2_base_probe(dev->parent);
- port->priv = dev_get_priv(dev->parent);
-
- /* Create and register the MDIO bus driver */
- bus = mdio_alloc();
- if (!bus) {
- printf("Failed to allocate MDIO bus\n");
- return -ENOMEM;
- }
-
- bus->read = mpp2_mdio_read;
- bus->write = mpp2_mdio_write;
- snprintf(bus->name, sizeof(bus->name), dev->name);
- bus->priv = (void *)port;
- port->bus = bus;
-
- err = mdio_register(bus);
- if (err)
- return err;
+ port->priv = priv;
err = phy_info_parse(dev, port);
if (err)
@@ -5474,7 +5339,7 @@ static int mvpp2_probe(struct udevice *dev)
port->gop_id * MVPP22_PORT_OFFSET;
/* Set phy address of the port */
- if(port->phy_node)
+ if (port->phyaddr < PHY_MAX_ADDR)
mvpp22_smi_phy_addr_cfg(port);
/* GoP Init */
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index bcea8a0c3e..dceea1516f 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -46,7 +46,7 @@ config B53_PHY_PORTS
endif # B53_SWITCH
config MV88E61XX_SWITCH
- bool "Marvel MV88E61xx Ethernet switch PHY support."
+ bool "Marvell MV88E61xx Ethernet switch PHY support."
if MV88E61XX_SWITCH
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 76b6197009..78955c57a8 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -25,7 +25,7 @@ obj-$(CONFIG_PHY_NATSEMI) += natsemi.o
obj-$(CONFIG_PHY_REALTEK) += realtek.o
obj-$(CONFIG_PHY_SMSC) += smsc.o
obj-$(CONFIG_PHY_TERANETICS) += teranetics.o
-obj-$(CONFIG_PHY_TI) += ti.o
+obj-$(CONFIG_PHY_TI) += dp83867.o
obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
obj-$(CONFIG_PHY_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
obj-$(CONFIG_PHY_VITESSE) += vitesse.o
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index 465ec2d342..c4bd443001 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -21,6 +21,7 @@
#define AQUNTIA_SPEED_MSB_MASK 0x40
#define AQUANTIA_SYSTEM_INTERFACE_SR 0xe812
+#define AQUANTIA_SYSTEM_INTERFACE_SR_READY BIT(0)
#define AQUANTIA_VENDOR_PROVISIONING_REG 0xC441
#define AQUANTIA_FIRMWARE_ID 0x20
#define AQUANTIA_RESERVED_STATUS 0xc885
@@ -33,10 +34,16 @@
#define AQUANTIA_SI_USXGMII 0x0018
/* registers in MDIO_MMD_VEND1 region */
+#define AQUANTIA_VND1_GLOBAL_SC 0x000
+#define AQUANTIA_VND1_GLOBAL_SC_LP BIT(0xb)
+
#define GLOBAL_FIRMWARE_ID 0x20
#define GLOBAL_FAULT 0xc850
#define GLOBAL_RSTATUS_1 0xc885
+#define GLOBAL_ALARM_1 0xcc00
+#define SYSTEM_READY_BIT 0x40
+
#define GLOBAL_STANDARD_CONTROL 0x0
#define SOFT_RESET BIT(15)
#define LOW_POWER BIT(11)
@@ -60,6 +67,36 @@
#define UP_RUN_STALL_OVERRIDE BIT(6)
#define UP_RUN_STALL BIT(0)
+#define AQUANTIA_PMA_RX_VENDOR_P1 0xe400
+#define AQUANTIA_PMA_RX_VENDOR_P1_MDI_MSK GENMASK(1, 0)
+/* MDI reversal configured through registers */
+#define AQUANTIA_PMA_RX_VENDOR_P1_MDI_CFG BIT(1)
+/* MDI reversal enabled */
+#define AQUANTIA_PMA_RX_VENDOR_P1_MDI_REV BIT(0)
+
+/*
+ * global start rate, the protocol associated with this speed is used by default
+ * on SI.
+ */
+#define AQUANTIA_VND1_GSTART_RATE 0x31a
+#define AQUANTIA_VND1_GSTART_RATE_OFF 0
+#define AQUANTIA_VND1_GSTART_RATE_100M 1
+#define AQUANTIA_VND1_GSTART_RATE_1G 2
+#define AQUANTIA_VND1_GSTART_RATE_10G 3
+#define AQUANTIA_VND1_GSTART_RATE_2_5G 4
+#define AQUANTIA_VND1_GSTART_RATE_5G 5
+
+/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */
+#define AQUANTIA_VND1_GSYSCFG_BASE 0x31b
+#define AQUANTIA_VND1_GSYSCFG_100M 0
+#define AQUANTIA_VND1_GSYSCFG_1G 1
+#define AQUANTIA_VND1_GSYSCFG_2_5G 2
+#define AQUANTIA_VND1_GSYSCFG_5G 3
+#define AQUANTIA_VND1_GSYSCFG_10G 4
+
+#define AQUANTIA_VND1_SMBUS0 0xc485
+#define AQUANTIA_VND1_SMBUS1 0xc495
+
/* addresses of memory segments in the phy */
#define DRAM_BASE_ADDR 0x3FFE0000
#define IRAM_BASE_ADDR 0x40000000
@@ -69,6 +106,12 @@
#define VERSION_STRING_OFFSET 0x0200
#define HEADER_OFFSET 0x300
+/* driver private data */
+#define AQUANTIA_NA 0
+#define AQUANTIA_GEN1 1
+#define AQUANTIA_GEN2 2
+#define AQUANTIA_GEN3 3
+
#pragma pack(1)
struct fw_header {
u8 padding[4];
@@ -254,10 +297,128 @@ static int aquantia_upload_firmware(struct phy_device *phydev)
}
#endif
+struct {
+ u16 syscfg;
+ int cnt;
+ u16 start_rate;
+} aquantia_syscfg[PHY_INTERFACE_MODE_COUNT] = {
+ [PHY_INTERFACE_MODE_SGMII] = {0x04b, AQUANTIA_VND1_GSYSCFG_1G,
+ AQUANTIA_VND1_GSTART_RATE_1G},
+ [PHY_INTERFACE_MODE_SGMII_2500] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G,
+ AQUANTIA_VND1_GSTART_RATE_2_5G},
+ [PHY_INTERFACE_MODE_XGMII] = {0x100, AQUANTIA_VND1_GSYSCFG_10G,
+ AQUANTIA_VND1_GSTART_RATE_10G},
+ [PHY_INTERFACE_MODE_XFI] = {0x100, AQUANTIA_VND1_GSYSCFG_10G,
+ AQUANTIA_VND1_GSTART_RATE_10G},
+ [PHY_INTERFACE_MODE_USXGMII] = {0x080, AQUANTIA_VND1_GSYSCFG_10G,
+ AQUANTIA_VND1_GSTART_RATE_10G},
+};
+
+static int aquantia_set_proto(struct phy_device *phydev)
+{
+ int i;
+
+ if (!aquantia_syscfg[phydev->interface].cnt)
+ return 0;
+
+ /* set the default rate to enable the SI link */
+ phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
+ aquantia_syscfg[phydev->interface].start_rate);
+
+ /* set selected protocol for all relevant line side link speeds */
+ for (i = 0; i <= aquantia_syscfg[phydev->interface].cnt; i++)
+ phy_write(phydev, MDIO_MMD_VEND1,
+ AQUANTIA_VND1_GSYSCFG_BASE + i,
+ aquantia_syscfg[phydev->interface].syscfg);
+ return 0;
+}
+
+static int aquantia_dts_config(struct phy_device *phydev)
+{
+#ifdef CONFIG_DM_ETH
+ ofnode node = phydev->node;
+ u32 prop;
+ u16 reg;
+
+ /* this code only works on gen2 and gen3 PHYs */
+ if (phydev->drv->data != AQUANTIA_GEN2 &&
+ phydev->drv->data != AQUANTIA_GEN3)
+ return -ENOTSUPP;
+
+ if (!ofnode_valid(node))
+ return 0;
+
+ if (!ofnode_read_u32(node, "mdi-reversal", &prop)) {
+ debug("mdi-reversal = %d\n", (int)prop);
+ reg = phy_read(phydev, MDIO_MMD_PMAPMD,
+ AQUANTIA_PMA_RX_VENDOR_P1);
+ reg &= ~AQUANTIA_PMA_RX_VENDOR_P1_MDI_MSK;
+ reg |= AQUANTIA_PMA_RX_VENDOR_P1_MDI_CFG;
+ reg |= prop ? AQUANTIA_PMA_RX_VENDOR_P1_MDI_REV : 0;
+ phy_write(phydev, MDIO_MMD_PMAPMD, AQUANTIA_PMA_RX_VENDOR_P1,
+ reg);
+ }
+ if (!ofnode_read_u32(node, "smb-addr", &prop)) {
+ debug("smb-addr = %x\n", (int)prop);
+ /*
+ * there are two addresses here, normally just one bus would
+ * be in use so we're setting both regs using the same DT
+ * property.
+ */
+ phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_SMBUS0,
+ (u16)(prop << 1));
+ phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_SMBUS1,
+ (u16)(prop << 1));
+ }
+
+#endif
+ return 0;
+}
+
+static bool aquantia_link_is_up(struct phy_device *phydev)
+{
+ u16 reg, regmask;
+ int devad, regnum;
+
+ /*
+ * On Gen 2 and 3 we have a bit that indicates that both system and
+ * line side are ready for data, use that if possible.
+ */
+ if (phydev->drv->data == AQUANTIA_GEN2 ||
+ phydev->drv->data == AQUANTIA_GEN3) {
+ devad = MDIO_MMD_PHYXS;
+ regnum = AQUANTIA_SYSTEM_INTERFACE_SR;
+ regmask = AQUANTIA_SYSTEM_INTERFACE_SR_READY;
+ } else {
+ devad = MDIO_MMD_AN;
+ regnum = MDIO_STAT1;
+ regmask = MDIO_AN_STAT1_COMPLETE;
+ }
+ /* the register should be latched, do a double read */
+ phy_read(phydev, devad, regnum);
+ reg = phy_read(phydev, devad, regnum);
+
+ return !!(reg & regmask);
+}
+
int aquantia_config(struct phy_device *phydev)
{
+ int interface = phydev->interface;
u32 val, id, rstatus, fault;
u32 reg_val1 = 0;
+ int num_retries = 5;
+ int usx_an = 0;
+
+ /*
+ * check if the system is out of reset and init sequence completed.
+ * chip-wide reset for gen1 quad phys takes longer
+ */
+ while (--num_retries) {
+ rstatus = phy_read(phydev, MDIO_MMD_VEND1, GLOBAL_ALARM_1);
+ if (rstatus & SYSTEM_READY_BIT)
+ break;
+ mdelay(10);
+ }
id = phy_read(phydev, MDIO_MMD_VEND1, GLOBAL_FIRMWARE_ID);
rstatus = phy_read(phydev, MDIO_MMD_VEND1, GLOBAL_RSTATUS_1);
@@ -278,17 +439,57 @@ int aquantia_config(struct phy_device *phydev)
if (ret != 0)
return ret;
}
+ /*
+ * for backward compatibility convert XGMII into either XFI or USX based
+ * on FW config
+ */
+ if (interface == PHY_INTERFACE_MODE_XGMII) {
+ reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS,
+ AQUANTIA_SYSTEM_INTERFACE_SR);
+ if ((reg_val1 & AQUANTIA_SI_IN_USE_MASK) == AQUANTIA_SI_USXGMII)
+ interface = PHY_INTERFACE_MODE_USXGMII;
+ else
+ interface = PHY_INTERFACE_MODE_XFI;
+ }
+
+ /*
+ * if link is up already we can just use it, otherwise configure
+ * the protocols in the PHY. If link is down set the system
+ * interface protocol to use based on phydev->interface
+ */
+ if (!aquantia_link_is_up(phydev) &&
+ (phydev->drv->data == AQUANTIA_GEN2 ||
+ phydev->drv->data == AQUANTIA_GEN3)) {
+ /* set PHY in low power mode so we can configure protocols */
+ phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC,
+ AQUANTIA_VND1_GLOBAL_SC_LP);
+ mdelay(10);
+
+ /* configure protocol based on phydev->interface */
+ aquantia_set_proto(phydev);
+ /* apply custom configuration based on DT */
+ aquantia_dts_config(phydev);
+
+ /* wake PHY back up */
+ phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
+ mdelay(10);
+ }
val = phy_read(phydev, MDIO_MMD_PMAPMD, MII_BMCR);
- if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
/* 1000BASE-T mode */
phydev->advertising = SUPPORTED_1000baseT_Full;
phydev->supported = phydev->advertising;
val = (val & ~AQUNTIA_SPEED_LSB_MASK) | AQUNTIA_SPEED_MSB_MASK;
phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val);
- } else if (phydev->interface == PHY_INTERFACE_MODE_XGMII) {
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ usx_an = 1;
+ /* FALLTHROUGH */
+ case PHY_INTERFACE_MODE_XFI:
/* 10GBASE-T mode */
phydev->advertising = SUPPORTED_10000baseT_Full;
phydev->supported = phydev->advertising;
@@ -299,40 +500,40 @@ int aquantia_config(struct phy_device *phydev)
AQUNTIA_SPEED_LSB_MASK |
AQUNTIA_SPEED_MSB_MASK);
- val = phy_read(phydev, MDIO_MMD_PHYXS,
- AQUANTIA_SYSTEM_INTERFACE_SR);
/* If SI is USXGMII then start USXGMII autoneg */
- if ((val & AQUANTIA_SI_IN_USE_MASK) == AQUANTIA_SI_USXGMII) {
- reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS,
- AQUANTIA_VENDOR_PROVISIONING_REG);
+ reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS,
+ AQUANTIA_VENDOR_PROVISIONING_REG);
+ if (usx_an) {
reg_val1 |= AQUANTIA_USX_AUTONEG_CONTROL_ENA;
-
- phy_write(phydev, MDIO_MMD_PHYXS,
- AQUANTIA_VENDOR_PROVISIONING_REG,
- reg_val1);
printf("%s: system interface USXGMII\n",
phydev->dev->name);
} else {
+ reg_val1 &= ~AQUANTIA_USX_AUTONEG_CONTROL_ENA;
printf("%s: system interface XFI\n",
phydev->dev->name);
}
- } else if (phydev->interface == PHY_INTERFACE_MODE_SGMII_2500) {
+ phy_write(phydev, MDIO_MMD_PHYXS,
+ AQUANTIA_VENDOR_PROVISIONING_REG, reg_val1);
+ break;
+ case PHY_INTERFACE_MODE_SGMII_2500:
/* 2.5GBASE-T mode */
phydev->advertising = SUPPORTED_1000baseT_Full;
phydev->supported = phydev->advertising;
phy_write(phydev, MDIO_MMD_AN, AQUNTIA_10G_CTL, 1);
phy_write(phydev, MDIO_MMD_AN, AQUNTIA_VENDOR_P1, 0x9440);
- } else if (phydev->interface == PHY_INTERFACE_MODE_MII) {
+ break;
+ case PHY_INTERFACE_MODE_MII:
/* 100BASE-TX mode */
phydev->advertising = SUPPORTED_100baseT_Full;
phydev->supported = phydev->advertising;
val = (val & ~AQUNTIA_SPEED_MSB_MASK) | AQUNTIA_SPEED_LSB_MASK;
phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val);
- }
+ break;
+ };
val = phy_read(phydev, MDIO_MMD_VEND1, AQUANTIA_RESERVED_STATUS);
reg_val1 = phy_read(phydev, MDIO_MMD_VEND1, AQUANTIA_FIRMWARE_ID);
@@ -354,17 +555,14 @@ int aquantia_startup(struct phy_device *phydev)
phydev->duplex = DUPLEX_FULL;
/* if the AN is still in progress, wait till timeout. */
- phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
- reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
- if (!(reg & MDIO_AN_STAT1_COMPLETE)) {
+ if (!aquantia_link_is_up(phydev)) {
printf("%s Waiting for PHY auto negotiation to complete",
phydev->dev->name);
do {
udelay(1000);
- reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
if ((i++ % 500) == 0)
printf(".");
- } while (!(reg & MDIO_AN_STAT1_COMPLETE) &&
+ } while (!aquantia_link_is_up(phydev) &&
i < (4 * PHY_ANEG_TIMEOUT));
if (i > PHY_ANEG_TIMEOUT)
@@ -433,6 +631,7 @@ struct phy_driver aqr105_driver = {
.config = &aquantia_config,
.startup = &aquantia_startup,
.shutdown = &gen10g_shutdown,
+ .data = AQUANTIA_GEN1,
};
struct phy_driver aqr106_driver = {
@@ -459,6 +658,7 @@ struct phy_driver aqr107_driver = {
.config = &aquantia_config,
.startup = &aquantia_startup,
.shutdown = &gen10g_shutdown,
+ .data = AQUANTIA_GEN2,
};
struct phy_driver aqr112_driver = {
@@ -472,6 +672,7 @@ struct phy_driver aqr112_driver = {
.config = &aquantia_config,
.startup = &aquantia_startup,
.shutdown = &gen10g_shutdown,
+ .data = AQUANTIA_GEN3,
};
struct phy_driver aqr405_driver = {
@@ -485,6 +686,7 @@ struct phy_driver aqr405_driver = {
.config = &aquantia_config,
.startup = &aquantia_startup,
.shutdown = &gen10g_shutdown,
+ .data = AQUANTIA_GEN1,
};
struct phy_driver aqr412_driver = {
@@ -498,6 +700,7 @@ struct phy_driver aqr412_driver = {
.config = &aquantia_config,
.startup = &aquantia_startup,
.shutdown = &gen10g_shutdown,
+ .data = AQUANTIA_GEN3,
};
int phy_aquantia_init(void)
diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/dp83867.c
index 7509936465..a43793cd42 100644
--- a/drivers/net/phy/ti.c
+++ b/drivers/net/phy/dp83867.c
@@ -25,6 +25,7 @@
#define DP83867_CFG4 0x0031
#define DP83867_RGMIICTL 0x0032
#define DP83867_STRAP_STS1 0x006E
+#define DP83867_STRAP_STS2 0x006f
#define DP83867_RGMIIDCTL 0x0086
#define DP83867_IO_MUX_CFG 0x0170
@@ -52,18 +53,27 @@
/* STRAP_STS1 bits */
#define DP83867_STRAP_STS1_RESERVED BIT(11)
+/* STRAP_STS2 bits */
+#define DP83867_STRAP_STS2_CLK_SKEW_TX_MASK GENMASK(6, 4)
+#define DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT 4
+#define DP83867_STRAP_STS2_CLK_SKEW_RX_MASK GENMASK(2, 0)
+#define DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT 0
+#define DP83867_STRAP_STS2_CLK_SKEW_NONE BIT(2)
+
/* PHY CTRL bits */
#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14
+#define DP83867_PHYCR_FIFO_DEPTH_MASK GENMASK(15, 14)
#define DP83867_PHYCR_RESERVED_MASK BIT(11)
#define DP83867_MDI_CROSSOVER 5
-#define DP83867_MDI_CROSSOVER_AUTO 2
#define DP83867_MDI_CROSSOVER_MDIX 2
#define DP83867_PHYCTRL_SGMIIEN 0x0800
#define DP83867_PHYCTRL_RXFIFO_SHIFT 12
#define DP83867_PHYCTRL_TXFIFO_SHIFT 14
/* RGMIIDCTL bits */
+#define DP83867_RGMII_TX_CLK_DELAY_MAX 0xf
#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4
+#define DP83867_RGMII_RX_CLK_DELAY_MAX 0xf
/* CFG2 bits */
#define MII_DP83867_CFG2_SPEEDOPT_10EN 0x0040
@@ -74,8 +84,6 @@
#define MII_DP83867_CFG2_MASK 0x003F
/* User setting - can be taken from DTS */
-#define DEFAULT_RX_ID_DELAY DP83867_RGMIIDCTL_2_25_NS
-#define DEFAULT_TX_ID_DELAY DP83867_RGMIIDCTL_2_75_NS
#define DEFAULT_FIFO_DEPTH DP83867_PHYCR_FIFO_DEPTH_4_B_NIB
/* IO_MUX_CFG bits */
@@ -83,6 +91,7 @@
#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0
#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f
+#define DP83867_IO_MUX_CFG_CLK_O_DISABLE BIT(6)
#define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8
#define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK \
GENMASK(0x1f, DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT)
@@ -97,12 +106,13 @@ enum {
};
struct dp83867_private {
- int rx_id_delay;
- int tx_id_delay;
+ u32 rx_id_delay;
+ u32 tx_id_delay;
int fifo_depth;
int io_impedance;
bool rxctrl_strap_quirk;
int port_mirroring;
+ bool set_clk_output;
unsigned int clk_output_sel;
};
@@ -134,16 +144,28 @@ static int dp83867_of_init(struct phy_device *phydev)
{
struct dp83867_private *dp83867 = phydev->priv;
ofnode node;
- u16 val;
+ int ret;
node = phy_get_ofnode(phydev);
if (!ofnode_valid(node))
return -EINVAL;
- /* Keep the default value if ti,clk-output-sel is not set */
- dp83867->clk_output_sel =
- ofnode_read_u32_default(node, "ti,clk-output-sel",
- DP83867_CLK_O_SEL_REF_CLK);
+ /* Optional configuration */
+ ret = ofnode_read_u32(node, "ti,clk-output-sel",
+ &dp83867->clk_output_sel);
+ /* If not set, keep default */
+ if (!ret) {
+ dp83867->set_clk_output = true;
+ /* Valid values are 0 to DP83867_CLK_O_SEL_REF_CLK or
+ * DP83867_CLK_O_SEL_OFF.
+ */
+ if (dp83867->clk_output_sel > DP83867_CLK_O_SEL_REF_CLK &&
+ dp83867->clk_output_sel != DP83867_CLK_O_SEL_OFF) {
+ pr_debug("ti,clk-output-sel value %u out of range\n",
+ dp83867->clk_output_sel);
+ return -EINVAL;
+ }
+ }
if (ofnode_read_bool(node, "ti,max-output-impedance"))
dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX;
@@ -154,13 +176,55 @@ static int dp83867_of_init(struct phy_device *phydev)
if (ofnode_read_bool(node, "ti,dp83867-rxctrl-strap-quirk"))
dp83867->rxctrl_strap_quirk = true;
- dp83867->rx_id_delay = ofnode_read_u32_default(node,
- "ti,rx-internal-delay",
- DEFAULT_RX_ID_DELAY);
- dp83867->tx_id_delay = ofnode_read_u32_default(node,
- "ti,tx-internal-delay",
- DEFAULT_TX_ID_DELAY);
+ /* Existing behavior was to use default pin strapping delay in rgmii
+ * mode, but rgmii should have meant no delay. Warn existing users.
+ */
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+ u16 val = phy_read_mmd(phydev, DP83867_DEVADDR,
+ DP83867_STRAP_STS2);
+ u16 txskew = (val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK) >>
+ DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT;
+ u16 rxskew = (val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK) >>
+ DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT;
+
+ if (txskew != DP83867_STRAP_STS2_CLK_SKEW_NONE ||
+ rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE)
+ pr_warn("PHY has delays via pin strapping, but phy-mode = 'rgmii'\n"
+ "Should be 'rgmii-id' to use internal delays\n");
+ }
+
+ /* RX delay *must* be specified if internal delay of RX is used. */
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+ ret = ofnode_read_u32(node, "ti,rx-internal-delay",
+ &dp83867->rx_id_delay);
+ if (ret) {
+ pr_debug("ti,rx-internal-delay must be specified\n");
+ return ret;
+ }
+ if (dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) {
+ pr_debug("ti,rx-internal-delay value of %u out of range\n",
+ dp83867->rx_id_delay);
+ return -EINVAL;
+ }
+ }
+
+ /* TX delay *must* be specified if internal delay of RX is used. */
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+ ret = ofnode_read_u32(node, "ti,tx-internal-delay",
+ &dp83867->tx_id_delay);
+ if (ret) {
+ debug("ti,tx-internal-delay must be specified\n");
+ return ret;
+ }
+ if (dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) {
+ pr_debug("ti,tx-internal-delay value of %u out of range\n",
+ dp83867->tx_id_delay);
+ return -EINVAL;
+ }
+ }
dp83867->fifo_depth = ofnode_read_u32_default(node, "ti,fifo-depth",
DEFAULT_FIFO_DEPTH);
@@ -170,18 +234,6 @@ static int dp83867_of_init(struct phy_device *phydev)
if (ofnode_read_bool(node, "enet-phy-lane-no-swap"))
dp83867->port_mirroring = DP83867_PORT_MIRRORING_DIS;
-
- /* Clock output selection if muxing property is set */
- if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK) {
- val = phy_read_mmd(phydev, DP83867_DEVADDR,
- DP83867_IO_MUX_CFG);
- val &= ~DP83867_IO_MUX_CFG_CLK_O_SEL_MASK;
- val |= (dp83867->clk_output_sel <<
- DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT);
- phy_write_mmd(phydev, DP83867_DEVADDR,
- DP83867_IO_MUX_CFG, val);
- }
-
return 0;
}
#else
@@ -189,8 +241,8 @@ static int dp83867_of_init(struct phy_device *phydev)
{
struct dp83867_private *dp83867 = phydev->priv;
- dp83867->rx_id_delay = DEFAULT_RX_ID_DELAY;
- dp83867->tx_id_delay = DEFAULT_TX_ID_DELAY;
+ dp83867->rx_id_delay = DP83867_RGMIIDCTL_2_25_NS;
+ dp83867->tx_id_delay = DP83867_RGMIIDCTL_2_75_NS;
dp83867->fifo_depth = DEFAULT_FIFO_DEPTH;
dp83867->io_impedance = -EINVAL;
@@ -204,18 +256,11 @@ static int dp83867_config(struct phy_device *phydev)
unsigned int val, delay, cfg2;
int ret, bs;
- if (!phydev->priv) {
- dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL);
- if (!dp83867)
- return -ENOMEM;
+ dp83867 = (struct dp83867_private *)phydev->priv;
- phydev->priv = dp83867;
- ret = dp83867_of_init(phydev);
- if (ret)
- goto err_out;
- } else {
- dp83867 = (struct dp83867_private *)phydev->priv;
- }
+ ret = dp83867_of_init(phydev);
+ if (ret)
+ return ret;
/* Restart the PHY. */
val = phy_read(phydev, MDIO_DEVAD_NONE, DP83867_CTRL);
@@ -232,11 +277,11 @@ static int dp83867_config(struct phy_device *phydev)
}
if (phy_interface_is_rgmii(phydev)) {
- ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
- (DP83867_MDI_CROSSOVER_AUTO << DP83867_MDI_CROSSOVER) |
- (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT));
- if (ret)
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL);
+ if (val < 0)
goto err_out;
+ val &= ~DP83867_PHYCR_FIFO_DEPTH_MASK;
+ val |= (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT);
/* The code below checks if "port mirroring" N/A MODE4 has been
* enabled during power on bootstrap.
@@ -248,16 +293,39 @@ static int dp83867_config(struct phy_device *phydev)
* register's bit 11 (marked as RESERVED).
*/
- bs = phy_read_mmd(phydev, DP83867_DEVADDR,
- DP83867_STRAP_STS1);
- val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL);
- if (bs & DP83867_STRAP_STS1_RESERVED) {
+ bs = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS1);
+ if (bs & DP83867_STRAP_STS1_RESERVED)
val &= ~DP83867_PHYCR_RESERVED_MASK;
- phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
- val);
- }
- } else if (phy_interface_is_sgmii(phydev)) {
+ ret = phy_write(phydev, MDIO_DEVAD_NONE,
+ MII_DP83867_PHYCTRL, val);
+
+ val = phy_read_mmd(phydev, DP83867_DEVADDR,
+ DP83867_RGMIICTL);
+
+ val &= ~(DP83867_RGMII_TX_CLK_DELAY_EN |
+ DP83867_RGMII_RX_CLK_DELAY_EN);
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ val |= (DP83867_RGMII_TX_CLK_DELAY_EN |
+ DP83867_RGMII_RX_CLK_DELAY_EN);
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+ val |= DP83867_RGMII_TX_CLK_DELAY_EN;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+ val |= DP83867_RGMII_RX_CLK_DELAY_EN;
+
+ phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL, val);
+
+ delay = (dp83867->rx_id_delay |
+ (dp83867->tx_id_delay <<
+ DP83867_RGMII_TX_CLK_DELAY_SHIFT));
+
+ phy_write_mmd(phydev, DP83867_DEVADDR,
+ DP83867_RGMIIDCTL, delay);
+ }
+
+ if (phy_interface_is_sgmii(phydev)) {
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR,
(BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000));
@@ -282,57 +350,62 @@ static int dp83867_config(struct phy_device *phydev)
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_BISCR, 0x0);
}
- if (phy_interface_is_rgmii(phydev)) {
- val = phy_read_mmd(phydev, DP83867_DEVADDR,
- DP83867_RGMIICTL);
-
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
- val |= (DP83867_RGMII_TX_CLK_DELAY_EN |
- DP83867_RGMII_RX_CLK_DELAY_EN);
-
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
- val |= DP83867_RGMII_TX_CLK_DELAY_EN;
-
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
- val |= DP83867_RGMII_RX_CLK_DELAY_EN;
-
+ if (dp83867->io_impedance >= 0) {
+ val = phy_read_mmd(phydev,
+ DP83867_DEVADDR,
+ DP83867_IO_MUX_CFG);
+ val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
+ val |= dp83867->io_impedance &
+ DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
phy_write_mmd(phydev, DP83867_DEVADDR,
- DP83867_RGMIICTL, val);
+ DP83867_IO_MUX_CFG, val);
+ }
- delay = (dp83867->rx_id_delay |
- (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
+ if (dp83867->port_mirroring != DP83867_PORT_MIRRORING_KEEP)
+ dp83867_config_port_mirroring(phydev);
- phy_write_mmd(phydev, DP83867_DEVADDR,
- DP83867_RGMIIDCTL, delay);
+ /* Clock output selection if muxing property is set */
+ if (dp83867->set_clk_output) {
+ val = phy_read_mmd(phydev, DP83867_DEVADDR,
+ DP83867_IO_MUX_CFG);
- if (dp83867->io_impedance >= 0) {
- val = phy_read_mmd(phydev,
- DP83867_DEVADDR,
- DP83867_IO_MUX_CFG);
- val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
- val |= dp83867->io_impedance &
- DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
- phy_write_mmd(phydev, DP83867_DEVADDR,
- DP83867_IO_MUX_CFG, val);
+ if (dp83867->clk_output_sel == DP83867_CLK_O_SEL_OFF) {
+ val |= DP83867_IO_MUX_CFG_CLK_O_DISABLE;
+ } else {
+ val &= ~(DP83867_IO_MUX_CFG_CLK_O_SEL_MASK |
+ DP83867_IO_MUX_CFG_CLK_O_DISABLE);
+ val |= dp83867->clk_output_sel <<
+ DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT;
}
+ phy_write_mmd(phydev, DP83867_DEVADDR,
+ DP83867_IO_MUX_CFG, val);
}
- if (dp83867->port_mirroring != DP83867_PORT_MIRRORING_KEEP)
- dp83867_config_port_mirroring(phydev);
-
genphy_config_aneg(phydev);
return 0;
err_out:
- kfree(dp83867);
return ret;
}
+static int dp83867_probe(struct phy_device *phydev)
+{
+ struct dp83867_private *dp83867;
+
+ dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL);
+ if (!dp83867)
+ return -ENOMEM;
+
+ phydev->priv = dp83867;
+ return 0;
+}
+
static struct phy_driver DP83867_driver = {
.name = "TI DP83867",
.uid = 0x2000a231,
.mask = 0xfffffff0,
.features = PHY_GBIT_FEATURES,
+ .probe = dp83867_probe,
.config = &dp83867_config,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
diff --git a/drivers/net/phy/micrel_ksz8xxx.c b/drivers/net/phy/micrel_ksz8xxx.c
index daa57ce33c..e27fc45a28 100644
--- a/drivers/net/phy/micrel_ksz8xxx.c
+++ b/drivers/net/phy/micrel_ksz8xxx.c
@@ -24,6 +24,7 @@ static struct phy_driver KSZ804_driver = {
};
#define MII_KSZPHY_OMSO 0x16
+#define KSZPHY_OMSO_FACTORY_TEST BIT(15)
#define KSZPHY_OMSO_B_CAST_OFF (1 << 9)
static int ksz_genconfig_bcastoff(struct phy_device *phydev)
@@ -80,12 +81,30 @@ static struct phy_driver KSZ8051_driver = {
.shutdown = &genphy_shutdown,
};
+static int ksz8081_config(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);
+ if (ret < 0)
+ return ret;
+
+ ret &= ~KSZPHY_OMSO_FACTORY_TEST;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,
+ ret | KSZPHY_OMSO_B_CAST_OFF);
+ if (ret < 0)
+ return ret;
+
+ return genphy_config(phydev);
+}
+
static struct phy_driver KSZ8081_driver = {
.name = "Micrel KSZ8081",
.uid = 0x221560,
.mask = 0xfffff0,
.features = PHY_BASIC_FEATURES,
- .config = &ksz_genconfig_bcastoff,
+ .config = &ksz8081_config,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c
index c1e2860329..5aff7ed397 100644
--- a/drivers/net/phy/mv88e61xx.c
+++ b/drivers/net/phy/mv88e61xx.c
@@ -39,15 +39,11 @@
#define PHY_AUTONEGOTIATE_TIMEOUT 5000
-#define PORT_COUNT 11
-#define PORT_MASK ((1 << PORT_COUNT) - 1)
+#define PORT_MASK(port_count) ((1 << (port_count)) - 1)
/* Device addresses */
#define DEVADDR_PHY(p) (p)
-#define DEVADDR_PORT(p) (0x10 + (p))
#define DEVADDR_SERDES 0x0F
-#define DEVADDR_GLOBAL_1 0x1B
-#define DEVADDR_GLOBAL_2 0x1C
/* SMI indirection registers for multichip addressing mode */
#define SMI_CMD_REG 0x00
@@ -88,11 +84,7 @@
#define GLOBAL1_MON_CTRL_CPUDEST_SHIFT 4
#define GLOBAL1_MON_CTRL_CPUDEST_WIDTH 4
-#define PORT_REG_STATUS_LINK BIT(11)
-#define PORT_REG_STATUS_DUPLEX BIT(10)
-
#define PORT_REG_STATUS_SPEED_SHIFT 8
-#define PORT_REG_STATUS_SPEED_WIDTH 2
#define PORT_REG_STATUS_SPEED_10 0
#define PORT_REG_STATUS_SPEED_100 1
#define PORT_REG_STATUS_SPEED_1000 2
@@ -111,6 +103,7 @@
#define PORT_REG_PHYS_CTRL_DUPLEX_VALUE BIT(3)
#define PORT_REG_PHYS_CTRL_DUPLEX_FORCE BIT(2)
#define PORT_REG_PHYS_CTRL_SPD1000 BIT(1)
+#define PORT_REG_PHYS_CTRL_SPD100 BIT(0)
#define PORT_REG_PHYS_CTRL_SPD_MASK (BIT(1) | BIT(0))
#define PORT_REG_CTRL_PSTATE_SHIFT 0
@@ -124,14 +117,12 @@
#define SERDES_REG_CTRL_1_FORCE_LINK BIT(10)
-#define PHY_REG_CTRL1_ENERGY_DET_SHIFT 8
-#define PHY_REG_CTRL1_ENERGY_DET_WIDTH 2
-
/* Field values */
#define PORT_REG_CTRL_PSTATE_DISABLED 0
#define PORT_REG_CTRL_PSTATE_FORWARD 3
#define PHY_REG_CTRL1_ENERGY_DET_OFF 0
+#define PHY_REG_CTRL1_ENERGY_DET_SENSE_PULSE 1
#define PHY_REG_CTRL1_ENERGY_DET_SENSE_ONLY 2
#define PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT 3
@@ -182,17 +173,32 @@
#endif
/* ID register values for different switch models */
+#define PORT_SWITCH_ID_6020 0x0200
+#define PORT_SWITCH_ID_6070 0x0700
+#define PORT_SWITCH_ID_6071 0x0710
#define PORT_SWITCH_ID_6096 0x0980
#define PORT_SWITCH_ID_6097 0x0990
#define PORT_SWITCH_ID_6172 0x1720
#define PORT_SWITCH_ID_6176 0x1760
+#define PORT_SWITCH_ID_6220 0x2200
#define PORT_SWITCH_ID_6240 0x2400
+#define PORT_SWITCH_ID_6250 0x2500
#define PORT_SWITCH_ID_6352 0x3520
struct mv88e61xx_phy_priv {
struct mii_dev *mdio_bus;
int smi_addr;
int id;
+ int port_count; /* Number of switch ports */
+ int port_reg_base; /* Base of the switch port registers */
+ u16 port_stat_link_mask;/* Bitmask for port link status bits */
+ u16 port_stat_dup_mask; /* Bitmask for port duplex status bits */
+ u8 port_stat_speed_width;/* Width of speed status bitfield */
+ u8 global1; /* Offset of Switch Global 1 registers */
+ u8 global2; /* Offset of Switch Global 2 registers */
+ u8 phy_ctrl1_en_det_shift; /* 'EDet' bit field offset */
+ u8 phy_ctrl1_en_det_width; /* Width of 'EDet' bit field */
+ u8 phy_ctrl1_en_det_ctrl; /* 'EDet' control value */
};
static inline int smi_cmd(int cmd, int addr, int reg)
@@ -329,11 +335,12 @@ static int mv88e61xx_reg_write(struct phy_device *phydev, int dev, int reg,
static int mv88e61xx_phy_wait(struct phy_device *phydev)
{
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
int val;
u32 timeout = 100;
do {
- val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_2,
+ val = mv88e61xx_reg_read(phydev, priv->global2,
GLOBAL2_REG_PHY_CMD);
if (val >= 0 && (val & SMI_BUSY) == 0)
return 0;
@@ -347,13 +354,15 @@ static int mv88e61xx_phy_wait(struct phy_device *phydev)
static int mv88e61xx_phy_read_indirect(struct mii_dev *smi_wrapper, int dev,
int devad, int reg)
{
+ struct mv88e61xx_phy_priv *priv;
struct phy_device *phydev;
int res;
phydev = (struct phy_device *)smi_wrapper->priv;
+ priv = phydev->priv;
/* Issue command to read */
- res = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_2,
+ res = mv88e61xx_reg_write(phydev, priv->global2,
GLOBAL2_REG_PHY_CMD,
smi_cmd_read(dev, reg));
@@ -363,25 +372,27 @@ static int mv88e61xx_phy_read_indirect(struct mii_dev *smi_wrapper, int dev,
return res;
/* Read retrieved data */
- return mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_2,
+ return mv88e61xx_reg_read(phydev, priv->global2,
GLOBAL2_REG_PHY_DATA);
}
static int mv88e61xx_phy_write_indirect(struct mii_dev *smi_wrapper, int dev,
int devad, int reg, u16 data)
{
+ struct mv88e61xx_phy_priv *priv;
struct phy_device *phydev;
int res;
phydev = (struct phy_device *)smi_wrapper->priv;
+ priv = phydev->priv;
/* Set the data to write */
- res = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_2,
+ res = mv88e61xx_reg_write(phydev, priv->global2,
GLOBAL2_REG_PHY_DATA, data);
if (res < 0)
return res;
/* Issue the write command */
- res = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_2,
+ res = mv88e61xx_reg_write(phydev, priv->global2,
GLOBAL2_REG_PHY_CMD,
smi_cmd_write(dev, reg));
if (res < 0)
@@ -408,13 +419,18 @@ static int mv88e61xx_phy_write(struct phy_device *phydev, int phy,
static int mv88e61xx_port_read(struct phy_device *phydev, u8 port, u8 reg)
{
- return mv88e61xx_reg_read(phydev, DEVADDR_PORT(port), reg);
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
+
+ return mv88e61xx_reg_read(phydev, priv->port_reg_base + port, reg);
}
static int mv88e61xx_port_write(struct phy_device *phydev, u8 port, u8 reg,
u16 val)
{
- return mv88e61xx_reg_write(phydev, DEVADDR_PORT(port), reg, val);
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
+
+ return mv88e61xx_reg_write(phydev, priv->port_reg_base + port,
+ reg, val);
}
static int mv88e61xx_set_page(struct phy_device *phydev, u8 phy, u8 page)
@@ -515,12 +531,13 @@ static int mv88e61xx_parse_status(struct phy_device *phydev)
static int mv88e61xx_switch_reset(struct phy_device *phydev)
{
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
int time;
int val;
u8 port;
/* Disable all ports */
- for (port = 0; port < PORT_COUNT; port++) {
+ for (port = 0; port < priv->port_count; port++) {
val = mv88e61xx_port_read(phydev, port, PORT_REG_CTRL);
if (val < 0)
return val;
@@ -536,19 +553,19 @@ static int mv88e61xx_switch_reset(struct phy_device *phydev)
udelay(2000);
/* Reset switch */
- val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_1, GLOBAL1_CTRL);
+ val = mv88e61xx_reg_read(phydev, priv->global1, GLOBAL1_CTRL);
if (val < 0)
return val;
val |= GLOBAL1_CTRL_SWRESET;
- val = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_1,
- GLOBAL1_CTRL, val);
+ val = mv88e61xx_reg_write(phydev, priv->global1,
+ GLOBAL1_CTRL, val);
if (val < 0)
return val;
/* Wait up to 1 second for switch reset complete */
for (time = 1000; time; time--) {
- val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_1,
- GLOBAL1_CTRL);
+ val = mv88e61xx_reg_read(phydev, priv->global1,
+ GLOBAL1_CTRL);
if (val >= 0 && ((val & GLOBAL1_CTRL_SWRESET) == 0))
break;
udelay(1000);
@@ -628,6 +645,7 @@ static int mv88e61xx_port_set_vlan(struct phy_device *phydev, u8 port,
static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port)
{
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
int res;
int val;
bool forced = false;
@@ -635,7 +653,7 @@ static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port)
val = mv88e61xx_port_read(phydev, port, PORT_REG_STATUS);
if (val < 0)
return val;
- if (!(val & PORT_REG_STATUS_LINK)) {
+ if (!(val & priv->port_stat_link_mask)) {
/* Temporarily force link to read port configuration */
u32 timeout = 100;
forced = true;
@@ -658,7 +676,7 @@ static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port)
res = -EIO;
goto unforce;
}
- if (val & PORT_REG_STATUS_LINK)
+ if (val & priv->port_stat_link_mask)
break;
} while (--timeout);
@@ -668,13 +686,13 @@ static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port)
}
}
- if (val & PORT_REG_STATUS_DUPLEX)
+ if (val & priv->port_stat_dup_mask)
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
val = bitfield_extract(val, PORT_REG_STATUS_SPEED_SHIFT,
- PORT_REG_STATUS_SPEED_WIDTH);
+ priv->port_stat_speed_width);
switch (val) {
case PORT_REG_STATUS_SPEED_1000:
phydev->speed = SPEED_1000;
@@ -707,6 +725,7 @@ unforce:
static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port)
{
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
int val;
val = mv88e61xx_port_read(phydev, port, PORT_REG_PHYS_CTRL);
@@ -714,13 +733,19 @@ static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port)
return val;
val &= ~(PORT_REG_PHYS_CTRL_SPD_MASK |
- PORT_REG_PHYS_CTRL_FC_VALUE);
- val |= PORT_REG_PHYS_CTRL_PCS_AN_EN |
- PORT_REG_PHYS_CTRL_PCS_AN_RST |
- PORT_REG_PHYS_CTRL_FC_FORCE |
+ PORT_REG_PHYS_CTRL_FC_VALUE |
+ PORT_REG_PHYS_CTRL_FC_FORCE);
+ val |= PORT_REG_PHYS_CTRL_FC_FORCE |
PORT_REG_PHYS_CTRL_DUPLEX_VALUE |
- PORT_REG_PHYS_CTRL_DUPLEX_FORCE |
- PORT_REG_PHYS_CTRL_SPD1000;
+ PORT_REG_PHYS_CTRL_DUPLEX_FORCE;
+
+ if (priv->id == PORT_SWITCH_ID_6071) {
+ val |= PORT_REG_PHYS_CTRL_SPD100;
+ } else {
+ val |= PORT_REG_PHYS_CTRL_PCS_AN_EN |
+ PORT_REG_PHYS_CTRL_PCS_AN_RST |
+ PORT_REG_PHYS_CTRL_SPD1000;
+ }
if (port == CONFIG_MV88E61XX_CPU_PORT)
val |= PORT_REG_PHYS_CTRL_LINK_VALUE |
@@ -732,22 +757,23 @@ static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port)
static int mv88e61xx_set_cpu_port(struct phy_device *phydev)
{
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
int val;
/* Set CPUDest */
- val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_1, GLOBAL1_MON_CTRL);
+ val = mv88e61xx_reg_read(phydev, priv->global1, GLOBAL1_MON_CTRL);
if (val < 0)
return val;
val = bitfield_replace(val, GLOBAL1_MON_CTRL_CPUDEST_SHIFT,
GLOBAL1_MON_CTRL_CPUDEST_WIDTH,
CONFIG_MV88E61XX_CPU_PORT);
- val = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_1,
- GLOBAL1_MON_CTRL, val);
+ val = mv88e61xx_reg_write(phydev, priv->global1,
+ GLOBAL1_MON_CTRL, val);
if (val < 0)
return val;
/* Allow CPU to route to any port */
- val = PORT_MASK & ~(1 << CONFIG_MV88E61XX_CPU_PORT);
+ val = PORT_MASK(priv->port_count) & ~(1 << CONFIG_MV88E61XX_CPU_PORT);
val = mv88e61xx_port_set_vlan(phydev, CONFIG_MV88E61XX_CPU_PORT, val);
if (val < 0)
return val;
@@ -821,6 +847,7 @@ static int mv88e61xx_phy_enable(struct phy_device *phydev, u8 phy)
static int mv88e61xx_phy_setup(struct phy_device *phydev, u8 phy)
{
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
int val;
/*
@@ -830,9 +857,9 @@ static int mv88e61xx_phy_setup(struct phy_device *phydev, u8 phy)
val = mv88e61xx_phy_read(phydev, phy, PHY_REG_CTRL1);
if (val < 0)
return val;
- val = bitfield_replace(val, PHY_REG_CTRL1_ENERGY_DET_SHIFT,
- PHY_REG_CTRL1_ENERGY_DET_WIDTH,
- PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT);
+ val = bitfield_replace(val, priv->phy_ctrl1_en_det_shift,
+ priv->phy_ctrl1_en_det_width,
+ priv->phy_ctrl1_en_det_ctrl);
val = mv88e61xx_phy_write(phydev, phy, PHY_REG_CTRL1, val);
if (val < 0)
return val;
@@ -856,6 +883,48 @@ static int mv88e61xx_phy_config_port(struct phy_device *phydev, u8 phy)
return 0;
}
+/*
+ * This function is used to pre-configure the required register
+ * offsets, so that the indirect register access to the PHY registers
+ * is possible. This is necessary to be able to read the PHY ID
+ * while driver probing or in get_phy_id(). The globalN register
+ * offsets must be initialized correctly for a detected switch,
+ * otherwise detection of the PHY ID won't work!
+ */
+static int mv88e61xx_priv_reg_offs_pre_init(struct phy_device *phydev)
+{
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
+
+ /*
+ * Initial 'port_reg_base' value must be an offset of existing
+ * port register, then reading the ID should succeed. First, try
+ * to read via port registers with device address 0x10 (88E6096
+ * and compatible switches).
+ */
+ priv->port_reg_base = 0x10;
+ priv->id = mv88e61xx_get_switch_id(phydev);
+ if (priv->id != 0xfff0) {
+ priv->global1 = 0x1B;
+ priv->global2 = 0x1C;
+ return 0;
+ }
+
+ /*
+ * Now try via port registers with device address 0x08
+ * (88E6020 and compatible switches).
+ */
+ priv->port_reg_base = 0x08;
+ priv->id = mv88e61xx_get_switch_id(phydev);
+ if (priv->id != 0xfff0) {
+ priv->global1 = 0x0F;
+ priv->global2 = 0x07;
+ return 0;
+ }
+
+ debug("%s Unknown ID 0x%x\n", __func__, priv->id);
+ return -ENODEV;
+}
+
static int mv88e61xx_probe(struct phy_device *phydev)
{
struct mii_dev *smi_wrapper;
@@ -910,13 +979,57 @@ static int mv88e61xx_probe(struct phy_device *phydev)
phydev->priv = priv;
- priv->id = mv88e61xx_get_switch_id(phydev);
+ res = mv88e61xx_priv_reg_offs_pre_init(phydev);
+ if (res < 0)
+ return res;
+
+ debug("%s ID 0x%x\n", __func__, priv->id);
+
+ switch (priv->id) {
+ case PORT_SWITCH_ID_6096:
+ case PORT_SWITCH_ID_6097:
+ case PORT_SWITCH_ID_6172:
+ case PORT_SWITCH_ID_6176:
+ case PORT_SWITCH_ID_6240:
+ case PORT_SWITCH_ID_6352:
+ priv->port_count = 11;
+ priv->port_stat_link_mask = BIT(11);
+ priv->port_stat_dup_mask = BIT(10);
+ priv->port_stat_speed_width = 2;
+ priv->phy_ctrl1_en_det_shift = 8;
+ priv->phy_ctrl1_en_det_width = 2;
+ priv->phy_ctrl1_en_det_ctrl =
+ PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT;
+ break;
+ case PORT_SWITCH_ID_6020:
+ case PORT_SWITCH_ID_6070:
+ case PORT_SWITCH_ID_6071:
+ case PORT_SWITCH_ID_6220:
+ case PORT_SWITCH_ID_6250:
+ priv->port_count = 7;
+ priv->port_stat_link_mask = BIT(12);
+ priv->port_stat_dup_mask = BIT(9);
+ priv->port_stat_speed_width = 1;
+ priv->phy_ctrl1_en_det_shift = 14;
+ priv->phy_ctrl1_en_det_width = 1;
+ priv->phy_ctrl1_en_det_ctrl =
+ PHY_REG_CTRL1_ENERGY_DET_SENSE_PULSE;
+ break;
+ default:
+ free(priv);
+ return -ENODEV;
+ }
+
+ res = mdio_register(smi_wrapper);
+ if (res)
+ printf("Failed to register SMI bus\n");
return 0;
}
static int mv88e61xx_phy_config(struct phy_device *phydev)
{
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
int res;
int i;
int ret = -1;
@@ -925,7 +1038,7 @@ static int mv88e61xx_phy_config(struct phy_device *phydev)
if (res < 0)
return res;
- for (i = 0; i < PORT_COUNT; i++) {
+ for (i = 0; i < priv->port_count; i++) {
if ((1 << i) & CONFIG_MV88E61XX_PHY_PORTS) {
phydev->addr = i;
@@ -988,13 +1101,14 @@ static int mv88e61xx_phy_is_connected(struct phy_device *phydev)
static int mv88e61xx_phy_startup(struct phy_device *phydev)
{
+ struct mv88e61xx_phy_priv *priv = phydev->priv;
int i;
int link = 0;
int res;
int speed = phydev->speed;
int duplex = phydev->duplex;
- for (i = 0; i < PORT_COUNT; i++) {
+ for (i = 0; i < priv->port_count; i++) {
if ((1 << i) & CONFIG_MV88E61XX_PHY_PORTS) {
phydev->addr = i;
if (!mv88e61xx_phy_is_connected(phydev))
@@ -1040,10 +1154,22 @@ static struct phy_driver mv88e609x_driver = {
.shutdown = &genphy_shutdown,
};
+static struct phy_driver mv88e6071_driver = {
+ .name = "Marvell MV88E6071",
+ .uid = 0x1410db0,
+ .mask = 0xfffffff0,
+ .features = PHY_BASIC_FEATURES | SUPPORTED_MII,
+ .probe = mv88e61xx_probe,
+ .config = mv88e61xx_phy_config,
+ .startup = mv88e61xx_phy_startup,
+ .shutdown = &genphy_shutdown,
+};
+
int phy_mv88e61xx_init(void)
{
phy_register(&mv88e61xx_driver);
phy_register(&mv88e609x_driver);
+ phy_register(&mv88e6071_driver);
return 0;
}
@@ -1068,6 +1194,16 @@ int get_phy_id(struct mii_dev *bus, int smi_addr, int devad, u32 *phy_id)
temp_phy.priv = &temp_priv;
temp_mii.priv = &temp_phy;
+ /*
+ * get_phy_id() can be called by framework before mv88e61xx driver
+ * probing, in this case the global register offsets are not
+ * initialized yet. Do this initialization here before indirect
+ * PHY register access.
+ */
+ val = mv88e61xx_priv_reg_offs_pre_init(&temp_phy);
+ if (val < 0)
+ return val;
+
val = mv88e61xx_phy_read_indirect(&temp_mii, 0, devad, MII_PHYSID1);
if (val < 0)
return -EIO;
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index f2d17aa91a..80a7664e49 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -256,11 +256,11 @@ int genphy_update_link(struct phy_device *phydev)
return -EINTR;
}
- if ((i++ % 500) == 0)
+ if ((i++ % 10) == 0)
printf(".");
- udelay(1000); /* 1 ms */
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+ mdelay(50); /* 50 ms */
}
printf(" done\n");
phydev->link = 1;
@@ -997,7 +997,7 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr,
#endif
{
struct phy_device *phydev = NULL;
- uint mask = (addr > 0) ? (1 << addr) : 0xffffffff;
+ uint mask = (addr >= 0) ? (1 << addr) : 0xffffffff;
#ifdef CONFIG_PHY_FIXED
phydev = phy_connect_fixed(bus, dev, interface);
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index 53454f2f21..5ccdfdd683 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -253,6 +253,7 @@ static struct {
{"RTL-8169sc/8110sc", 0x18, 0xff7e1880,},
{"RTL-8168b/8111sb", 0x30, 0xff7e1880,},
{"RTL-8168b/8111sb", 0x38, 0xff7e1880,},
+ {"RTL-8168c/8111c", 0x3c, 0xff7e1880,},
{"RTL-8168d/8111d", 0x28, 0xff7e1880,},
{"RTL-8168evl/8111evl", 0x2e, 0xff7e1880,},
{"RTL-8168/8111g", 0x4c, 0xff7e1880,},
diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c
index 06b0663950..2590486810 100644
--- a/drivers/net/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ti/am65-cpsw-nuss.c
@@ -99,7 +99,6 @@ struct am65_cpsw_common {
u32 port_num;
struct am65_cpsw_port ports[AM65_CPSW_CPSWNU_MAX_PORTS];
- u32 rflow_id_base;
struct mii_dev *bus;
u32 bus_freq;
@@ -276,6 +275,7 @@ static int am65_cpsw_start(struct udevice *dev)
struct am65_cpsw_common *common = priv->cpsw_common;
struct am65_cpsw_port *port = &common->ports[priv->port_id];
struct am65_cpsw_port *port0 = &common->ports[0];
+ struct ti_udma_drv_chan_cfg_data *dma_rx_cfg_data;
int ret, i;
ret = power_domain_on(&common->pwrdmn);
@@ -341,8 +341,11 @@ static int am65_cpsw_start(struct udevice *dev)
writel(PKTSIZE_ALIGN, port0->port_base + AM65_CPSW_PN_RX_MAXLEN_REG);
/* set base flow_id */
- writel(common->rflow_id_base,
+ dma_get_cfg(&common->dma_rx, 0, (void **)&dma_rx_cfg_data);
+ writel(dma_rx_cfg_data->flow_id_base,
port0->port_base + AM65_CPSW_P0_FLOW_ID_REG);
+ dev_info(dev, "K3 CPSW: rflow_id_base: %u\n",
+ dma_rx_cfg_data->flow_id_base);
/* Reset and enable the ALE */
writel(AM65_CPSW_ALE_CTL_REG_ENABLE | AM65_CPSW_ALE_CTL_REG_RESET_TBL |
@@ -669,11 +672,6 @@ static int am65_cpsw_probe_cpsw(struct udevice *dev)
AM65_CPSW_CPSW_NU_ALE_BASE;
cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE;
- cpsw_common->rflow_id_base = 0;
- cpsw_common->rflow_id_base =
- dev_read_u32_default(dev, "ti,rx-flow-id-base",
- cpsw_common->rflow_id_base);
-
ports_np = dev_read_subnode(dev, "ports");
if (!ofnode_valid(ports_np)) {
ret = -ENOENT;
@@ -761,12 +759,11 @@ static int am65_cpsw_probe_cpsw(struct udevice *dev)
if (ret)
goto out;
- dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u rflow_id_base:%u mdio_freq:%u\n",
+ dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u mdio_freq:%u\n",
readl(cpsw_common->ss_base),
readl(cpsw_common->cpsw_base),
readl(cpsw_common->ale_base),
cpsw_common->port_num,
- cpsw_common->rflow_id_base,
cpsw_common->bus_freq);
out:
@@ -777,6 +774,7 @@ out:
static const struct udevice_id am65_cpsw_nuss_ids[] = {
{ .compatible = "ti,am654-cpsw-nuss" },
+ { .compatible = "ti,j721e-cpsw-nuss" },
{ }
};
diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile
index 83913f668f..fcf19f877a 100644
--- a/drivers/pinctrl/rockchip/Makefile
+++ b/drivers/pinctrl/rockchip/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_ROCKCHIP_RK3128) += pinctrl-rk3128.o
obj-$(CONFIG_ROCKCHIP_RK3188) += pinctrl-rk3188.o
obj-$(CONFIG_ROCKCHIP_RK322X) += pinctrl-rk322x.o
obj-$(CONFIG_ROCKCHIP_RK3288) += pinctrl-rk3288.o
+obj-$(CONFIG_ROCKCHIP_RK3308) += pinctrl-rk3308.o
obj-$(CONFIG_ROCKCHIP_RK3328) += pinctrl-rk3328.o
obj-$(CONFIG_ROCKCHIP_RK3368) += pinctrl-rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3399) += pinctrl-rk3399.o
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3308.c b/drivers/pinctrl/rockchip/pinctrl-rk3308.c
new file mode 100644
index 0000000000..abd57e54a5
--- /dev/null
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3308.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#include "pinctrl-rockchip.h"
+
+static struct rockchip_mux_recalced_data rk3308_mux_recalced_data[] = {
+ {
+ .num = 1,
+ .pin = 14,
+ .reg = 0x28,
+ .bit = 12,
+ .mask = 0xf
+ }, {
+ .num = 1,
+ .pin = 15,
+ .reg = 0x2c,
+ .bit = 0,
+ .mask = 0x3
+ }, {
+ .num = 1,
+ .pin = 18,
+ .reg = 0x30,
+ .bit = 4,
+ .mask = 0xf
+ }, {
+ .num = 1,
+ .pin = 19,
+ .reg = 0x30,
+ .bit = 8,
+ .mask = 0xf
+ }, {
+ .num = 1,
+ .pin = 20,
+ .reg = 0x30,
+ .bit = 12,
+ .mask = 0xf
+ }, {
+ .num = 1,
+ .pin = 21,
+ .reg = 0x34,
+ .bit = 0,
+ .mask = 0xf
+ }, {
+ .num = 1,
+ .pin = 22,
+ .reg = 0x34,
+ .bit = 4,
+ .mask = 0xf
+ }, {
+ .num = 1,
+ .pin = 23,
+ .reg = 0x34,
+ .bit = 8,
+ .mask = 0xf
+ }, {
+ .num = 3,
+ .pin = 12,
+ .reg = 0x68,
+ .bit = 8,
+ .mask = 0xf
+ }, {
+ .num = 3,
+ .pin = 13,
+ .reg = 0x68,
+ .bit = 12,
+ .mask = 0xf
+ }, {
+ .num = 2,
+ .pin = 2,
+ .reg = 0x608,
+ .bit = 0,
+ .mask = 0x7
+ }, {
+ .num = 2,
+ .pin = 3,
+ .reg = 0x608,
+ .bit = 4,
+ .mask = 0x7
+ }, {
+ .num = 2,
+ .pin = 16,
+ .reg = 0x610,
+ .bit = 8,
+ .mask = 0x7
+ }, {
+ .num = 3,
+ .pin = 10,
+ .reg = 0x610,
+ .bit = 0,
+ .mask = 0x7
+ }, {
+ .num = 3,
+ .pin = 11,
+ .reg = 0x610,
+ .bit = 4,
+ .mask = 0x7
+ },
+};
+
+static struct rockchip_mux_route_data rk3308_mux_route_data[] = {
+ {
+ /* rtc_clk */
+ .bank_num = 0,
+ .pin = 19,
+ .func = 1,
+ .route_offset = 0x314,
+ .route_val = BIT(16 + 0) | BIT(0),
+ }, {
+ /* uart2_rxm0 */
+ .bank_num = 1,
+ .pin = 22,
+ .func = 2,
+ .route_offset = 0x314,
+ .route_val = BIT(16 + 2) | BIT(16 + 3),
+ }, {
+ /* uart2_rxm1 */
+ .bank_num = 4,
+ .pin = 26,
+ .func = 2,
+ .route_offset = 0x314,
+ .route_val = BIT(16 + 2) | BIT(16 + 3) | BIT(2),
+ }, {
+ /* i2c3_sdam0 */
+ .bank_num = 0,
+ .pin = 15,
+ .func = 2,
+ .route_offset = 0x608,
+ .route_val = BIT(16 + 8) | BIT(16 + 9),
+ }, {
+ /* i2c3_sdam1 */
+ .bank_num = 3,
+ .pin = 12,
+ .func = 2,
+ .route_offset = 0x608,
+ .route_val = BIT(16 + 8) | BIT(16 + 9) | BIT(8),
+ }, {
+ /* i2c3_sdam2 */
+ .bank_num = 2,
+ .pin = 0,
+ .func = 3,
+ .route_offset = 0x608,
+ .route_val = BIT(16 + 8) | BIT(16 + 9) | BIT(9),
+ }, {
+ /* i2s-8ch-1-sclktxm0 */
+ .bank_num = 1,
+ .pin = 3,
+ .func = 2,
+ .route_offset = 0x308,
+ .route_val = BIT(16 + 3),
+ }, {
+ /* i2s-8ch-1-sclkrxm0 */
+ .bank_num = 1,
+ .pin = 4,
+ .func = 2,
+ .route_offset = 0x308,
+ .route_val = BIT(16 + 3),
+ }, {
+ /* i2s-8ch-1-sclktxm1 */
+ .bank_num = 1,
+ .pin = 13,
+ .func = 2,
+ .route_offset = 0x308,
+ .route_val = BIT(16 + 3) | BIT(3),
+ }, {
+ /* i2s-8ch-1-sclkrxm1 */
+ .bank_num = 1,
+ .pin = 14,
+ .func = 2,
+ .route_offset = 0x308,
+ .route_val = BIT(16 + 3) | BIT(3),
+ }, {
+ /* pdm-clkm0 */
+ .bank_num = 1,
+ .pin = 4,
+ .func = 3,
+ .route_offset = 0x308,
+ .route_val = BIT(16 + 12) | BIT(16 + 13),
+ }, {
+ /* pdm-clkm1 */
+ .bank_num = 1,
+ .pin = 14,
+ .func = 4,
+ .route_offset = 0x308,
+ .route_val = BIT(16 + 12) | BIT(16 + 13) | BIT(12),
+ }, {
+ /* pdm-clkm2 */
+ .bank_num = 2,
+ .pin = 6,
+ .func = 2,
+ .route_offset = 0x308,
+ .route_val = BIT(16 + 12) | BIT(16 + 13) | BIT(13),
+ }, {
+ /* pdm-clkm-m2 */
+ .bank_num = 2,
+ .pin = 4,
+ .func = 3,
+ .route_offset = 0x600,
+ .route_val = BIT(16 + 2) | BIT(2),
+ }, {
+ /* spi1_miso */
+ .bank_num = 3,
+ .pin = 10,
+ .func = 3,
+ .route_offset = 0x314,
+ .route_val = BIT(16 + 9),
+ }, {
+ /* spi1_miso_m1 */
+ .bank_num = 2,
+ .pin = 4,
+ .func = 2,
+ .route_offset = 0x314,
+ .route_val = BIT(16 + 9) | BIT(9),
+ }, {
+ /* mac_rxd0_m0 */
+ .bank_num = 1,
+ .pin = 20,
+ .func = 3,
+ .route_offset = 0x314,
+ .route_val = BIT(16 + 14),
+ }, {
+ /* mac_rxd0_m1 */
+ .bank_num = 4,
+ .pin = 2,
+ .func = 2,
+ .route_offset = 0x314,
+ .route_val = BIT(16 + 14) | BIT(14),
+ }, {
+ /* uart3_rx */
+ .bank_num = 3,
+ .pin = 12,
+ .func = 4,
+ .route_offset = 0x314,
+ .route_val = BIT(16 + 15),
+ }, {
+ /* uart3_rx_m1 */
+ .bank_num = 0,
+ .pin = 17,
+ .func = 3,
+ .route_offset = 0x314,
+ .route_val = BIT(16 + 15) | BIT(15),
+ },
+};
+
+static int rk3308_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data, route_reg, route_val;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ if (bank->recalced_mask & BIT(pin))
+ rockchip_get_recalced_mux(bank, pin, &reg, &bit, &mask);
+
+ if (bank->route_mask & BIT(pin)) {
+ if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
+ &route_val)) {
+ ret = regmap_write(regmap, route_reg, route_val);
+ if (ret)
+ return ret;
+ }
+ }
+
+ data = (mask << (bit + 16));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
+#define RK3308_PULL_OFFSET 0xa0
+
+static void rk3308_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+
+ *regmap = priv->regmap_base;
+ *reg = RK3308_PULL_OFFSET;
+ *reg += bank->bank_num * ROCKCHIP_PULL_BANK_STRIDE;
+ *reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
+
+ *bit = (pin_num % ROCKCHIP_PULL_PINS_PER_REG);
+ *bit *= ROCKCHIP_PULL_BITS_PER_PIN;
+}
+
+static int rk3308_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -ENOTSUPP;
+
+ rk3308_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ type = bank->pull_type[pin_num / 8];
+ ret = rockchip_translate_pull_value(type, pull);
+ if (ret < 0) {
+ debug("unsupported pull setting %d\n", pull);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
+#define RK3308_DRV_GRF_OFFSET 0x100
+
+static void rk3308_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+
+ *regmap = priv->regmap_base;
+ *reg = RK3308_DRV_GRF_OFFSET;
+ *reg += bank->bank_num * ROCKCHIP_DRV_BANK_STRIDE;
+ *reg += ((pin_num / ROCKCHIP_DRV_PINS_PER_REG) * 4);
+
+ *bit = (pin_num % ROCKCHIP_DRV_PINS_PER_REG);
+ *bit *= ROCKCHIP_DRV_BITS_PER_PIN;
+}
+
+static int rk3308_set_drive(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u32 data;
+ u8 bit;
+ int type = bank->drv[pin_num / 8].drv_type;
+
+ rk3308_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ ret = rockchip_translate_drive_value(type, strength);
+ if (ret < 0) {
+ debug("unsupported driver strength %d\n", strength);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+ return ret;
+}
+
+#define RK3308_SCHMITT_PINS_PER_REG 8
+#define RK3308_SCHMITT_BANK_STRIDE 16
+#define RK3308_SCHMITT_GRF_OFFSET 0x1a0
+
+static int rk3308_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num,
+ struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+
+ *regmap = priv->regmap_base;
+ *reg = RK3308_SCHMITT_GRF_OFFSET;
+
+ *reg += bank->bank_num * RK3308_SCHMITT_BANK_STRIDE;
+ *reg += ((pin_num / RK3308_SCHMITT_PINS_PER_REG) * 4);
+ *bit = pin_num % RK3308_SCHMITT_PINS_PER_REG;
+
+ return 0;
+}
+
+static int rk3308_set_schmitt(struct rockchip_pin_bank *bank,
+ int pin_num, int enable)
+{
+ struct regmap *regmap;
+ int reg;
+ u8 bit;
+ u32 data;
+
+ rk3308_calc_schmitt_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ /* enable the write to the equivalent lower bits */
+ data = BIT(bit + 16) | (enable << bit);
+
+ return regmap_write(regmap, reg, data);
+}
+
+static struct rockchip_pin_bank rk3308_pin_banks[] = {
+ PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT),
+ PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT),
+ PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT),
+ PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT),
+ PIN_BANK_IOMUX_FLAGS(4, 32, "gpio4", IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT,
+ IOMUX_8WIDTH_2BIT),
+};
+
+static struct rockchip_pin_ctrl rk3308_pin_ctrl = {
+ .pin_banks = rk3308_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3308_pin_banks),
+ .grf_mux_offset = 0x0,
+ .iomux_recalced = rk3308_mux_recalced_data,
+ .niomux_recalced = ARRAY_SIZE(rk3308_mux_recalced_data),
+ .iomux_routes = rk3308_mux_route_data,
+ .niomux_routes = ARRAY_SIZE(rk3308_mux_route_data),
+ .set_mux = rk3308_set_mux,
+ .set_drive = rk3308_set_drive,
+ .set_pull = rk3308_set_pull,
+ .set_schmitt = rk3308_set_schmitt,
+};
+
+static const struct udevice_id rk3308_pinctrl_ids[] = {
+ {
+ .compatible = "rockchip,rk3308-pinctrl",
+ .data = (ulong)&rk3308_pin_ctrl
+ },
+ { }
+};
+
+U_BOOT_DRIVER(pinctrl_rk3308) = {
+ .name = "rockchip_rk3308_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = rk3308_pinctrl_ids,
+ .priv_auto_alloc_size = sizeof(struct rockchip_pinctrl_priv),
+ .ops = &rockchip_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .bind = dm_scan_fdt_dev,
+#endif
+ .probe = rockchip_pinctrl_probe,
+};
diff --git a/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c b/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
index 80dc431d20..0fd0416b18 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
@@ -539,7 +539,8 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(struct udevice *d
* 4bit iomux'es are spread over two registers.
*/
inc = (iom->type & (IOMUX_WIDTH_4BIT |
- IOMUX_WIDTH_3BIT)) ? 8 : 4;
+ IOMUX_WIDTH_3BIT |
+ IOMUX_8WIDTH_2BIT)) ? 8 : 4;
if (iom->type & IOMUX_SOURCE_PMU)
pmu_offs += inc;
else
diff --git a/drivers/pinctrl/rockchip/pinctrl-rockchip.h b/drivers/pinctrl/rockchip/pinctrl-rockchip.h
index 9651e9c7a6..5edc7cbd74 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rockchip.h
+++ b/drivers/pinctrl/rockchip/pinctrl-rockchip.h
@@ -16,6 +16,7 @@
#define IOMUX_SOURCE_PMU BIT(2)
#define IOMUX_UNROUTED BIT(3)
#define IOMUX_WIDTH_3BIT BIT(4)
+#define IOMUX_8WIDTH_2BIT BIT(5)
/**
* Defined some common pins constants
diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c
index 88db294cf1..46888e9077 100644
--- a/drivers/pwm/rk_pwm.c
+++ b/drivers/pwm/rk_pwm.c
@@ -15,22 +15,38 @@
#include <asm/arch-rockchip/pwm.h>
#include <power/regulator.h>
+DECLARE_GLOBAL_DATA_PTR;
+
+struct rockchip_pwm_data {
+ struct rockchip_pwm_regs regs;
+ unsigned int prescaler;
+ bool supports_polarity;
+ bool supports_lock;
+ u32 enable_conf;
+ u32 enable_conf_mask;
+};
+
struct rk_pwm_priv {
- struct rk3288_pwm *regs;
+ fdt_addr_t base;
ulong freq;
- uint enable_conf;
+ u32 conf_polarity;
+ const struct rockchip_pwm_data *data;
};
static int rk_pwm_set_invert(struct udevice *dev, uint channel, bool polarity)
{
struct rk_pwm_priv *priv = dev_get_priv(dev);
+ if (!priv->data->supports_polarity) {
+ debug("%s: Do not support polarity\n", __func__);
+ return 0;
+ }
+
debug("%s: polarity=%u\n", __func__, polarity);
- priv->enable_conf &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK);
if (polarity)
- priv->enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE;
+ priv->conf_polarity = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE;
else
- priv->enable_conf |= PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
+ priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
return 0;
}
@@ -39,20 +55,44 @@ static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
uint duty_ns)
{
struct rk_pwm_priv *priv = dev_get_priv(dev);
- struct rk3288_pwm *regs = priv->regs;
+ const struct rockchip_pwm_regs *regs = &priv->data->regs;
unsigned long period, duty;
+ u32 ctrl;
debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
- writel(PWM_SEL_SRC_CLK | PWM_OUTPUT_LEFT | PWM_LP_DISABLE |
- PWM_CONTINUOUS | priv->enable_conf |
- RK_PWM_DISABLE,
- &regs->ctrl);
- period = lldiv((uint64_t)(priv->freq / 1000) * period_ns, 1000000);
- duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns, 1000000);
+ ctrl = readl(priv->base + regs->ctrl);
+ /*
+ * Lock the period and duty of previous configuration, then
+ * change the duty and period, that would not be effective.
+ */
+ if (priv->data->supports_lock) {
+ ctrl |= PWM_LOCK;
+ writel(ctrl, priv->base + regs->ctrl);
+ }
+
+ period = lldiv((uint64_t)priv->freq * period_ns,
+ priv->data->prescaler * 1000000000);
+ duty = lldiv((uint64_t)priv->freq * duty_ns,
+ priv->data->prescaler * 1000000000);
+
+ writel(period, priv->base + regs->period);
+ writel(duty, priv->base + regs->duty);
+
+ if (priv->data->supports_polarity) {
+ ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK);
+ ctrl |= priv->conf_polarity;
+ }
+
+ /*
+ * Unlock and set polarity at the same time,
+ * the configuration of duty, period and polarity
+ * would be effective together at next period.
+ */
+ if (priv->data->supports_lock)
+ ctrl &= ~PWM_LOCK;
+ writel(ctrl, priv->base + regs->ctrl);
- writel(period, &regs->period_hpr);
- writel(duty, &regs->duty_lpr);
debug("%s: period=%lu, duty=%lu\n", __func__, period, duty);
return 0;
@@ -61,10 +101,20 @@ static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
{
struct rk_pwm_priv *priv = dev_get_priv(dev);
- struct rk3288_pwm *regs = priv->regs;
+ const struct rockchip_pwm_regs *regs = &priv->data->regs;
+ u32 ctrl;
debug("%s: Enable '%s'\n", __func__, dev->name);
- clrsetbits_le32(&regs->ctrl, RK_PWM_ENABLE, enable ? RK_PWM_ENABLE : 0);
+
+ ctrl = readl(priv->base + regs->ctrl);
+ ctrl &= ~priv->data->enable_conf_mask;
+
+ if (enable)
+ ctrl |= priv->data->enable_conf;
+ else
+ ctrl &= ~priv->data->enable_conf;
+
+ writel(ctrl, priv->base + regs->ctrl);
return 0;
}
@@ -73,7 +123,7 @@ static int rk_pwm_ofdata_to_platdata(struct udevice *dev)
{
struct rk_pwm_priv *priv = dev_get_priv(dev);
- priv->regs = (struct rk3288_pwm *)dev_read_addr(dev);
+ priv->base = dev_read_addr(dev);
return 0;
}
@@ -89,8 +139,12 @@ static int rk_pwm_probe(struct udevice *dev)
debug("%s get clock fail!\n", __func__);
return -EINVAL;
}
+
priv->freq = clk_get_rate(&clk);
- priv->enable_conf = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
+ priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev);
+
+ if (priv->data->supports_polarity)
+ priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
return 0;
}
@@ -101,8 +155,54 @@ static const struct pwm_ops rk_pwm_ops = {
.set_enable = rk_pwm_set_enable,
};
+static const struct rockchip_pwm_data pwm_data_v1 = {
+ .regs = {
+ .duty = 0x04,
+ .period = 0x08,
+ .cntr = 0x00,
+ .ctrl = 0x0c,
+ },
+ .prescaler = 2,
+ .supports_polarity = false,
+ .supports_lock = false,
+ .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
+ .enable_conf_mask = BIT(1) | BIT(3),
+};
+
+static const struct rockchip_pwm_data pwm_data_v2 = {
+ .regs = {
+ .duty = 0x08,
+ .period = 0x04,
+ .cntr = 0x00,
+ .ctrl = 0x0c,
+ },
+ .prescaler = 1,
+ .supports_polarity = true,
+ .supports_lock = false,
+ .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
+ PWM_CONTINUOUS,
+ .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
+};
+
+static const struct rockchip_pwm_data pwm_data_v3 = {
+ .regs = {
+ .duty = 0x08,
+ .period = 0x04,
+ .cntr = 0x00,
+ .ctrl = 0x0c,
+ },
+ .prescaler = 1,
+ .supports_polarity = true,
+ .supports_lock = true,
+ .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
+ PWM_CONTINUOUS,
+ .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
+};
+
static const struct udevice_id rk_pwm_ids[] = {
- { .compatible = "rockchip,rk3288-pwm" },
+ { .compatible = "rockchip,rk2928-pwm", .data = (ulong)&pwm_data_v1},
+ { .compatible = "rockchip,rk3288-pwm", .data = (ulong)&pwm_data_v2},
+ { .compatible = "rockchip,rk3328-pwm", .data = (ulong)&pwm_data_v3},
{ }
};
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 8778cc7b26..89e71cc7eb 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -7,6 +7,7 @@ menu "Real Time Clock"
config DM_RTC
bool "Enable Driver Model for RTC drivers"
depends on DM
+ select LIB_DATE
help
Enable drver model for real-time-clock drivers. The RTC uclass
then provides the rtc_get()/rtc_set() interface, delegating to
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f97a669982..e8875ce10f 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -7,7 +7,6 @@
obj-$(CONFIG_$(SPL_TPL_)DM_RTC) += rtc-uclass.o
obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o
-obj-y += date.o
obj-y += rtc-lib.o
obj-$(CONFIG_RTC_DAVINCI) += davinci.o
obj-$(CONFIG_RTC_DS1302) += ds1302.o
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index 67a0e8caae..1ffdfe0d90 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -18,6 +18,7 @@
#include "ubifs.h"
#include <u-boot/zlib.h>
+#include <linux/compat.h>
#include <linux/err.h>
#include <linux/lzo.h>
@@ -70,24 +71,6 @@ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
#ifdef __UBOOT__
-/* from mm/util.c */
-
-/**
- * kmemdup - duplicate region of memory
- *
- * @src: memory region to duplicate
- * @len: memory region length
- * @gfp: GFP mask to use
- */
-void *kmemdup(const void *src, size_t len, gfp_t gfp)
-{
- void *p;
-
- p = kmalloc(len, gfp);
- if (p)
- memcpy(p, src, len);
- return p;
-}
struct crypto_comp {
int compressor;
diff --git a/include/configs/ax25-ae350.h b/include/configs/ax25-ae350.h
index 5fd7a6043f..4504962171 100644
--- a/include/configs/ax25-ae350.h
+++ b/include/configs/ax25-ae350.h
@@ -7,6 +7,23 @@
#ifndef __CONFIG_H
#define __CONFIG_H
+#ifdef CONFIG_SPL
+#define CONFIG_SPL_MAX_SIZE 0x00100000
+#define CONFIG_SPL_BSS_START_ADDR 0x04000000
+#define CONFIG_SPL_BSS_MAX_SIZE 0x00100000
+
+#ifndef CONFIG_XIP
+#define CONFIG_SPL_LOAD_FIT_ADDRESS 0x00200000
+#else
+#define CONFIG_SPL_LOAD_FIT_ADDRESS 0x80010000
+#endif
+
+#ifdef CONFIG_SPL_MMC_SUPPORT
+#define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 1
+#define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "u-boot.itb"
+#endif
+#endif
+
/*
* CPU and Board Configuration Options
*/
diff --git a/include/configs/imx8qxp_mek.h b/include/configs/imx8qxp_mek.h
index cb39bcdebf..81ac4b52f3 100644
--- a/include/configs/imx8qxp_mek.h
+++ b/include/configs/imx8qxp_mek.h
@@ -196,4 +196,9 @@
#define CONFIG_FEC_XCV_TYPE RGMII
#define FEC_QUIRK_ENET_MAC
+/* Misc configuration */
+#define CONFIG_SYS_CBSIZE 2048
+#define CONFIG_SYS_MAXARGS 64
+#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
+
#endif /* __IMX8QXP_MEK_H */
diff --git a/include/configs/rk3328_common.h b/include/configs/rk3328_common.h
index e51e1b0e0e..b14da3a626 100644
--- a/include/configs/rk3328_common.h
+++ b/include/configs/rk3328_common.h
@@ -36,7 +36,7 @@
"pxefile_addr_r=0x00600000\0" \
"fdt_addr_r=0x01f00000\0" \
"kernel_addr_r=0x02080000\0" \
- "ramdisk_addr_r=0x04000000\0"
+ "ramdisk_addr_r=0x06000000\0"
#include <config_distro_bootcmd.h>
#define CONFIG_EXTRA_ENV_SETTINGS \
diff --git a/include/configs/rk3399_common.h b/include/configs/rk3399_common.h
index 7331c6dc02..127ca1f09c 100644
--- a/include/configs/rk3399_common.h
+++ b/include/configs/rk3399_common.h
@@ -51,7 +51,7 @@
"pxefile_addr_r=0x00600000\0" \
"fdt_addr_r=0x01f00000\0" \
"kernel_addr_r=0x02080000\0" \
- "ramdisk_addr_r=0x04000000\0"
+ "ramdisk_addr_r=0x06000000\0"
#ifndef ROCKCHIP_DEVICE_SETTINGS
#define ROCKCHIP_DEVICE_SETTINGS
diff --git a/include/configs/vining_2000.h b/include/configs/vining_2000.h
index 54c8c2f62e..0c0baf2738 100644
--- a/include/configs/vining_2000.h
+++ b/include/configs/vining_2000.h
@@ -58,8 +58,6 @@
#define CONFIG_POWER_PFUZE100_I2C_ADDR 0x08
/* Network */
-#define CONFIG_FEC_MXC
-
#define IMX_FEC_BASE ENET_BASE_ADDR
#define CONFIG_FEC_MXC_PHYADDR 0x0
@@ -91,4 +89,8 @@
#define CONFIG_SYS_MMC_ENV_PART 1 /* boot0 */
#endif
+#ifdef CONFIG_SPL_BUILD
+#define CONFIG_MXC_UART_BASE UART1_BASE
+#endif
+
#endif /* __CONFIG_H */
diff --git a/include/configs/warp7.h b/include/configs/warp7.h
index 9a82581c5f..da894ec0ca 100644
--- a/include/configs/warp7.h
+++ b/include/configs/warp7.h
@@ -125,6 +125,19 @@
#define CONFIG_SYS_INIT_SP_ADDR \
(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
+/*
+ * Environment starts at CONFIG_ENV_OFFSET= 0xC0000 = 768k = 768*1024 = 786432
+ *
+ * Detect overlap between U-Boot image and environment area in build-time
+ *
+ * CONFIG_BOARD_SIZE_LIMIT = CONFIG_ENV_OFFSET - u-boot.imx offset
+ * CONFIG_BOARD_SIZE_LIMIT = 768k - 1k = 767k = 785408
+ *
+ * Currently CONFIG_BOARD_SIZE_LIMIT does not handle expressions, so
+ * write the direct value here
+ */
+#define CONFIG_BOARD_SIZE_LIMIT 785408
+
/* I2C configs */
#define CONFIG_SYS_I2C_MXC
#define CONFIG_SYS_I2C_SPEED 100000
diff --git a/include/crypto/internal/rsa.h b/include/crypto/internal/rsa.h
new file mode 100644
index 0000000000..e870133f4b
--- /dev/null
+++ b/include/crypto/internal/rsa.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * RSA internal helpers
+ *
+ * Copyright (c) 2015, Intel Corporation
+ * Authors: Tadeusz Struk <tadeusz.struk@intel.com>
+ */
+#ifndef _RSA_HELPER_
+#define _RSA_HELPER_
+#include <linux/types.h>
+
+/**
+ * rsa_key - RSA key structure
+ * @n : RSA modulus raw byte stream
+ * @e : RSA public exponent raw byte stream
+ * @d : RSA private exponent raw byte stream
+ * @p : RSA prime factor p of n raw byte stream
+ * @q : RSA prime factor q of n raw byte stream
+ * @dp : RSA exponent d mod (p - 1) raw byte stream
+ * @dq : RSA exponent d mod (q - 1) raw byte stream
+ * @qinv : RSA CRT coefficient q^(-1) mod p raw byte stream
+ * @n_sz : length in bytes of RSA modulus n
+ * @e_sz : length in bytes of RSA public exponent
+ * @d_sz : length in bytes of RSA private exponent
+ * @p_sz : length in bytes of p field
+ * @q_sz : length in bytes of q field
+ * @dp_sz : length in bytes of dp field
+ * @dq_sz : length in bytes of dq field
+ * @qinv_sz : length in bytes of qinv field
+ */
+struct rsa_key {
+ const u8 *n;
+ const u8 *e;
+ const u8 *d;
+ const u8 *p;
+ const u8 *q;
+ const u8 *dp;
+ const u8 *dq;
+ const u8 *qinv;
+ size_t n_sz;
+ size_t e_sz;
+ size_t d_sz;
+ size_t p_sz;
+ size_t q_sz;
+ size_t dp_sz;
+ size_t dq_sz;
+ size_t qinv_sz;
+};
+
+int rsa_parse_pub_key(struct rsa_key *rsa_key, const void *key,
+ unsigned int key_len);
+
+int rsa_parse_priv_key(struct rsa_key *rsa_key, const void *key,
+ unsigned int key_len);
+
+extern struct crypto_template rsa_pkcs1pad_tmpl;
+#endif
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h
new file mode 100644
index 0000000000..8f5c8a7ee3
--- /dev/null
+++ b/include/crypto/pkcs7.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* PKCS#7 crypto data parser
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifndef _CRYPTO_PKCS7_H
+#define _CRYPTO_PKCS7_H
+
+#ifndef __UBOOT__
+#include <linux/verification.h>
+#include <crypto/public_key.h>
+#endif
+
+struct key;
+struct pkcs7_message;
+
+/*
+ * pkcs7_parser.c
+ */
+extern struct pkcs7_message *pkcs7_parse_message(const void *data,
+ size_t datalen);
+extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
+
+extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
+ const void **_data, size_t *_datalen,
+ size_t *_headerlen);
+
+#ifndef __UBOOT__
+/*
+ * pkcs7_trust.c
+ */
+extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
+ struct key *trust_keyring);
+
+/*
+ * pkcs7_verify.c
+ */
+extern int pkcs7_verify(struct pkcs7_message *pkcs7,
+ enum key_being_used_for usage);
+
+extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7,
+ const void *data, size_t datalen);
+#endif
+
+#endif /* _CRYPTO_PKCS7_H */
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
new file mode 100644
index 0000000000..436a1ee1ee
--- /dev/null
+++ b/include/crypto/public_key.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Asymmetric public-key algorithm definitions
+ *
+ * See Documentation/crypto/asymmetric-keys.txt
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifndef _LINUX_PUBLIC_KEY_H
+#define _LINUX_PUBLIC_KEY_H
+
+#ifdef __UBOOT__
+#include <linux/types.h>
+#else
+#include <linux/keyctl.h>
+#endif
+#include <linux/oid_registry.h>
+
+/*
+ * Cryptographic data for the public-key subtype of the asymmetric key type.
+ *
+ * Note that this may include private part of the key as well as the public
+ * part.
+ */
+struct public_key {
+ void *key;
+ u32 keylen;
+ enum OID algo;
+ void *params;
+ u32 paramlen;
+ bool key_is_private;
+ const char *id_type;
+ const char *pkey_algo;
+};
+
+extern void public_key_free(struct public_key *key);
+
+/*
+ * Public key cryptography signature data
+ */
+struct public_key_signature {
+ struct asymmetric_key_id *auth_ids[2];
+ u8 *s; /* Signature */
+ u32 s_size; /* Number of bytes in signature */
+ u8 *digest;
+ u8 digest_size; /* Number of bytes in digest */
+ const char *pkey_algo;
+ const char *hash_algo;
+ const char *encoding;
+};
+
+extern void public_key_signature_free(struct public_key_signature *sig);
+
+#ifndef __UBOOT__
+extern struct asymmetric_key_subtype public_key_subtype;
+
+struct key;
+struct key_type;
+union key_payload;
+
+extern int restrict_link_by_signature(struct key *dest_keyring,
+ const struct key_type *type,
+ const union key_payload *payload,
+ struct key *trust_keyring);
+
+extern int restrict_link_by_key_or_keyring(struct key *dest_keyring,
+ const struct key_type *type,
+ const union key_payload *payload,
+ struct key *trusted);
+
+extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring,
+ const struct key_type *type,
+ const union key_payload *payload,
+ struct key *trusted);
+
+extern int query_asymmetric_key(const struct kernel_pkey_params *,
+ struct kernel_pkey_query *);
+
+extern int encrypt_blob(struct kernel_pkey_params *, const void *, void *);
+extern int decrypt_blob(struct kernel_pkey_params *, const void *, void *);
+extern int create_signature(struct kernel_pkey_params *, const void *, void *);
+extern int verify_signature(const struct key *,
+ const struct public_key_signature *);
+
+int public_key_verify_signature(const struct public_key *pkey,
+ const struct public_key_signature *sig);
+#endif /* !__UBOOT__ */
+
+#endif /* _LINUX_PUBLIC_KEY_H */
diff --git a/include/dma-uclass.h b/include/dma-uclass.h
index 31b43fb4b9..a1d9d26ac5 100644
--- a/include/dma-uclass.h
+++ b/include/dma-uclass.h
@@ -108,6 +108,17 @@ struct dma_ops {
* @return zero on success, or -ve error code.
*/
int (*send)(struct dma *dma, void *src, size_t len, void *metadata);
+ /**
+ * get_cfg() - Get DMA channel configuration for client's use
+ *
+ * @dma: The DMA Channel to manipulate
+ * @cfg_id: DMA provider specific ID to identify what
+ * configuration data client needs
+ * @data: Pointer to store pointer to DMA driver specific
+ * configuration data for the given cfg_id (output param)
+ * @return zero on success, or -ve error code.
+ */
+ int (*get_cfg)(struct dma *dma, u32 cfg_id, void **data);
#endif /* CONFIG_DMA_CHANNELS */
/**
* transfer() - Issue a DMA transfer. The implementation must
diff --git a/include/dma.h b/include/dma.h
index d1c3d0df7d..6c55aa3a00 100644
--- a/include/dma.h
+++ b/include/dma.h
@@ -290,6 +290,18 @@ int dma_receive(struct dma *dma, void **dst, void *metadata);
* @return zero on success, or -ve error code.
*/
int dma_send(struct dma *dma, void *src, size_t len, void *metadata);
+
+/**
+ * dma_get_cfg() - Get DMA channel configuration for client's use
+ *
+ * @dma: The DMA Channel to manipulate
+ * @cfg_id: DMA provider specific ID to identify what
+ * configuration data client needs
+ * @cfg_data: Pointer to store pointer to DMA driver specific
+ * configuration data for the given cfg_id (output param)
+ * @return zero on success, or -ve error code.
+ */
+int dma_get_cfg(struct dma *dma, u32 cfg_id, void **cfg_data);
#endif /* CONFIG_DMA_CHANNELS */
/*
diff --git a/include/dt-bindings/net/ti-dp83867.h b/include/dt-bindings/net/ti-dp83867.h
index 85d08f6974..cde5aa7e27 100644
--- a/include/dt-bindings/net/ti-dp83867.h
+++ b/include/dt-bindings/net/ti-dp83867.h
@@ -45,5 +45,6 @@
#define DP83867_CLK_O_SEL_CHN_C_TCLK 0xA
#define DP83867_CLK_O_SEL_CHN_D_TCLK 0xB
#define DP83867_CLK_O_SEL_REF_CLK 0xC
-
+/* Special flag to indicate clock should be off */
+#define DP83867_CLK_O_SEL_OFF 0xFFFFFFFF
#endif
diff --git a/include/env.h b/include/env.h
index b72239f6a5..d6c2d751d6 100644
--- a/include/env.h
+++ b/include/env.h
@@ -113,6 +113,16 @@ int env_match(unsigned char *name, int index);
*/
char *env_get(const char *varname);
+/*
+ * Like env_get, but prints an error if envvar isn't defined in the
+ * environment. It always returns what env_get does, so it can be used in
+ * place of env_get without changing error handling otherwise.
+ *
+ * @varname: Variable to look up
+ * @return value of variable, or NULL if not found
+ */
+char *from_env(const char *envvar);
+
/**
* env_get_f() - Look up the value of an environment variable (early)
*
diff --git a/include/fdt_support.h b/include/fdt_support.h
index cefb2b2cce..2286ea7793 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -94,6 +94,7 @@ int fdt_fixup_memory(void *blob, u64 start, u64 size);
*/
#ifdef CONFIG_ARCH_FIXUP_FDT_MEMORY
int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks);
+int fdt_set_usable_memory(void *blob, u64 start[], u64 size[], int banks);
#else
static inline int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[],
int banks)
diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h
new file mode 100644
index 0000000000..47d83917df
--- /dev/null
+++ b/include/keys/asymmetric-type.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Asymmetric Public-key cryptography key type interface
+ *
+ * See Documentation/crypto/asymmetric-keys.txt
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifndef _KEYS_ASYMMETRIC_TYPE_H
+#define _KEYS_ASYMMETRIC_TYPE_H
+
+#ifndef __UBOOT__
+#include <linux/key-type.h>
+#include <linux/verification.h>
+
+extern struct key_type key_type_asymmetric;
+
+/*
+ * The key payload is four words. The asymmetric-type key uses them as
+ * follows:
+ */
+enum asymmetric_payload_bits {
+ asym_crypto, /* The data representing the key */
+ asym_subtype, /* Pointer to an asymmetric_key_subtype struct */
+ asym_key_ids, /* Pointer to an asymmetric_key_ids struct */
+ asym_auth /* The key's authorisation (signature, parent key ID) */
+};
+#endif /* !__UBOOT__ */
+
+/*
+ * Identifiers for an asymmetric key ID. We have three ways of looking up a
+ * key derived from an X.509 certificate:
+ *
+ * (1) Serial Number & Issuer. Non-optional. This is the only valid way to
+ * map a PKCS#7 signature to an X.509 certificate.
+ *
+ * (2) Issuer & Subject Unique IDs. Optional. These were the original way to
+ * match X.509 certificates, but have fallen into disuse in favour of (3).
+ *
+ * (3) Auth & Subject Key Identifiers. Optional. SKIDs are only provided on
+ * CA keys that are intended to sign other keys, so don't appear in end
+ * user certificates unless forced.
+ *
+ * We could also support an PGP key identifier, which is just a SHA1 sum of the
+ * public key and certain parameters, but since we don't support PGP keys at
+ * the moment, we shall ignore those.
+ *
+ * What we actually do is provide a place where binary identifiers can be
+ * stashed and then compare against them when checking for an id match.
+ */
+struct asymmetric_key_id {
+ unsigned short len;
+ unsigned char data[];
+};
+
+struct asymmetric_key_ids {
+ void *id[2];
+};
+
+extern bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
+ const struct asymmetric_key_id *kid2);
+
+extern bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
+ const struct asymmetric_key_id *kid2);
+
+extern struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
+ size_t len_1,
+ const void *val_2,
+ size_t len_2);
+#ifndef __UBOOT__
+static inline
+const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
+{
+ return key->payload.data[asym_key_ids];
+}
+
+extern struct key *find_asymmetric_key(struct key *keyring,
+ const struct asymmetric_key_id *id_0,
+ const struct asymmetric_key_id *id_1,
+ bool partial);
+#endif
+
+/*
+ * The payload is at the discretion of the subtype.
+ */
+
+#endif /* _KEYS_ASYMMETRIC_TYPE_H */
diff --git a/include/linux/asn1.h b/include/linux/asn1.h
new file mode 100644
index 0000000000..a4d0bdd107
--- /dev/null
+++ b/include/linux/asn1.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* ASN.1 BER/DER/CER encoding definitions
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifndef _LINUX_ASN1_H
+#define _LINUX_ASN1_H
+
+/* Class */
+enum asn1_class {
+ ASN1_UNIV = 0, /* Universal */
+ ASN1_APPL = 1, /* Application */
+ ASN1_CONT = 2, /* Context */
+ ASN1_PRIV = 3 /* Private */
+};
+#define ASN1_CLASS_BITS 0xc0
+
+
+enum asn1_method {
+ ASN1_PRIM = 0, /* Primitive */
+ ASN1_CONS = 1 /* Constructed */
+};
+#define ASN1_CONS_BIT 0x20
+
+/* Tag */
+enum asn1_tag {
+ ASN1_EOC = 0, /* End Of Contents or N/A */
+ ASN1_BOOL = 1, /* Boolean */
+ ASN1_INT = 2, /* Integer */
+ ASN1_BTS = 3, /* Bit String */
+ ASN1_OTS = 4, /* Octet String */
+ ASN1_NULL = 5, /* Null */
+ ASN1_OID = 6, /* Object Identifier */
+ ASN1_ODE = 7, /* Object Description */
+ ASN1_EXT = 8, /* External */
+ ASN1_REAL = 9, /* Real float */
+ ASN1_ENUM = 10, /* Enumerated */
+ ASN1_EPDV = 11, /* Embedded PDV */
+ ASN1_UTF8STR = 12, /* UTF8 String */
+ ASN1_RELOID = 13, /* Relative OID */
+ /* 14 - Reserved */
+ /* 15 - Reserved */
+ ASN1_SEQ = 16, /* Sequence and Sequence of */
+ ASN1_SET = 17, /* Set and Set of */
+ ASN1_NUMSTR = 18, /* Numerical String */
+ ASN1_PRNSTR = 19, /* Printable String */
+ ASN1_TEXSTR = 20, /* T61 String / Teletext String */
+ ASN1_VIDSTR = 21, /* Videotex String */
+ ASN1_IA5STR = 22, /* IA5 String */
+ ASN1_UNITIM = 23, /* Universal Time */
+ ASN1_GENTIM = 24, /* General Time */
+ ASN1_GRASTR = 25, /* Graphic String */
+ ASN1_VISSTR = 26, /* Visible String */
+ ASN1_GENSTR = 27, /* General String */
+ ASN1_UNISTR = 28, /* Universal String */
+ ASN1_CHRSTR = 29, /* Character String */
+ ASN1_BMPSTR = 30, /* BMP String */
+ ASN1_LONG_TAG = 31 /* Long form tag */
+};
+
+#define ASN1_INDEFINITE_LENGTH 0x80
+
+#endif /* _LINUX_ASN1_H */
diff --git a/include/linux/asn1_ber_bytecode.h b/include/linux/asn1_ber_bytecode.h
new file mode 100644
index 0000000000..b38361953a
--- /dev/null
+++ b/include/linux/asn1_ber_bytecode.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* ASN.1 BER/DER/CER parsing state machine internal definitions
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifndef _LINUX_ASN1_BER_BYTECODE_H
+#define _LINUX_ASN1_BER_BYTECODE_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#endif
+#include <linux/asn1.h>
+
+typedef int (*asn1_action_t)(void *context,
+ size_t hdrlen, /* In case of ANY type */
+ unsigned char tag, /* In case of ANY type */
+ const void *value, size_t vlen);
+
+struct asn1_decoder {
+ const unsigned char *machine;
+ size_t machlen;
+ const asn1_action_t *actions;
+};
+
+enum asn1_opcode {
+ /* The tag-matching ops come first and the odd-numbered slots
+ * are for OR_SKIP ops.
+ */
+#define ASN1_OP_MATCH__SKIP 0x01
+#define ASN1_OP_MATCH__ACT 0x02
+#define ASN1_OP_MATCH__JUMP 0x04
+#define ASN1_OP_MATCH__ANY 0x08
+#define ASN1_OP_MATCH__COND 0x10
+
+ ASN1_OP_MATCH = 0x00,
+ ASN1_OP_MATCH_OR_SKIP = 0x01,
+ ASN1_OP_MATCH_ACT = 0x02,
+ ASN1_OP_MATCH_ACT_OR_SKIP = 0x03,
+ ASN1_OP_MATCH_JUMP = 0x04,
+ ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05,
+ ASN1_OP_MATCH_ANY = 0x08,
+ ASN1_OP_MATCH_ANY_OR_SKIP = 0x09,
+ ASN1_OP_MATCH_ANY_ACT = 0x0a,
+ ASN1_OP_MATCH_ANY_ACT_OR_SKIP = 0x0b,
+ /* Everything before here matches unconditionally */
+
+ ASN1_OP_COND_MATCH_OR_SKIP = 0x11,
+ ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13,
+ ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15,
+ ASN1_OP_COND_MATCH_ANY = 0x18,
+ ASN1_OP_COND_MATCH_ANY_OR_SKIP = 0x19,
+ ASN1_OP_COND_MATCH_ANY_ACT = 0x1a,
+ ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP = 0x1b,
+
+ /* Everything before here will want a tag from the data */
+#define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP
+
+ /* These are here to help fill up space */
+ ASN1_OP_COND_FAIL = 0x1c,
+ ASN1_OP_COMPLETE = 0x1d,
+ ASN1_OP_ACT = 0x1e,
+ ASN1_OP_MAYBE_ACT = 0x1f,
+
+ /* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */
+ ASN1_OP_END_SEQ = 0x20,
+ ASN1_OP_END_SET = 0x21,
+ ASN1_OP_END_SEQ_OF = 0x22,
+ ASN1_OP_END_SET_OF = 0x23,
+ ASN1_OP_END_SEQ_ACT = 0x24,
+ ASN1_OP_END_SET_ACT = 0x25,
+ ASN1_OP_END_SEQ_OF_ACT = 0x26,
+ ASN1_OP_END_SET_OF_ACT = 0x27,
+#define ASN1_OP_END__SET 0x01
+#define ASN1_OP_END__OF 0x02
+#define ASN1_OP_END__ACT 0x04
+
+ ASN1_OP_RETURN = 0x28,
+
+ ASN1_OP__NR
+};
+
+#define _tag(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | ASN1_##TAG)
+#define _tagn(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | TAG)
+#define _jump_target(N) (N)
+#define _action(N) (N)
+
+#endif /* _LINUX_ASN1_BER_BYTECODE_H */
diff --git a/include/linux/asn1_decoder.h b/include/linux/asn1_decoder.h
new file mode 100644
index 0000000000..83f9c6e1e5
--- /dev/null
+++ b/include/linux/asn1_decoder.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* ASN.1 decoder
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifndef _LINUX_ASN1_DECODER_H
+#define _LINUX_ASN1_DECODER_H
+
+#include <linux/asn1.h>
+
+struct asn1_decoder;
+
+extern int asn1_ber_decoder(const struct asn1_decoder *decoder,
+ void *context,
+ const unsigned char *data,
+ size_t datalen);
+
+#endif /* _LINUX_ASN1_DECODER_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 5c7e5f635b..564819a1c0 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -1,8 +1,8 @@
#ifndef _LINUX_KERNEL_H
#define _LINUX_KERNEL_H
-
#include <linux/types.h>
+#include <linux/printk.h> /* for printf/pr_* utilities */
#define USHRT_MAX ((u16)(~0U))
#define SHRT_MAX ((s16)(USHRT_MAX>>1))
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
new file mode 100644
index 0000000000..657d6bf2c0
--- /dev/null
+++ b/include/linux/oid_registry.h
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* ASN.1 Object identifier (OID) registry
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifndef _LINUX_OID_REGISTRY_H
+#define _LINUX_OID_REGISTRY_H
+
+#include <linux/types.h>
+
+/*
+ * OIDs are turned into these values if possible, or OID__NR if not held here.
+ *
+ * NOTE! Do not mess with the format of each line as this is read by
+ * build_OID_registry.pl to generate the data for look_up_OID().
+ */
+enum OID {
+ OID_id_dsa_with_sha1, /* 1.2.840.10030.4.3 */
+ OID_id_dsa, /* 1.2.840.10040.4.1 */
+ OID_id_ecdsa_with_sha1, /* 1.2.840.10045.4.1 */
+ OID_id_ecPublicKey, /* 1.2.840.10045.2.1 */
+
+ /* PKCS#1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)} */
+ OID_rsaEncryption, /* 1.2.840.113549.1.1.1 */
+ OID_md2WithRSAEncryption, /* 1.2.840.113549.1.1.2 */
+ OID_md3WithRSAEncryption, /* 1.2.840.113549.1.1.3 */
+ OID_md4WithRSAEncryption, /* 1.2.840.113549.1.1.4 */
+ OID_sha1WithRSAEncryption, /* 1.2.840.113549.1.1.5 */
+ OID_sha256WithRSAEncryption, /* 1.2.840.113549.1.1.11 */
+ OID_sha384WithRSAEncryption, /* 1.2.840.113549.1.1.12 */
+ OID_sha512WithRSAEncryption, /* 1.2.840.113549.1.1.13 */
+ OID_sha224WithRSAEncryption, /* 1.2.840.113549.1.1.14 */
+ /* PKCS#7 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-7(7)} */
+ OID_data, /* 1.2.840.113549.1.7.1 */
+ OID_signed_data, /* 1.2.840.113549.1.7.2 */
+ /* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */
+ OID_email_address, /* 1.2.840.113549.1.9.1 */
+ OID_contentType, /* 1.2.840.113549.1.9.3 */
+ OID_messageDigest, /* 1.2.840.113549.1.9.4 */
+ OID_signingTime, /* 1.2.840.113549.1.9.5 */
+ OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */
+ OID_smimeAuthenticatedAttrs, /* 1.2.840.113549.1.9.16.2.11 */
+
+ /* {iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2)} */
+ OID_md2, /* 1.2.840.113549.2.2 */
+ OID_md4, /* 1.2.840.113549.2.4 */
+ OID_md5, /* 1.2.840.113549.2.5 */
+
+ /* Microsoft Authenticode & Software Publishing */
+ OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */
+ OID_msStatementType, /* 1.3.6.1.4.1.311.2.1.11 */
+ OID_msSpOpusInfo, /* 1.3.6.1.4.1.311.2.1.12 */
+ OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */
+ OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */
+ OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
+
+ OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
+ OID_sha1, /* 1.3.14.3.2.26 */
+ OID_sha256, /* 2.16.840.1.101.3.4.2.1 */
+ OID_sha384, /* 2.16.840.1.101.3.4.2.2 */
+ OID_sha512, /* 2.16.840.1.101.3.4.2.3 */
+ OID_sha224, /* 2.16.840.1.101.3.4.2.4 */
+
+ /* Distinguished Name attribute IDs [RFC 2256] */
+ OID_commonName, /* 2.5.4.3 */
+ OID_surname, /* 2.5.4.4 */
+ OID_countryName, /* 2.5.4.6 */
+ OID_locality, /* 2.5.4.7 */
+ OID_stateOrProvinceName, /* 2.5.4.8 */
+ OID_organizationName, /* 2.5.4.10 */
+ OID_organizationUnitName, /* 2.5.4.11 */
+ OID_title, /* 2.5.4.12 */
+ OID_description, /* 2.5.4.13 */
+ OID_name, /* 2.5.4.41 */
+ OID_givenName, /* 2.5.4.42 */
+ OID_initials, /* 2.5.4.43 */
+ OID_generationalQualifier, /* 2.5.4.44 */
+
+ /* Certificate extension IDs */
+ OID_subjectKeyIdentifier, /* 2.5.29.14 */
+ OID_keyUsage, /* 2.5.29.15 */
+ OID_subjectAltName, /* 2.5.29.17 */
+ OID_issuerAltName, /* 2.5.29.18 */
+ OID_basicConstraints, /* 2.5.29.19 */
+ OID_crlDistributionPoints, /* 2.5.29.31 */
+ OID_certPolicies, /* 2.5.29.32 */
+ OID_authorityKeyIdentifier, /* 2.5.29.35 */
+ OID_extKeyUsage, /* 2.5.29.37 */
+
+ /* EC-RDSA */
+ OID_gostCPSignA, /* 1.2.643.2.2.35.1 */
+ OID_gostCPSignB, /* 1.2.643.2.2.35.2 */
+ OID_gostCPSignC, /* 1.2.643.2.2.35.3 */
+ OID_gost2012PKey256, /* 1.2.643.7.1.1.1.1 */
+ OID_gost2012PKey512, /* 1.2.643.7.1.1.1.2 */
+ OID_gost2012Digest256, /* 1.2.643.7.1.1.2.2 */
+ OID_gost2012Digest512, /* 1.2.643.7.1.1.2.3 */
+ OID_gost2012Signature256, /* 1.2.643.7.1.1.3.2 */
+ OID_gost2012Signature512, /* 1.2.643.7.1.1.3.3 */
+ OID_gostTC26Sign256A, /* 1.2.643.7.1.2.1.1.1 */
+ OID_gostTC26Sign256B, /* 1.2.643.7.1.2.1.1.2 */
+ OID_gostTC26Sign256C, /* 1.2.643.7.1.2.1.1.3 */
+ OID_gostTC26Sign256D, /* 1.2.643.7.1.2.1.1.4 */
+ OID_gostTC26Sign512A, /* 1.2.643.7.1.2.1.2.1 */
+ OID_gostTC26Sign512B, /* 1.2.643.7.1.2.1.2.2 */
+ OID_gostTC26Sign512C, /* 1.2.643.7.1.2.1.2.3 */
+
+ OID__NR
+};
+
+extern enum OID look_up_OID(const void *data, size_t datasize);
+extern int sprint_oid(const void *, size_t, char *, size_t);
+extern int sprint_OID(enum OID, char *, size_t);
+
+#endif /* _LINUX_OID_REGISTRY_H */
diff --git a/include/linux/soc/ti/ti-udma.h b/include/linux/soc/ti/ti-udma.h
index e9d4226c48..04e354fb2d 100644
--- a/include/linux/soc/ti/ti-udma.h
+++ b/include/linux/soc/ti/ti-udma.h
@@ -21,4 +21,23 @@ struct ti_udma_drv_packet_data {
u32 dest_tag;
};
+/**
+ * struct ti_udma_drv_chan_cfg_data - TI UDMA per channel specific
+ * configuration data
+ *
+ * @flow_id_base: Start index of flow ID allocated to this channel
+ * @flow_id_cnt: Number of flows allocated for this channel starting at
+ * flow_id_base
+ *
+ * TI UDMA channel specific data returned as part of dma_get_cfg() call
+ * from the DMA client driver.
+ */
+struct ti_udma_drv_chan_cfg_data {
+ u32 flow_id_base;
+ u32 flow_id_cnt;
+};
+
+/* TI UDMA specific flag IDs for dma_get_cfg() call */
+#define TI_UDMA_CHAN_PRIV_INFO 0
+
#endif /* __TI_UDMA_H */
diff --git a/include/linux/time.h b/include/linux/time.h
index b8d298eb4d..702dd276ae 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -1,6 +1,8 @@
#ifndef _LINUX_TIME_H
#define _LINUX_TIME_H
+#include <rtc.h>
+#include <vsprintf.h>
#include <linux/types.h>
#define _DEFUN(a,b,c) a(c)
@@ -150,4 +152,13 @@ _DEFUN (ctime_r, (tim_p, result),
return asctime_r (localtime_r (tim_p, &tm), result);
}
+/* for compatibility with linux code */
+typedef __s64 time64_t;
+
+#ifdef CONFIG_LIB_DATE
+time64_t mktime64(const unsigned int year, const unsigned int mon,
+ const unsigned int day, const unsigned int hour,
+ const unsigned int min, const unsigned int sec);
+#endif
+
#endif
diff --git a/include/linux/types.h b/include/linux/types.h
index 51cb284bb8..bd912bcb42 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -85,7 +85,7 @@ typedef unsigned int u_int;
typedef unsigned long u_long;
/* sysv */
-typedef unsigned char unchar;
+typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
diff --git a/include/miiphy.h b/include/miiphy.h
index 9b97d09f18..61c136b114 100644
--- a/include/miiphy.h
+++ b/include/miiphy.h
@@ -154,17 +154,29 @@ void dm_mdio_probe_devices(void);
/**
* dm_mdio_phy_connect - Wrapper over phy_connect for DM MDIO
*
- * @dev: mdio dev
- * @addr: PHY address on MDIO bus
+ * @mdiodev: mdio device the PHY is accesible on
+ * @phyaddr: PHY address on MDIO bus
* @ethdev: ethernet device to connect to the PHY
* @interface: MAC-PHY protocol
*
* @return pointer to phy_device, or 0 on error
*/
-struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr,
+struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr,
struct udevice *ethdev,
phy_interface_t interface);
+/**
+ * dm_eth_phy_connect - Connect an Eth device to a PHY based on device tree
+ *
+ * Picks up the DT phy-handle and phy-mode from ethernet device node and
+ * connects the ethernet device to the linked PHY.
+ *
+ * @ethdev: ethernet device
+ *
+ * @return pointer to phy_device, or 0 on error
+ */
+struct phy_device *dm_eth_phy_connect(struct udevice *ethdev);
+
#endif
#ifdef CONFIG_DM_MDIO_MUX
diff --git a/include/net.h b/include/net.h
index 11eca1bc6c..834f244982 100644
--- a/include/net.h
+++ b/include/net.h
@@ -826,15 +826,29 @@ static inline void net_random_ethaddr(uchar *addr)
addr[0] |= 0x02; /* set local assignment bit (IEEE802) */
}
+/**
+ * string_to_enetaddr() - Parse a MAC address
+ *
+ * Convert a string MAC address
+ *
+ * Implemented in lib/net_utils.c (built unconditionally)
+ *
+ * @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit
+ * hex value
+ * @enetaddr: Place to put MAC address (6 bytes)
+ */
+void string_to_enetaddr(const char *addr, uint8_t *enetaddr);
+
/* Convert an IP address to a string */
void ip_to_string(struct in_addr x, char *s);
/**
* string_to_ip() - Convert a string to ip address
*
- * @s: String to conver, in the format format a.b.c.d, where each value is a
- * decimal number from 0 to 255
- * @return IP address, or 0 if invalid
+ * Implemented in lib/net_utils.c (built unconditionally)
+ *
+ * @s: Input string to parse
+ * @return: in_addr struct containing the parsed IP address
*/
struct in_addr string_to_ip(const char *s);
@@ -880,19 +894,6 @@ unsigned int random_port(void);
*/
int update_tftp(ulong addr, char *interface, char *devstring);
-/**********************************************************************/
-
-/**
- * eth_parse_enetaddr() - Parse a MAC address
- *
- * Convert a string MAC address
- *
- * @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit
- * hex value
- * @enetaddr: Place to put MAC address (6 bytes)
- */
-void eth_parse_enetaddr(const char *addr, uint8_t *enetaddr);
-
/**
* env_get_ip() - Convert an environment value to to an ip address
*
@@ -905,5 +906,4 @@ static inline struct in_addr env_get_ip(char *var)
{
return string_to_ip(env_get(var));
}
-
#endif /* __NET_H__ */
diff --git a/include/opensbi.h b/include/opensbi.h
index 9f1d62e7dd..d812cc8ccd 100644
--- a/include/opensbi.h
+++ b/include/opensbi.h
@@ -11,7 +11,7 @@
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
/** Maximum supported info version */
-#define FW_DYNAMIC_INFO_VERSION 0x1
+#define FW_DYNAMIC_INFO_VERSION 0x2
/** Possible next mode values */
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
@@ -35,6 +35,22 @@ struct fw_dynamic_info {
unsigned long next_mode;
/** Options for OpenSBI library */
unsigned long options;
+ /**
+ * Preferred boot HART id
+ *
+ * It is possible that the previous booting stage uses same link
+ * address as the FW_DYNAMIC firmware. In this case, the relocation
+ * lottery mechanism can potentially overwrite the previous booting
+ * stage while other HARTs are still running in the previous booting
+ * stage leading to boot-time crash. To avoid this boot-time crash,
+ * the previous booting stage can specify last HART that will jump
+ * to the FW_DYNAMIC firmware as the preferred boot HART.
+ *
+ * To avoid specifying a preferred boot HART, the previous booting
+ * stage can set it to -1UL which will force the FW_DYNAMIC firmware
+ * to use the relocation lottery mechanism.
+ */
+ unsigned long boot_hart;
} __packed;
#endif
diff --git a/include/phy.h b/include/phy.h
index e50f56b6eb..6ace9b3a0c 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -115,6 +115,9 @@ struct phy_driver {
u16 val);
struct list_head list;
+
+ /* driver private data */
+ ulong data;
};
struct phy_device {
diff --git a/include/phy_interface.h b/include/phy_interface.h
index c6823189f8..73f3a3679c 100644
--- a/include/phy_interface.h
+++ b/include/phy_interface.h
@@ -31,6 +31,8 @@ typedef enum {
PHY_INTERFACE_MODE_XLAUI,
PHY_INTERFACE_MODE_CAUI2,
PHY_INTERFACE_MODE_CAUI4,
+ PHY_INTERFACE_MODE_XFI,
+ PHY_INTERFACE_MODE_USXGMII,
PHY_INTERFACE_MODE_NONE, /* Must be last */
PHY_INTERFACE_MODE_COUNT,
@@ -58,6 +60,8 @@ static const char * const phy_interface_strings[] = {
[PHY_INTERFACE_MODE_XLAUI] = "xlaui4",
[PHY_INTERFACE_MODE_CAUI2] = "caui2",
[PHY_INTERFACE_MODE_CAUI4] = "caui4",
+ [PHY_INTERFACE_MODE_XFI] = "xfi",
+ [PHY_INTERFACE_MODE_USXGMII] = "usxgmii",
[PHY_INTERFACE_MODE_NONE] = "",
};
diff --git a/include/rtc.h b/include/rtc.h
index 7386d52db1..8aabfc1162 100644
--- a/include/rtc.h
+++ b/include/rtc.h
@@ -18,6 +18,8 @@
#ifdef CONFIG_DM_RTC
+struct udevice;
+
struct rtc_ops {
/**
* get() - get the current time
diff --git a/lib/Kconfig b/lib/Kconfig
index 55dedcbcdd..965cf7bc03 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -265,6 +265,7 @@ config AES
present.
source lib/rsa/Kconfig
+source lib/crypto/Kconfig
config TPM
bool "Trusted Platform Module (TPM) Support"
@@ -566,6 +567,19 @@ config SMBIOS_PRODUCT_NAME
endmenu
+config ASN1_COMPILER
+ bool
+
+config ASN1_DECODER
+ bool
+ help
+ Enable asn1 decoder library.
+
+config OID_REGISTRY
+ bool
+ help
+ Enable fast lookup object identifier registry.
+
source lib/efi/Kconfig
source lib/efi_loader/Kconfig
source lib/optee/Kconfig
@@ -574,4 +588,7 @@ config TEST_FDTDEC
bool "enable fdtdec test"
depends on OF_LIBFDT
+config LIB_DATE
+ bool
+
endmenu
diff --git a/lib/Makefile b/lib/Makefile
index e15a189f65..1fb650cd90 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -17,6 +17,8 @@ obj-$(CONFIG_OF_LIVE) += of_live.o
obj-$(CONFIG_CMD_DHRYSTONE) += dhry/
obj-$(CONFIG_ARCH_AT91) += at91/
obj-$(CONFIG_OPTEE) += optee/
+obj-$(CONFIG_ASN1_DECODER) += asn1_decoder.o
+obj-y += crypto/
obj-$(CONFIG_AES) += aes.o
@@ -117,4 +119,22 @@ else
obj-y += vsprintf.o strto.o
endif
+obj-y += date.o
+
+#
+# Build a fast OID lookup registry from include/linux/oid_registry.h
+#
+obj-$(CONFIG_OID_REGISTRY) += oid_registry.o
+
+$(obj)/oid_registry.o: $(obj)/oid_registry_data.c
+
+$(obj)/oid_registry_data.c: $(srctree)/include/linux/oid_registry.h \
+ $(srctree)/scripts/build_OID_registry
+ $(call cmd,build_OID_registry)
+
+quiet_cmd_build_OID_registry = GEN $@
+ cmd_build_OID_registry = perl $(srctree)/scripts/build_OID_registry $< $@
+
+clean-files += oid_registry_data.c
+
subdir-ccflags-$(CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED) += -O2
diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c
new file mode 100644
index 0000000000..db222625dd
--- /dev/null
+++ b/lib/asn1_decoder.c
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Decoder for ASN.1 BER/DER/CER encoded bytestream
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifdef __UBOOT__
+#include <linux/compat.h>
+#else
+#include <linux/export.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#ifndef __UBOOT__
+#include <linux/module.h>
+#endif
+#include <linux/asn1_decoder.h>
+#include <linux/asn1_ber_bytecode.h>
+
+static const unsigned char asn1_op_lengths[ASN1_OP__NR] = {
+ /* OPC TAG JMP ACT */
+ [ASN1_OP_MATCH] = 1 + 1,
+ [ASN1_OP_MATCH_OR_SKIP] = 1 + 1,
+ [ASN1_OP_MATCH_ACT] = 1 + 1 + 1,
+ [ASN1_OP_MATCH_ACT_OR_SKIP] = 1 + 1 + 1,
+ [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1,
+ [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1,
+ [ASN1_OP_MATCH_ANY] = 1,
+ [ASN1_OP_MATCH_ANY_OR_SKIP] = 1,
+ [ASN1_OP_MATCH_ANY_ACT] = 1 + 1,
+ [ASN1_OP_MATCH_ANY_ACT_OR_SKIP] = 1 + 1,
+ [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1,
+ [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1,
+ [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1,
+ [ASN1_OP_COND_MATCH_ANY] = 1,
+ [ASN1_OP_COND_MATCH_ANY_OR_SKIP] = 1,
+ [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1,
+ [ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP] = 1 + 1,
+ [ASN1_OP_COND_FAIL] = 1,
+ [ASN1_OP_COMPLETE] = 1,
+ [ASN1_OP_ACT] = 1 + 1,
+ [ASN1_OP_MAYBE_ACT] = 1 + 1,
+ [ASN1_OP_RETURN] = 1,
+ [ASN1_OP_END_SEQ] = 1,
+ [ASN1_OP_END_SEQ_OF] = 1 + 1,
+ [ASN1_OP_END_SET] = 1,
+ [ASN1_OP_END_SET_OF] = 1 + 1,
+ [ASN1_OP_END_SEQ_ACT] = 1 + 1,
+ [ASN1_OP_END_SEQ_OF_ACT] = 1 + 1 + 1,
+ [ASN1_OP_END_SET_ACT] = 1 + 1,
+ [ASN1_OP_END_SET_OF_ACT] = 1 + 1 + 1,
+};
+
+/*
+ * Find the length of an indefinite length object
+ * @data: The data buffer
+ * @datalen: The end of the innermost containing element in the buffer
+ * @_dp: The data parse cursor (updated before returning)
+ * @_len: Where to return the size of the element.
+ * @_errmsg: Where to return a pointer to an error message on error
+ */
+static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen,
+ size_t *_dp, size_t *_len,
+ const char **_errmsg)
+{
+ unsigned char tag, tmp;
+ size_t dp = *_dp, len, n;
+ int indef_level = 1;
+
+next_tag:
+ if (unlikely(datalen - dp < 2)) {
+ if (datalen == dp)
+ goto missing_eoc;
+ goto data_overrun_error;
+ }
+
+ /* Extract a tag from the data */
+ tag = data[dp++];
+ if (tag == ASN1_EOC) {
+ /* It appears to be an EOC. */
+ if (data[dp++] != 0)
+ goto invalid_eoc;
+ if (--indef_level <= 0) {
+ *_len = dp - *_dp;
+ *_dp = dp;
+ return 0;
+ }
+ goto next_tag;
+ }
+
+ if (unlikely((tag & 0x1f) == ASN1_LONG_TAG)) {
+ do {
+ if (unlikely(datalen - dp < 2))
+ goto data_overrun_error;
+ tmp = data[dp++];
+ } while (tmp & 0x80);
+ }
+
+ /* Extract the length */
+ len = data[dp++];
+ if (len <= 0x7f)
+ goto check_length;
+
+ if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
+ /* Indefinite length */
+ if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5))
+ goto indefinite_len_primitive;
+ indef_level++;
+ goto next_tag;
+ }
+
+ n = len - 0x80;
+ if (unlikely(n > sizeof(len) - 1))
+ goto length_too_long;
+ if (unlikely(n > datalen - dp))
+ goto data_overrun_error;
+ len = 0;
+ for (; n > 0; n--) {
+ len <<= 8;
+ len |= data[dp++];
+ }
+check_length:
+ if (len > datalen - dp)
+ goto data_overrun_error;
+ dp += len;
+ goto next_tag;
+
+length_too_long:
+ *_errmsg = "Unsupported length";
+ goto error;
+indefinite_len_primitive:
+ *_errmsg = "Indefinite len primitive not permitted";
+ goto error;
+invalid_eoc:
+ *_errmsg = "Invalid length EOC";
+ goto error;
+data_overrun_error:
+ *_errmsg = "Data overrun error";
+ goto error;
+missing_eoc:
+ *_errmsg = "Missing EOC in indefinite len cons";
+error:
+ *_dp = dp;
+ return -1;
+}
+
+/**
+ * asn1_ber_decoder - Decoder BER/DER/CER ASN.1 according to pattern
+ * @decoder: The decoder definition (produced by asn1_compiler)
+ * @context: The caller's context (to be passed to the action functions)
+ * @data: The encoded data
+ * @datalen: The size of the encoded data
+ *
+ * Decode BER/DER/CER encoded ASN.1 data according to a bytecode pattern
+ * produced by asn1_compiler. Action functions are called on marked tags to
+ * allow the caller to retrieve significant data.
+ *
+ * LIMITATIONS:
+ *
+ * To keep down the amount of stack used by this function, the following limits
+ * have been imposed:
+ *
+ * (1) This won't handle datalen > 65535 without increasing the size of the
+ * cons stack elements and length_too_long checking.
+ *
+ * (2) The stack of constructed types is 10 deep. If the depth of non-leaf
+ * constructed types exceeds this, the decode will fail.
+ *
+ * (3) The SET type (not the SET OF type) isn't really supported as tracking
+ * what members of the set have been seen is a pain.
+ */
+int asn1_ber_decoder(const struct asn1_decoder *decoder,
+ void *context,
+ const unsigned char *data,
+ size_t datalen)
+{
+ const unsigned char *machine = decoder->machine;
+ const asn1_action_t *actions = decoder->actions;
+ size_t machlen = decoder->machlen;
+ enum asn1_opcode op;
+ unsigned char tag = 0, csp = 0, jsp = 0, optag = 0, hdr = 0;
+ const char *errmsg;
+ size_t pc = 0, dp = 0, tdp = 0, len = 0;
+ int ret;
+
+ unsigned char flags = 0;
+#define FLAG_INDEFINITE_LENGTH 0x01
+#define FLAG_MATCHED 0x02
+#define FLAG_LAST_MATCHED 0x04 /* Last tag matched */
+#define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag
+ * - ie. whether or not we are going to parse
+ * a compound type.
+ */
+
+#define NR_CONS_STACK 10
+ unsigned short cons_dp_stack[NR_CONS_STACK];
+ unsigned short cons_datalen_stack[NR_CONS_STACK];
+ unsigned char cons_hdrlen_stack[NR_CONS_STACK];
+#define NR_JUMP_STACK 10
+ unsigned char jump_stack[NR_JUMP_STACK];
+
+ if (datalen > 65535)
+ return -EMSGSIZE;
+
+next_op:
+ pr_debug("next_op: pc=\e[32m%zu\e[m/%zu dp=\e[33m%zu\e[m/%zu C=%d J=%d\n",
+ pc, machlen, dp, datalen, csp, jsp);
+ if (unlikely(pc >= machlen))
+ goto machine_overrun_error;
+ op = machine[pc];
+ if (unlikely(pc + asn1_op_lengths[op] > machlen))
+ goto machine_overrun_error;
+
+ /* If this command is meant to match a tag, then do that before
+ * evaluating the command.
+ */
+ if (op <= ASN1_OP__MATCHES_TAG) {
+ unsigned char tmp;
+
+ /* Skip conditional matches if possible */
+ if ((op & ASN1_OP_MATCH__COND && flags & FLAG_MATCHED) ||
+ (op & ASN1_OP_MATCH__SKIP && dp == datalen)) {
+ flags &= ~FLAG_LAST_MATCHED;
+ pc += asn1_op_lengths[op];
+ goto next_op;
+ }
+
+ flags = 0;
+ hdr = 2;
+
+ /* Extract a tag from the data */
+ if (unlikely(datalen - dp < 2))
+ goto data_overrun_error;
+ tag = data[dp++];
+ if (unlikely((tag & 0x1f) == ASN1_LONG_TAG))
+ goto long_tag_not_supported;
+
+ if (op & ASN1_OP_MATCH__ANY) {
+ pr_debug("- any %02x\n", tag);
+ } else {
+ /* Extract the tag from the machine
+ * - Either CONS or PRIM are permitted in the data if
+ * CONS is not set in the op stream, otherwise CONS
+ * is mandatory.
+ */
+ optag = machine[pc + 1];
+ flags |= optag & FLAG_CONS;
+
+ /* Determine whether the tag matched */
+ tmp = optag ^ tag;
+ tmp &= ~(optag & ASN1_CONS_BIT);
+ pr_debug("- match? %02x %02x %02x\n", tag, optag, tmp);
+ if (tmp != 0) {
+ /* All odd-numbered tags are MATCH_OR_SKIP. */
+ if (op & ASN1_OP_MATCH__SKIP) {
+ pc += asn1_op_lengths[op];
+ dp--;
+ goto next_op;
+ }
+ goto tag_mismatch;
+ }
+ }
+ flags |= FLAG_MATCHED;
+
+ len = data[dp++];
+ if (len > 0x7f) {
+ if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
+ /* Indefinite length */
+ if (unlikely(!(tag & ASN1_CONS_BIT)))
+ goto indefinite_len_primitive;
+ flags |= FLAG_INDEFINITE_LENGTH;
+ if (unlikely(2 > datalen - dp))
+ goto data_overrun_error;
+ } else {
+ int n = len - 0x80;
+ if (unlikely(n > 2))
+ goto length_too_long;
+ if (unlikely(n > datalen - dp))
+ goto data_overrun_error;
+ hdr += n;
+ for (len = 0; n > 0; n--) {
+ len <<= 8;
+ len |= data[dp++];
+ }
+ if (unlikely(len > datalen - dp))
+ goto data_overrun_error;
+ }
+ } else {
+ if (unlikely(len > datalen - dp))
+ goto data_overrun_error;
+ }
+
+ if (flags & FLAG_CONS) {
+ /* For expected compound forms, we stack the positions
+ * of the start and end of the data.
+ */
+ if (unlikely(csp >= NR_CONS_STACK))
+ goto cons_stack_overflow;
+ cons_dp_stack[csp] = dp;
+ cons_hdrlen_stack[csp] = hdr;
+ if (!(flags & FLAG_INDEFINITE_LENGTH)) {
+ cons_datalen_stack[csp] = datalen;
+ datalen = dp + len;
+ } else {
+ cons_datalen_stack[csp] = 0;
+ }
+ csp++;
+ }
+
+ pr_debug("- TAG: %02x %zu%s\n",
+ tag, len, flags & FLAG_CONS ? " CONS" : "");
+ tdp = dp;
+ }
+
+ /* Decide how to handle the operation */
+ switch (op) {
+ case ASN1_OP_MATCH:
+ case ASN1_OP_MATCH_OR_SKIP:
+ case ASN1_OP_MATCH_ACT:
+ case ASN1_OP_MATCH_ACT_OR_SKIP:
+ case ASN1_OP_MATCH_ANY:
+ case ASN1_OP_MATCH_ANY_OR_SKIP:
+ case ASN1_OP_MATCH_ANY_ACT:
+ case ASN1_OP_MATCH_ANY_ACT_OR_SKIP:
+ case ASN1_OP_COND_MATCH_OR_SKIP:
+ case ASN1_OP_COND_MATCH_ACT_OR_SKIP:
+ case ASN1_OP_COND_MATCH_ANY:
+ case ASN1_OP_COND_MATCH_ANY_OR_SKIP:
+ case ASN1_OP_COND_MATCH_ANY_ACT:
+ case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP:
+
+ if (!(flags & FLAG_CONS)) {
+ if (flags & FLAG_INDEFINITE_LENGTH) {
+ size_t tmp = dp;
+
+ ret = asn1_find_indefinite_length(
+ data, datalen, &tmp, &len, &errmsg);
+ if (ret < 0)
+ goto error;
+ }
+ pr_debug("- LEAF: %zu\n", len);
+ }
+
+ if (op & ASN1_OP_MATCH__ACT) {
+ unsigned char act;
+
+ if (op & ASN1_OP_MATCH__ANY)
+ act = machine[pc + 1];
+ else
+ act = machine[pc + 2];
+ ret = actions[act](context, hdr, tag, data + dp, len);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (!(flags & FLAG_CONS))
+ dp += len;
+ pc += asn1_op_lengths[op];
+ goto next_op;
+
+ case ASN1_OP_MATCH_JUMP:
+ case ASN1_OP_MATCH_JUMP_OR_SKIP:
+ case ASN1_OP_COND_MATCH_JUMP_OR_SKIP:
+ pr_debug("- MATCH_JUMP\n");
+ if (unlikely(jsp == NR_JUMP_STACK))
+ goto jump_stack_overflow;
+ jump_stack[jsp++] = pc + asn1_op_lengths[op];
+ pc = machine[pc + 2];
+ goto next_op;
+
+ case ASN1_OP_COND_FAIL:
+ if (unlikely(!(flags & FLAG_MATCHED)))
+ goto tag_mismatch;
+ pc += asn1_op_lengths[op];
+ goto next_op;
+
+ case ASN1_OP_COMPLETE:
+ if (unlikely(jsp != 0 || csp != 0)) {
+ pr_err("ASN.1 decoder error: Stacks not empty at completion (%u, %u)\n",
+ jsp, csp);
+ return -EBADMSG;
+ }
+ return 0;
+
+ case ASN1_OP_END_SET:
+ case ASN1_OP_END_SET_ACT:
+ if (unlikely(!(flags & FLAG_MATCHED)))
+ goto tag_mismatch;
+ /* fall through */
+
+ case ASN1_OP_END_SEQ:
+ case ASN1_OP_END_SET_OF:
+ case ASN1_OP_END_SEQ_OF:
+ case ASN1_OP_END_SEQ_ACT:
+ case ASN1_OP_END_SET_OF_ACT:
+ case ASN1_OP_END_SEQ_OF_ACT:
+ if (unlikely(csp <= 0))
+ goto cons_stack_underflow;
+ csp--;
+ tdp = cons_dp_stack[csp];
+ hdr = cons_hdrlen_stack[csp];
+ len = datalen;
+ datalen = cons_datalen_stack[csp];
+ pr_debug("- end cons t=%zu dp=%zu l=%zu/%zu\n",
+ tdp, dp, len, datalen);
+ if (datalen == 0) {
+ /* Indefinite length - check for the EOC. */
+ datalen = len;
+ if (unlikely(datalen - dp < 2))
+ goto data_overrun_error;
+ if (data[dp++] != 0) {
+ if (op & ASN1_OP_END__OF) {
+ dp--;
+ csp++;
+ pc = machine[pc + 1];
+ pr_debug("- continue\n");
+ goto next_op;
+ }
+ goto missing_eoc;
+ }
+ if (data[dp++] != 0)
+ goto invalid_eoc;
+ len = dp - tdp - 2;
+ } else {
+ if (dp < len && (op & ASN1_OP_END__OF)) {
+ datalen = len;
+ csp++;
+ pc = machine[pc + 1];
+ pr_debug("- continue\n");
+ goto next_op;
+ }
+ if (dp != len)
+ goto cons_length_error;
+ len -= tdp;
+ pr_debug("- cons len l=%zu d=%zu\n", len, dp - tdp);
+ }
+
+ if (op & ASN1_OP_END__ACT) {
+ unsigned char act;
+ if (op & ASN1_OP_END__OF)
+ act = machine[pc + 2];
+ else
+ act = machine[pc + 1];
+ ret = actions[act](context, hdr, 0, data + tdp, len);
+ if (ret < 0)
+ return ret;
+ }
+ pc += asn1_op_lengths[op];
+ goto next_op;
+
+ case ASN1_OP_MAYBE_ACT:
+ if (!(flags & FLAG_LAST_MATCHED)) {
+ pc += asn1_op_lengths[op];
+ goto next_op;
+ }
+ /* fall through */
+
+ case ASN1_OP_ACT:
+ ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len);
+ if (ret < 0)
+ return ret;
+ pc += asn1_op_lengths[op];
+ goto next_op;
+
+ case ASN1_OP_RETURN:
+ if (unlikely(jsp <= 0))
+ goto jump_stack_underflow;
+ pc = jump_stack[--jsp];
+ flags |= FLAG_MATCHED | FLAG_LAST_MATCHED;
+ goto next_op;
+
+ default:
+ break;
+ }
+
+ /* Shouldn't reach here */
+ pr_err("ASN.1 decoder error: Found reserved opcode (%u) pc=%zu\n",
+ op, pc);
+ return -EBADMSG;
+
+data_overrun_error:
+ errmsg = "Data overrun error";
+ goto error;
+machine_overrun_error:
+ errmsg = "Machine overrun error";
+ goto error;
+jump_stack_underflow:
+ errmsg = "Jump stack underflow";
+ goto error;
+jump_stack_overflow:
+ errmsg = "Jump stack overflow";
+ goto error;
+cons_stack_underflow:
+ errmsg = "Cons stack underflow";
+ goto error;
+cons_stack_overflow:
+ errmsg = "Cons stack overflow";
+ goto error;
+cons_length_error:
+ errmsg = "Cons length error";
+ goto error;
+missing_eoc:
+ errmsg = "Missing EOC in indefinite len cons";
+ goto error;
+invalid_eoc:
+ errmsg = "Invalid length EOC";
+ goto error;
+length_too_long:
+ errmsg = "Unsupported length";
+ goto error;
+indefinite_len_primitive:
+ errmsg = "Indefinite len primitive not permitted";
+ goto error;
+tag_mismatch:
+ errmsg = "Unexpected tag";
+ goto error;
+long_tag_not_supported:
+ errmsg = "Long tag not supported";
+error:
+ pr_debug("\nASN1: %s [m=%zu d=%zu ot=%02x t=%02x l=%zu]\n",
+ errmsg, pc, dp, optag, tag, len);
+ return -EBADMSG;
+}
+EXPORT_SYMBOL_GPL(asn1_ber_decoder);
+
+MODULE_LICENSE("GPL");
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
new file mode 100644
index 0000000000..2b221b915a
--- /dev/null
+++ b/lib/crypto/Kconfig
@@ -0,0 +1,52 @@
+menuconfig ASYMMETRIC_KEY_TYPE
+ bool "Asymmetric (public-key cryptographic) key Support"
+ help
+ This option provides support for a key type that holds the data for
+ the asymmetric keys used for public key cryptographic operations such
+ as encryption, decryption, signature generation and signature
+ verification.
+
+if ASYMMETRIC_KEY_TYPE
+
+config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+ bool "Asymmetric public-key crypto algorithm subtype"
+ help
+ This option provides support for asymmetric public key type handling.
+ If signature generation and/or verification are to be used,
+ appropriate hash algorithms (such as SHA-1) must be available.
+ ENOPKG will be reported if the requisite algorithm is unavailable.
+
+config RSA_PUBLIC_KEY_PARSER
+ bool "RSA public key parser"
+ depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+ select ASN1_DECODER
+ select ASN1_COMPILER
+ select OID_REGISTRY
+ help
+ This option provides support for parsing a blob containing RSA
+ public key data and provides the ability to instantiate a public
+ key.
+
+config X509_CERTIFICATE_PARSER
+ bool "X.509 certificate parser"
+ depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+ select ASN1_DECODER
+ select ASN1_COMPILER
+ select OID_REGISTRY
+ select LIB_DATE
+ help
+ This option provides support for parsing X.509 format blobs for key
+ data and provides the ability to instantiate a crypto key from a
+ public key packet found inside the certificate.
+
+config PKCS7_MESSAGE_PARSER
+ bool "PKCS#7 message parser"
+ depends on X509_CERTIFICATE_PARSER
+ select ASN1_DECODER
+ select ASN1_COMPILER
+ select OID_REGISTRY
+ help
+ This option provides support for parsing PKCS#7 format messages for
+ signature data and provides the ability to verify the signature.
+
+endif # ASYMMETRIC_KEY_TYPE
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
new file mode 100644
index 0000000000..8267fee0a7
--- /dev/null
+++ b/lib/crypto/Makefile
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Makefile for asymmetric cryptographic keys
+#
+
+obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
+
+asymmetric_keys-y := asymmetric_type.o
+
+obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
+
+#
+# RSA public key parser
+#
+obj-$(CONFIG_RSA_PUBLIC_KEY_PARSER) += rsa_public_key.o
+rsa_public_key-y := \
+ rsapubkey.asn1.o \
+ rsa_helper.o
+
+$(obj)/rsapubkey.asn1.o: $(obj)/rsapubkey.asn1.c $(obj)/rsapubkey.asn1.h
+$(obj)/rsa_helper.o: $(obj)/rsapubkey.asn1.h
+
+#
+# X.509 Certificate handling
+#
+obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o
+x509_key_parser-y := \
+ x509.asn1.o \
+ x509_akid.asn1.o \
+ x509_cert_parser.o \
+ x509_public_key.o
+
+$(obj)/x509_cert_parser.o: \
+ $(obj)/x509.asn1.h \
+ $(obj)/x509_akid.asn1.h
+
+$(obj)/x509.asn1.o: $(obj)/x509.asn1.c $(obj)/x509.asn1.h
+$(obj)/x509_akid.asn1.o: $(obj)/x509_akid.asn1.c $(obj)/x509_akid.asn1.h
+
+#
+# PKCS#7 message handling
+#
+obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o
+pkcs7_message-y := \
+ pkcs7.asn1.o \
+ pkcs7_parser.o
+
+$(obj)/pkcs7_parser.o: $(obj)/pkcs7.asn1.h
+$(obj)/pkcs7.asn1.o: $(obj)/pkcs7.asn1.c $(obj)/pkcs7.asn1.h
diff --git a/lib/crypto/asymmetric_type.c b/lib/crypto/asymmetric_type.c
new file mode 100644
index 0000000000..e04666c080
--- /dev/null
+++ b/lib/crypto/asymmetric_type.c
@@ -0,0 +1,668 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Asymmetric public-key cryptography key type
+ *
+ * See Documentation/crypto/asymmetric-keys.txt
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+#ifndef __UBOOT__
+#include <keys/asymmetric-subtype.h>
+#include <keys/asymmetric-parser.h>
+#endif
+#include <crypto/public_key.h>
+#ifdef __UBOOT__
+#include <linux/compat.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#else
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#endif
+#ifdef __UBOOT__
+#include <keys/asymmetric-type.h>
+#else
+#include <keys/system_keyring.h>
+#include <keys/user-type.h>
+#include "asymmetric_keys.h"
+#endif
+
+MODULE_LICENSE("GPL");
+
+#ifndef __UBOOT__
+const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = {
+ [VERIFYING_MODULE_SIGNATURE] = "mod sig",
+ [VERIFYING_FIRMWARE_SIGNATURE] = "firmware sig",
+ [VERIFYING_KEXEC_PE_SIGNATURE] = "kexec PE sig",
+ [VERIFYING_KEY_SIGNATURE] = "key sig",
+ [VERIFYING_KEY_SELF_SIGNATURE] = "key self sig",
+ [VERIFYING_UNSPECIFIED_SIGNATURE] = "unspec sig",
+};
+EXPORT_SYMBOL_GPL(key_being_used_for);
+
+static LIST_HEAD(asymmetric_key_parsers);
+static DECLARE_RWSEM(asymmetric_key_parsers_sem);
+
+/**
+ * find_asymmetric_key - Find a key by ID.
+ * @keyring: The keys to search.
+ * @id_0: The first ID to look for or NULL.
+ * @id_1: The second ID to look for or NULL.
+ * @partial: Use partial match if true, exact if false.
+ *
+ * Find a key in the given keyring by identifier. The preferred identifier is
+ * the id_0 and the fallback identifier is the id_1. If both are given, the
+ * lookup is by the former, but the latter must also match.
+ */
+struct key *find_asymmetric_key(struct key *keyring,
+ const struct asymmetric_key_id *id_0,
+ const struct asymmetric_key_id *id_1,
+ bool partial)
+{
+ struct key *key;
+ key_ref_t ref;
+ const char *lookup;
+ char *req, *p;
+ int len;
+
+ BUG_ON(!id_0 && !id_1);
+
+ if (id_0) {
+ lookup = id_0->data;
+ len = id_0->len;
+ } else {
+ lookup = id_1->data;
+ len = id_1->len;
+ }
+
+ /* Construct an identifier "id:<keyid>". */
+ p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
+ if (!req)
+ return ERR_PTR(-ENOMEM);
+
+ if (partial) {
+ *p++ = 'i';
+ *p++ = 'd';
+ } else {
+ *p++ = 'e';
+ *p++ = 'x';
+ }
+ *p++ = ':';
+ p = bin2hex(p, lookup, len);
+ *p = 0;
+
+ pr_debug("Look up: \"%s\"\n", req);
+
+ ref = keyring_search(make_key_ref(keyring, 1),
+ &key_type_asymmetric, req, true);
+ if (IS_ERR(ref))
+ pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
+ kfree(req);
+
+ if (IS_ERR(ref)) {
+ switch (PTR_ERR(ref)) {
+ /* Hide some search errors */
+ case -EACCES:
+ case -ENOTDIR:
+ case -EAGAIN:
+ return ERR_PTR(-ENOKEY);
+ default:
+ return ERR_CAST(ref);
+ }
+ }
+
+ key = key_ref_to_ptr(ref);
+ if (id_0 && id_1) {
+ const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+
+ if (!kids->id[1]) {
+ pr_debug("First ID matches, but second is missing\n");
+ goto reject;
+ }
+ if (!asymmetric_key_id_same(id_1, kids->id[1])) {
+ pr_debug("First ID matches, but second does not\n");
+ goto reject;
+ }
+ }
+
+ pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
+ return key;
+
+reject:
+ key_put(key);
+ return ERR_PTR(-EKEYREJECTED);
+}
+EXPORT_SYMBOL_GPL(find_asymmetric_key);
+#endif /* !__UBOOT__ */
+
+/**
+ * asymmetric_key_generate_id: Construct an asymmetric key ID
+ * @val_1: First binary blob
+ * @len_1: Length of first binary blob
+ * @val_2: Second binary blob
+ * @len_2: Length of second binary blob
+ *
+ * Construct an asymmetric key ID from a pair of binary blobs.
+ */
+struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
+ size_t len_1,
+ const void *val_2,
+ size_t len_2)
+{
+ struct asymmetric_key_id *kid;
+
+ kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
+ GFP_KERNEL);
+ if (!kid)
+ return ERR_PTR(-ENOMEM);
+ kid->len = len_1 + len_2;
+ memcpy(kid->data, val_1, len_1);
+ memcpy(kid->data + len_1, val_2, len_2);
+ return kid;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_generate_id);
+
+/**
+ * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same.
+ * @kid_1, @kid_2: The key IDs to compare
+ */
+bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
+ const struct asymmetric_key_id *kid2)
+{
+ if (!kid1 || !kid2)
+ return false;
+ if (kid1->len != kid2->len)
+ return false;
+ return memcmp(kid1->data, kid2->data, kid1->len) == 0;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_id_same);
+
+/**
+ * asymmetric_key_id_partial - Return true if two asymmetric keys IDs
+ * partially match
+ * @kid_1, @kid_2: The key IDs to compare
+ */
+bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
+ const struct asymmetric_key_id *kid2)
+{
+ if (!kid1 || !kid2)
+ return false;
+ if (kid1->len < kid2->len)
+ return false;
+ return memcmp(kid1->data + (kid1->len - kid2->len),
+ kid2->data, kid2->len) == 0;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_id_partial);
+
+#ifndef __UBOOT__
+/**
+ * asymmetric_match_key_ids - Search asymmetric key IDs
+ * @kids: The list of key IDs to check
+ * @match_id: The key ID we're looking for
+ * @match: The match function to use
+ */
+static bool asymmetric_match_key_ids(
+ const struct asymmetric_key_ids *kids,
+ const struct asymmetric_key_id *match_id,
+ bool (*match)(const struct asymmetric_key_id *kid1,
+ const struct asymmetric_key_id *kid2))
+{
+ int i;
+
+ if (!kids || !match_id)
+ return false;
+ for (i = 0; i < ARRAY_SIZE(kids->id); i++)
+ if (match(kids->id[i], match_id))
+ return true;
+ return false;
+}
+
+/* helper function can be called directly with pre-allocated memory */
+inline int __asymmetric_key_hex_to_key_id(const char *id,
+ struct asymmetric_key_id *match_id,
+ size_t hexlen)
+{
+ match_id->len = hexlen;
+ return hex2bin(match_id->data, id, hexlen);
+}
+
+/**
+ * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID.
+ * @id: The ID as a hex string.
+ */
+struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
+{
+ struct asymmetric_key_id *match_id;
+ size_t asciihexlen;
+ int ret;
+
+ if (!*id)
+ return ERR_PTR(-EINVAL);
+ asciihexlen = strlen(id);
+ if (asciihexlen & 1)
+ return ERR_PTR(-EINVAL);
+
+ match_id = kmalloc(sizeof(struct asymmetric_key_id) + asciihexlen / 2,
+ GFP_KERNEL);
+ if (!match_id)
+ return ERR_PTR(-ENOMEM);
+ ret = __asymmetric_key_hex_to_key_id(id, match_id, asciihexlen / 2);
+ if (ret < 0) {
+ kfree(match_id);
+ return ERR_PTR(-EINVAL);
+ }
+ return match_id;
+}
+
+/*
+ * Match asymmetric keys by an exact match on an ID.
+ */
+static bool asymmetric_key_cmp(const struct key *key,
+ const struct key_match_data *match_data)
+{
+ const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+ const struct asymmetric_key_id *match_id = match_data->preparsed;
+
+ return asymmetric_match_key_ids(kids, match_id,
+ asymmetric_key_id_same);
+}
+
+/*
+ * Match asymmetric keys by a partial match on an IDs.
+ */
+static bool asymmetric_key_cmp_partial(const struct key *key,
+ const struct key_match_data *match_data)
+{
+ const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+ const struct asymmetric_key_id *match_id = match_data->preparsed;
+
+ return asymmetric_match_key_ids(kids, match_id,
+ asymmetric_key_id_partial);
+}
+
+/*
+ * Preparse the match criterion. If we don't set lookup_type and cmp,
+ * the default will be an exact match on the key description.
+ *
+ * There are some specifiers for matching key IDs rather than by the key
+ * description:
+ *
+ * "id:<id>" - find a key by partial match on any available ID
+ * "ex:<id>" - find a key by exact match on any available ID
+ *
+ * These have to be searched by iteration rather than by direct lookup because
+ * the key is hashed according to its description.
+ */
+static int asymmetric_key_match_preparse(struct key_match_data *match_data)
+{
+ struct asymmetric_key_id *match_id;
+ const char *spec = match_data->raw_data;
+ const char *id;
+ bool (*cmp)(const struct key *, const struct key_match_data *) =
+ asymmetric_key_cmp;
+
+ if (!spec || !*spec)
+ return -EINVAL;
+ if (spec[0] == 'i' &&
+ spec[1] == 'd' &&
+ spec[2] == ':') {
+ id = spec + 3;
+ cmp = asymmetric_key_cmp_partial;
+ } else if (spec[0] == 'e' &&
+ spec[1] == 'x' &&
+ spec[2] == ':') {
+ id = spec + 3;
+ } else {
+ goto default_match;
+ }
+
+ match_id = asymmetric_key_hex_to_key_id(id);
+ if (IS_ERR(match_id))
+ return PTR_ERR(match_id);
+
+ match_data->preparsed = match_id;
+ match_data->cmp = cmp;
+ match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
+ return 0;
+
+default_match:
+ return 0;
+}
+
+/*
+ * Free the preparsed the match criterion.
+ */
+static void asymmetric_key_match_free(struct key_match_data *match_data)
+{
+ kfree(match_data->preparsed);
+}
+
+/*
+ * Describe the asymmetric key
+ */
+static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
+{
+ const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
+ const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+ const struct asymmetric_key_id *kid;
+ const unsigned char *p;
+ int n;
+
+ seq_puts(m, key->description);
+
+ if (subtype) {
+ seq_puts(m, ": ");
+ subtype->describe(key, m);
+
+ if (kids && kids->id[1]) {
+ kid = kids->id[1];
+ seq_putc(m, ' ');
+ n = kid->len;
+ p = kid->data;
+ if (n > 4) {
+ p += n - 4;
+ n = 4;
+ }
+ seq_printf(m, "%*phN", n, p);
+ }
+
+ seq_puts(m, " [");
+ /* put something here to indicate the key's capabilities */
+ seq_putc(m, ']');
+ }
+}
+
+/*
+ * Preparse a asymmetric payload to get format the contents appropriately for the
+ * internal payload to cut down on the number of scans of the data performed.
+ *
+ * We also generate a proposed description from the contents of the key that
+ * can be used to name the key if the user doesn't want to provide one.
+ */
+static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
+{
+ struct asymmetric_key_parser *parser;
+ int ret;
+
+ pr_devel("==>%s()\n", __func__);
+
+ if (prep->datalen == 0)
+ return -EINVAL;
+
+ down_read(&asymmetric_key_parsers_sem);
+
+ ret = -EBADMSG;
+ list_for_each_entry(parser, &asymmetric_key_parsers, link) {
+ pr_debug("Trying parser '%s'\n", parser->name);
+
+ ret = parser->parse(prep);
+ if (ret != -EBADMSG) {
+ pr_debug("Parser recognised the format (ret %d)\n",
+ ret);
+ break;
+ }
+ }
+
+ up_read(&asymmetric_key_parsers_sem);
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+}
+
+/*
+ * Clean up the key ID list
+ */
+static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
+{
+ int i;
+
+ if (kids) {
+ for (i = 0; i < ARRAY_SIZE(kids->id); i++)
+ kfree(kids->id[i]);
+ kfree(kids);
+ }
+}
+
+/*
+ * Clean up the preparse data
+ */
+static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
+{
+ struct asymmetric_key_subtype *subtype = prep->payload.data[asym_subtype];
+ struct asymmetric_key_ids *kids = prep->payload.data[asym_key_ids];
+
+ pr_devel("==>%s()\n", __func__);
+
+ if (subtype) {
+ subtype->destroy(prep->payload.data[asym_crypto],
+ prep->payload.data[asym_auth]);
+ module_put(subtype->owner);
+ }
+ asymmetric_key_free_kids(kids);
+ kfree(prep->description);
+}
+
+/*
+ * dispose of the data dangling from the corpse of a asymmetric key
+ */
+static void asymmetric_key_destroy(struct key *key)
+{
+ struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
+ struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids];
+ void *data = key->payload.data[asym_crypto];
+ void *auth = key->payload.data[asym_auth];
+
+ key->payload.data[asym_crypto] = NULL;
+ key->payload.data[asym_subtype] = NULL;
+ key->payload.data[asym_key_ids] = NULL;
+ key->payload.data[asym_auth] = NULL;
+
+ if (subtype) {
+ subtype->destroy(data, auth);
+ module_put(subtype->owner);
+ }
+
+ asymmetric_key_free_kids(kids);
+}
+
+static struct key_restriction *asymmetric_restriction_alloc(
+ key_restrict_link_func_t check,
+ struct key *key)
+{
+ struct key_restriction *keyres =
+ kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
+
+ if (!keyres)
+ return ERR_PTR(-ENOMEM);
+
+ keyres->check = check;
+ keyres->key = key;
+ keyres->keytype = &key_type_asymmetric;
+
+ return keyres;
+}
+
+/*
+ * look up keyring restrict functions for asymmetric keys
+ */
+static struct key_restriction *asymmetric_lookup_restriction(
+ const char *restriction)
+{
+ char *restrict_method;
+ char *parse_buf;
+ char *next;
+ struct key_restriction *ret = ERR_PTR(-EINVAL);
+
+ if (strcmp("builtin_trusted", restriction) == 0)
+ return asymmetric_restriction_alloc(
+ restrict_link_by_builtin_trusted, NULL);
+
+ if (strcmp("builtin_and_secondary_trusted", restriction) == 0)
+ return asymmetric_restriction_alloc(
+ restrict_link_by_builtin_and_secondary_trusted, NULL);
+
+ parse_buf = kstrndup(restriction, PAGE_SIZE, GFP_KERNEL);
+ if (!parse_buf)
+ return ERR_PTR(-ENOMEM);
+
+ next = parse_buf;
+ restrict_method = strsep(&next, ":");
+
+ if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) {
+ char *key_text;
+ key_serial_t serial;
+ struct key *key;
+ key_restrict_link_func_t link_fn =
+ restrict_link_by_key_or_keyring;
+ bool allow_null_key = false;
+
+ key_text = strsep(&next, ":");
+
+ if (next) {
+ if (strcmp(next, "chain") != 0)
+ goto out;
+
+ link_fn = restrict_link_by_key_or_keyring_chain;
+ allow_null_key = true;
+ }
+
+ if (kstrtos32(key_text, 0, &serial) < 0)
+ goto out;
+
+ if ((serial == 0) && allow_null_key) {
+ key = NULL;
+ } else {
+ key = key_lookup(serial);
+ if (IS_ERR(key)) {
+ ret = ERR_CAST(key);
+ goto out;
+ }
+ }
+
+ ret = asymmetric_restriction_alloc(link_fn, key);
+ if (IS_ERR(ret))
+ key_put(key);
+ }
+
+out:
+ kfree(parse_buf);
+ return ret;
+}
+
+int asymmetric_key_eds_op(struct kernel_pkey_params *params,
+ const void *in, void *out)
+{
+ const struct asymmetric_key_subtype *subtype;
+ struct key *key = params->key;
+ int ret;
+
+ pr_devel("==>%s()\n", __func__);
+
+ if (key->type != &key_type_asymmetric)
+ return -EINVAL;
+ subtype = asymmetric_key_subtype(key);
+ if (!subtype ||
+ !key->payload.data[0])
+ return -EINVAL;
+ if (!subtype->eds_op)
+ return -ENOTSUPP;
+
+ ret = subtype->eds_op(params, in, out);
+
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+}
+
+static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
+ const void *in, const void *in2)
+{
+ struct public_key_signature sig = {
+ .s_size = params->in2_len,
+ .digest_size = params->in_len,
+ .encoding = params->encoding,
+ .hash_algo = params->hash_algo,
+ .digest = (void *)in,
+ .s = (void *)in2,
+ };
+
+ return verify_signature(params->key, &sig);
+}
+
+struct key_type key_type_asymmetric = {
+ .name = "asymmetric",
+ .preparse = asymmetric_key_preparse,
+ .free_preparse = asymmetric_key_free_preparse,
+ .instantiate = generic_key_instantiate,
+ .match_preparse = asymmetric_key_match_preparse,
+ .match_free = asymmetric_key_match_free,
+ .destroy = asymmetric_key_destroy,
+ .describe = asymmetric_key_describe,
+ .lookup_restriction = asymmetric_lookup_restriction,
+ .asym_query = query_asymmetric_key,
+ .asym_eds_op = asymmetric_key_eds_op,
+ .asym_verify_signature = asymmetric_key_verify_signature,
+};
+EXPORT_SYMBOL_GPL(key_type_asymmetric);
+
+/**
+ * register_asymmetric_key_parser - Register a asymmetric key blob parser
+ * @parser: The parser to register
+ */
+int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
+{
+ struct asymmetric_key_parser *cursor;
+ int ret;
+
+ down_write(&asymmetric_key_parsers_sem);
+
+ list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
+ if (strcmp(cursor->name, parser->name) == 0) {
+ pr_err("Asymmetric key parser '%s' already registered\n",
+ parser->name);
+ ret = -EEXIST;
+ goto out;
+ }
+ }
+
+ list_add_tail(&parser->link, &asymmetric_key_parsers);
+
+ pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
+ ret = 0;
+
+out:
+ up_write(&asymmetric_key_parsers_sem);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
+
+/**
+ * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
+ * @parser: The parser to unregister
+ */
+void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
+{
+ down_write(&asymmetric_key_parsers_sem);
+ list_del(&parser->link);
+ up_write(&asymmetric_key_parsers_sem);
+
+ pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
+}
+EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
+
+/*
+ * Module stuff
+ */
+static int __init asymmetric_key_init(void)
+{
+ return register_key_type(&key_type_asymmetric);
+}
+
+static void __exit asymmetric_key_cleanup(void)
+{
+ unregister_key_type(&key_type_asymmetric);
+}
+
+module_init(asymmetric_key_init);
+module_exit(asymmetric_key_cleanup);
+#endif /* !__UBOOT__ */
diff --git a/lib/crypto/pkcs7.asn1 b/lib/crypto/pkcs7.asn1
new file mode 100644
index 0000000000..1eca740b81
--- /dev/null
+++ b/lib/crypto/pkcs7.asn1
@@ -0,0 +1,135 @@
+PKCS7ContentInfo ::= SEQUENCE {
+ contentType ContentType ({ pkcs7_check_content_type }),
+ content [0] EXPLICIT SignedData OPTIONAL
+}
+
+ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID })
+
+SignedData ::= SEQUENCE {
+ version INTEGER ({ pkcs7_note_signeddata_version }),
+ digestAlgorithms DigestAlgorithmIdentifiers,
+ contentInfo ContentInfo ({ pkcs7_note_content }),
+ certificates CHOICE {
+ certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
+ certSequence [2] IMPLICIT Certificates
+ } OPTIONAL ({ pkcs7_note_certificate_list }),
+ crls CHOICE {
+ crlSet [1] IMPLICIT CertificateRevocationLists,
+ crlSequence [3] IMPLICIT CRLSequence
+ } OPTIONAL,
+ signerInfos SignerInfos
+}
+
+ContentInfo ::= SEQUENCE {
+ contentType ContentType ({ pkcs7_note_OID }),
+ content [0] EXPLICIT Data OPTIONAL
+}
+
+Data ::= ANY ({ pkcs7_note_data })
+
+DigestAlgorithmIdentifiers ::= CHOICE {
+ daSet SET OF DigestAlgorithmIdentifier,
+ daSequence SEQUENCE OF DigestAlgorithmIdentifier
+}
+
+DigestAlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+ parameters ANY OPTIONAL
+}
+
+--
+-- Certificates and certificate lists
+--
+ExtendedCertificatesAndCertificates ::= SET OF ExtendedCertificateOrCertificate
+
+ExtendedCertificateOrCertificate ::= CHOICE {
+ certificate Certificate, -- X.509
+ extendedCertificate [0] IMPLICIT ExtendedCertificate -- PKCS#6
+}
+
+ExtendedCertificate ::= Certificate -- cheating
+
+Certificates ::= SEQUENCE OF Certificate
+
+CertificateRevocationLists ::= SET OF CertificateList
+
+CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly
+
+CRLSequence ::= SEQUENCE OF CertificateList
+
+Certificate ::= ANY ({ pkcs7_extract_cert }) -- X.509
+
+--
+-- Signer information
+--
+SignerInfos ::= CHOICE {
+ siSet SET OF SignerInfo,
+ siSequence SEQUENCE OF SignerInfo
+}
+
+SignerInfo ::= SEQUENCE {
+ version INTEGER ({ pkcs7_note_signerinfo_version }),
+ sid SignerIdentifier, -- CMS variant, not PKCS#7
+ digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }),
+ authenticatedAttributes CHOICE {
+ aaSet [0] IMPLICIT SetOfAuthenticatedAttribute
+ ({ pkcs7_sig_note_set_of_authattrs }),
+ aaSequence [2] EXPLICIT SEQUENCE OF AuthenticatedAttribute
+ -- Explicit because easier to compute digest on
+ -- sequence of attributes and then reuse encoded
+ -- sequence in aaSequence.
+ } OPTIONAL,
+ digestEncryptionAlgorithm
+ DigestEncryptionAlgorithmIdentifier ({ pkcs7_sig_note_pkey_algo }),
+ encryptedDigest EncryptedDigest,
+ unauthenticatedAttributes CHOICE {
+ uaSet [1] IMPLICIT SET OF UnauthenticatedAttribute,
+ uaSequence [3] IMPLICIT SEQUENCE OF UnauthenticatedAttribute
+ } OPTIONAL
+} ({ pkcs7_note_signed_info })
+
+SignerIdentifier ::= CHOICE {
+ -- RFC5652 sec 5.3
+ issuerAndSerialNumber IssuerAndSerialNumber,
+ subjectKeyIdentifier [0] IMPLICIT SubjectKeyIdentifier
+}
+
+IssuerAndSerialNumber ::= SEQUENCE {
+ issuer Name ({ pkcs7_sig_note_issuer }),
+ serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial })
+}
+
+CertificateSerialNumber ::= INTEGER
+
+SubjectKeyIdentifier ::= OCTET STRING ({ pkcs7_sig_note_skid })
+
+SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute
+
+AuthenticatedAttribute ::= SEQUENCE {
+ type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+ values SET OF ANY ({ pkcs7_sig_note_authenticated_attr })
+}
+
+UnauthenticatedAttribute ::= SEQUENCE {
+ type OBJECT IDENTIFIER,
+ values SET OF ANY
+}
+
+DigestEncryptionAlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+ parameters ANY OPTIONAL
+}
+
+EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature })
+
+---
+--- X.500 Name
+---
+Name ::= SEQUENCE OF RelativeDistinguishedName
+
+RelativeDistinguishedName ::= SET OF AttributeValueAssertion
+
+AttributeValueAssertion ::= SEQUENCE {
+ attributeType OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+ attributeValue ANY
+}
diff --git a/lib/crypto/pkcs7_parser.c b/lib/crypto/pkcs7_parser.c
new file mode 100644
index 0000000000..bf9e7e888f
--- /dev/null
+++ b/lib/crypto/pkcs7_parser.c
@@ -0,0 +1,693 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* PKCS#7 parser
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#define pr_fmt(fmt) "PKCS7: "fmt
+#ifdef __UBOOT__
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#endif
+#include <linux/kernel.h>
+#ifndef __UBOOT__
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#endif
+#include <linux/err.h>
+#include <linux/oid_registry.h>
+#include <crypto/public_key.h>
+#include "pkcs7_parser.h"
+#include "pkcs7.asn1.h"
+
+MODULE_DESCRIPTION("PKCS#7 parser");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+struct pkcs7_parse_context {
+ struct pkcs7_message *msg; /* Message being constructed */
+ struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */
+ struct pkcs7_signed_info **ppsinfo;
+ struct x509_certificate *certs; /* Certificate cache */
+ struct x509_certificate **ppcerts;
+ unsigned long data; /* Start of data */
+ enum OID last_oid; /* Last OID encountered */
+ unsigned x509_index;
+ unsigned sinfo_index;
+ const void *raw_serial;
+ unsigned raw_serial_size;
+ unsigned raw_issuer_size;
+ const void *raw_issuer;
+ const void *raw_skid;
+ unsigned raw_skid_size;
+ bool expect_skid;
+};
+
+/*
+ * Free a signed information block.
+ */
+static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
+{
+ if (sinfo) {
+ public_key_signature_free(sinfo->sig);
+ kfree(sinfo);
+ }
+}
+
+/**
+ * pkcs7_free_message - Free a PKCS#7 message
+ * @pkcs7: The PKCS#7 message to free
+ */
+void pkcs7_free_message(struct pkcs7_message *pkcs7)
+{
+ struct x509_certificate *cert;
+ struct pkcs7_signed_info *sinfo;
+
+ if (pkcs7) {
+ while (pkcs7->certs) {
+ cert = pkcs7->certs;
+ pkcs7->certs = cert->next;
+ x509_free_certificate(cert);
+ }
+ while (pkcs7->crl) {
+ cert = pkcs7->crl;
+ pkcs7->crl = cert->next;
+ x509_free_certificate(cert);
+ }
+ while (pkcs7->signed_infos) {
+ sinfo = pkcs7->signed_infos;
+ pkcs7->signed_infos = sinfo->next;
+ pkcs7_free_signed_info(sinfo);
+ }
+ kfree(pkcs7);
+ }
+}
+EXPORT_SYMBOL_GPL(pkcs7_free_message);
+
+/*
+ * Check authenticatedAttributes are provided or not provided consistently.
+ */
+static int pkcs7_check_authattrs(struct pkcs7_message *msg)
+{
+ struct pkcs7_signed_info *sinfo;
+ bool want = false;
+
+ sinfo = msg->signed_infos;
+ if (!sinfo)
+ goto inconsistent;
+
+ if (sinfo->authattrs) {
+ want = true;
+ msg->have_authattrs = true;
+ }
+
+ for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
+ if (!!sinfo->authattrs != want)
+ goto inconsistent;
+ return 0;
+
+inconsistent:
+ pr_warn("Inconsistently supplied authAttrs\n");
+ return -EINVAL;
+}
+
+/**
+ * pkcs7_parse_message - Parse a PKCS#7 message
+ * @data: The raw binary ASN.1 encoded message to be parsed
+ * @datalen: The size of the encoded message
+ */
+struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
+{
+ struct pkcs7_parse_context *ctx;
+ struct pkcs7_message *msg = ERR_PTR(-ENOMEM);
+ int ret;
+
+ ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
+ if (!ctx)
+ goto out_no_ctx;
+ ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
+ if (!ctx->msg)
+ goto out_no_msg;
+ ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
+ if (!ctx->sinfo)
+ goto out_no_sinfo;
+ ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
+ GFP_KERNEL);
+ if (!ctx->sinfo->sig)
+ goto out_no_sig;
+
+ ctx->data = (unsigned long)data;
+ ctx->ppcerts = &ctx->certs;
+ ctx->ppsinfo = &ctx->msg->signed_infos;
+
+ /* Attempt to decode the signature */
+ ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
+ if (ret < 0) {
+ msg = ERR_PTR(ret);
+ goto out;
+ }
+
+ ret = pkcs7_check_authattrs(ctx->msg);
+ if (ret < 0) {
+ msg = ERR_PTR(ret);
+ goto out;
+ }
+
+ msg = ctx->msg;
+ ctx->msg = NULL;
+
+out:
+ while (ctx->certs) {
+ struct x509_certificate *cert = ctx->certs;
+ ctx->certs = cert->next;
+ x509_free_certificate(cert);
+ }
+out_no_sig:
+ pkcs7_free_signed_info(ctx->sinfo);
+out_no_sinfo:
+ pkcs7_free_message(ctx->msg);
+out_no_msg:
+ kfree(ctx);
+out_no_ctx:
+ return msg;
+}
+EXPORT_SYMBOL_GPL(pkcs7_parse_message);
+
+/**
+ * pkcs7_get_content_data - Get access to the PKCS#7 content
+ * @pkcs7: The preparsed PKCS#7 message to access
+ * @_data: Place to return a pointer to the data
+ * @_data_len: Place to return the data length
+ * @_headerlen: Size of ASN.1 header not included in _data
+ *
+ * Get access to the data content of the PKCS#7 message. The size of the
+ * header of the ASN.1 object that contains it is also provided and can be used
+ * to adjust *_data and *_data_len to get the entire object.
+ *
+ * Returns -ENODATA if the data object was missing from the message.
+ */
+int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
+ const void **_data, size_t *_data_len,
+ size_t *_headerlen)
+{
+ if (!pkcs7->data)
+ return -ENODATA;
+
+ *_data = pkcs7->data;
+ *_data_len = pkcs7->data_len;
+ if (_headerlen)
+ *_headerlen = pkcs7->data_hdrlen;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
+
+/*
+ * Note an OID when we find one for later processing when we know how
+ * to interpret it.
+ */
+int pkcs7_note_OID(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ ctx->last_oid = look_up_OID(value, vlen);
+ if (ctx->last_oid == OID__NR) {
+ char buffer[50];
+ sprint_oid(value, vlen, buffer, sizeof(buffer));
+ printk("PKCS7: Unknown OID: [%lu] %s\n",
+ (unsigned long)value - ctx->data, buffer);
+ }
+ return 0;
+}
+
+/*
+ * Note the digest algorithm for the signature.
+ */
+int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ switch (ctx->last_oid) {
+ case OID_md4:
+ ctx->sinfo->sig->hash_algo = "md4";
+ break;
+ case OID_md5:
+ ctx->sinfo->sig->hash_algo = "md5";
+ break;
+ case OID_sha1:
+ ctx->sinfo->sig->hash_algo = "sha1";
+ break;
+ case OID_sha256:
+ ctx->sinfo->sig->hash_algo = "sha256";
+ break;
+ case OID_sha384:
+ ctx->sinfo->sig->hash_algo = "sha384";
+ break;
+ case OID_sha512:
+ ctx->sinfo->sig->hash_algo = "sha512";
+ break;
+ case OID_sha224:
+ ctx->sinfo->sig->hash_algo = "sha224";
+ break;
+ default:
+ printk("Unsupported digest algo: %u\n", ctx->last_oid);
+ return -ENOPKG;
+ }
+ return 0;
+}
+
+/*
+ * Note the public key algorithm for the signature.
+ */
+int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ switch (ctx->last_oid) {
+ case OID_rsaEncryption:
+ ctx->sinfo->sig->pkey_algo = "rsa";
+ ctx->sinfo->sig->encoding = "pkcs1";
+ break;
+ default:
+ printk("Unsupported pkey algo: %u\n", ctx->last_oid);
+ return -ENOPKG;
+ }
+ return 0;
+}
+
+/*
+ * We only support signed data [RFC2315 sec 9].
+ */
+int pkcs7_check_content_type(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ if (ctx->last_oid != OID_signed_data) {
+ pr_warn("Only support pkcs7_signedData type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Note the SignedData version
+ */
+int pkcs7_note_signeddata_version(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+ unsigned version;
+
+ if (vlen != 1)
+ goto unsupported;
+
+ ctx->msg->version = version = *(const u8 *)value;
+ switch (version) {
+ case 1:
+ /* PKCS#7 SignedData [RFC2315 sec 9.1]
+ * CMS ver 1 SignedData [RFC5652 sec 5.1]
+ */
+ break;
+ case 3:
+ /* CMS ver 3 SignedData [RFC2315 sec 5.1] */
+ break;
+ default:
+ goto unsupported;
+ }
+
+ return 0;
+
+unsupported:
+ pr_warn("Unsupported SignedData version\n");
+ return -EINVAL;
+}
+
+/*
+ * Note the SignerInfo version
+ */
+int pkcs7_note_signerinfo_version(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+ unsigned version;
+
+ if (vlen != 1)
+ goto unsupported;
+
+ version = *(const u8 *)value;
+ switch (version) {
+ case 1:
+ /* PKCS#7 SignerInfo [RFC2315 sec 9.2]
+ * CMS ver 1 SignerInfo [RFC5652 sec 5.3]
+ */
+ if (ctx->msg->version != 1)
+ goto version_mismatch;
+ ctx->expect_skid = false;
+ break;
+ case 3:
+ /* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */
+ if (ctx->msg->version == 1)
+ goto version_mismatch;
+ ctx->expect_skid = true;
+ break;
+ default:
+ goto unsupported;
+ }
+
+ return 0;
+
+unsupported:
+ pr_warn("Unsupported SignerInfo version\n");
+ return -EINVAL;
+version_mismatch:
+ pr_warn("SignedData-SignerInfo version mismatch\n");
+ return -EBADMSG;
+}
+
+/*
+ * Extract a certificate and store it in the context.
+ */
+int pkcs7_extract_cert(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+ struct x509_certificate *x509;
+
+ if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) {
+ pr_debug("Cert began with tag %02x at %lu\n",
+ tag, (unsigned long)ctx - ctx->data);
+ return -EBADMSG;
+ }
+
+ /* We have to correct for the header so that the X.509 parser can start
+ * from the beginning. Note that since X.509 stipulates DER, there
+ * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which
+ * stipulates BER).
+ */
+ value -= hdrlen;
+ vlen += hdrlen;
+
+ if (((u8*)value)[1] == 0x80)
+ vlen += 2; /* Indefinite length - there should be an EOC */
+
+ x509 = x509_cert_parse(value, vlen);
+ if (IS_ERR(x509))
+ return PTR_ERR(x509);
+
+ x509->index = ++ctx->x509_index;
+ pr_debug("Got cert %u for %s\n", x509->index, x509->subject);
+ pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data);
+
+ *ctx->ppcerts = x509;
+ ctx->ppcerts = &x509->next;
+ return 0;
+}
+
+/*
+ * Save the certificate list
+ */
+int pkcs7_note_certificate_list(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ pr_devel("Got cert list (%02x)\n", tag);
+
+ *ctx->ppcerts = ctx->msg->certs;
+ ctx->msg->certs = ctx->certs;
+ ctx->certs = NULL;
+ ctx->ppcerts = &ctx->certs;
+ return 0;
+}
+
+/*
+ * Note the content type.
+ */
+int pkcs7_note_content(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ if (ctx->last_oid != OID_data &&
+ ctx->last_oid != OID_msIndirectData) {
+ pr_warn("Unsupported data type %d\n", ctx->last_oid);
+ return -EINVAL;
+ }
+
+ ctx->msg->data_type = ctx->last_oid;
+ return 0;
+}
+
+/*
+ * Extract the data from the message and store that and its content type OID in
+ * the context.
+ */
+int pkcs7_note_data(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ pr_debug("Got data\n");
+
+ ctx->msg->data = value;
+ ctx->msg->data_len = vlen;
+ ctx->msg->data_hdrlen = hdrlen;
+ return 0;
+}
+
+/*
+ * Parse authenticated attributes.
+ */
+int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+ struct pkcs7_signed_info *sinfo = ctx->sinfo;
+ enum OID content_type;
+
+ pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
+
+ switch (ctx->last_oid) {
+ case OID_contentType:
+ if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set))
+ goto repeated;
+ content_type = look_up_OID(value, vlen);
+ if (content_type != ctx->msg->data_type) {
+ pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n",
+ ctx->msg->data_type, sinfo->index,
+ content_type);
+ return -EBADMSG;
+ }
+ return 0;
+
+ case OID_signingTime:
+ if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set))
+ goto repeated;
+ /* Should we check that the signing time is consistent
+ * with the signer's X.509 cert?
+ */
+ return x509_decode_time(&sinfo->signing_time,
+ hdrlen, tag, value, vlen);
+
+ case OID_messageDigest:
+ if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))
+ goto repeated;
+ if (tag != ASN1_OTS)
+ return -EBADMSG;
+ sinfo->msgdigest = value;
+ sinfo->msgdigest_len = vlen;
+ return 0;
+
+ case OID_smimeCapabilites:
+ if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set))
+ goto repeated;
+#ifdef __UBOOT__ /* OID_data is needed for authenticated UEFI variables */
+ if (ctx->msg->data_type != OID_msIndirectData &&
+ ctx->msg->data_type != OID_data) {
+#else
+ if (ctx->msg->data_type != OID_msIndirectData) {
+#endif
+ pr_warn("S/MIME Caps only allowed with Authenticode\n");
+ return -EKEYREJECTED;
+ }
+ return 0;
+
+ /* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE
+ * char URLs and cont[1] 8-bit char URLs.
+ *
+ * Microsoft StatementType seems to contain a list of OIDs that
+ * are also used as extendedKeyUsage types in X.509 certs.
+ */
+ case OID_msSpOpusInfo:
+ if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
+ goto repeated;
+ goto authenticode_check;
+ case OID_msStatementType:
+ if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set))
+ goto repeated;
+ authenticode_check:
+ if (ctx->msg->data_type != OID_msIndirectData) {
+ pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n");
+ return -EKEYREJECTED;
+ }
+ /* I'm not sure how to validate these */
+ return 0;
+ default:
+ return 0;
+ }
+
+repeated:
+ /* We permit max one item per AuthenticatedAttribute and no repeats */
+ pr_warn("Repeated/multivalue AuthAttrs not permitted\n");
+ return -EKEYREJECTED;
+}
+
+/*
+ * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3]
+ */
+int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+ struct pkcs7_signed_info *sinfo = ctx->sinfo;
+
+ if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||
+ !test_bit(sinfo_has_message_digest, &sinfo->aa_set)) {
+ pr_warn("Missing required AuthAttr\n");
+ return -EBADMSG;
+ }
+
+ if (ctx->msg->data_type != OID_msIndirectData &&
+ test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) {
+ pr_warn("Unexpected Authenticode AuthAttr\n");
+ return -EBADMSG;
+ }
+
+ /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
+ sinfo->authattrs = value - (hdrlen - 1);
+ sinfo->authattrs_len = vlen + (hdrlen - 1);
+ return 0;
+}
+
+/*
+ * Note the issuing certificate serial number
+ */
+int pkcs7_sig_note_serial(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+ ctx->raw_serial = value;
+ ctx->raw_serial_size = vlen;
+ return 0;
+}
+
+/*
+ * Note the issuer's name
+ */
+int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+ ctx->raw_issuer = value;
+ ctx->raw_issuer_size = vlen;
+ return 0;
+}
+
+/*
+ * Note the issuing cert's subjectKeyIdentifier
+ */
+int pkcs7_sig_note_skid(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
+
+ ctx->raw_skid = value;
+ ctx->raw_skid_size = vlen;
+ return 0;
+}
+
+/*
+ * Note the signature data
+ */
+int pkcs7_sig_note_signature(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ ctx->sinfo->sig->s = kmemdup(value, vlen, GFP_KERNEL);
+ if (!ctx->sinfo->sig->s)
+ return -ENOMEM;
+
+ ctx->sinfo->sig->s_size = vlen;
+ return 0;
+}
+
+/*
+ * Note a signature information block
+ */
+int pkcs7_note_signed_info(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+ struct pkcs7_signed_info *sinfo = ctx->sinfo;
+ struct asymmetric_key_id *kid;
+
+ if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) {
+ pr_warn("Authenticode requires AuthAttrs\n");
+ return -EBADMSG;
+ }
+
+ /* Generate cert issuer + serial number key ID */
+ if (!ctx->expect_skid) {
+ kid = asymmetric_key_generate_id(ctx->raw_serial,
+ ctx->raw_serial_size,
+ ctx->raw_issuer,
+ ctx->raw_issuer_size);
+ } else {
+ kid = asymmetric_key_generate_id(ctx->raw_skid,
+ ctx->raw_skid_size,
+ "", 0);
+ }
+ if (IS_ERR(kid))
+ return PTR_ERR(kid);
+
+ pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
+
+ sinfo->sig->auth_ids[0] = kid;
+ sinfo->index = ++ctx->sinfo_index;
+ *ctx->ppsinfo = sinfo;
+ ctx->ppsinfo = &sinfo->next;
+ ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
+ if (!ctx->sinfo)
+ return -ENOMEM;
+ ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
+ GFP_KERNEL);
+ if (!ctx->sinfo->sig)
+ return -ENOMEM;
+ return 0;
+}
diff --git a/lib/crypto/pkcs7_parser.h b/lib/crypto/pkcs7_parser.h
new file mode 100644
index 0000000000..6565fdc2d4
--- /dev/null
+++ b/lib/crypto/pkcs7_parser.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* PKCS#7 crypto data parser internal definitions
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#include <linux/oid_registry.h>
+#include <crypto/pkcs7.h>
+#include "x509_parser.h"
+
+#define kenter(FMT, ...) \
+ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
+#define kleave(FMT, ...) \
+ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
+
+struct pkcs7_signed_info {
+ struct pkcs7_signed_info *next;
+ struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
+ unsigned index;
+ bool unsupported_crypto; /* T if not usable due to missing crypto */
+ bool blacklisted;
+
+ /* Message digest - the digest of the Content Data (or NULL) */
+ const void *msgdigest;
+ unsigned msgdigest_len;
+
+ /* Authenticated Attribute data (or NULL) */
+ unsigned authattrs_len;
+ const void *authattrs;
+ unsigned long aa_set;
+#define sinfo_has_content_type 0
+#define sinfo_has_signing_time 1
+#define sinfo_has_message_digest 2
+#define sinfo_has_smime_caps 3
+#define sinfo_has_ms_opus_info 4
+#define sinfo_has_ms_statement_type 5
+ time64_t signing_time;
+
+ /* Message signature.
+ *
+ * This contains the generated digest of _either_ the Content Data or
+ * the Authenticated Attributes [RFC2315 9.3]. If the latter, one of
+ * the attributes contains the digest of the the Content Data within
+ * it.
+ *
+ * THis also contains the issuing cert serial number and issuer's name
+ * [PKCS#7 or CMS ver 1] or issuing cert's SKID [CMS ver 3].
+ */
+ struct public_key_signature *sig;
+};
+
+struct pkcs7_message {
+ struct x509_certificate *certs; /* Certificate list */
+ struct x509_certificate *crl; /* Revocation list */
+ struct pkcs7_signed_info *signed_infos;
+ u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */
+ bool have_authattrs; /* T if have authattrs */
+
+ /* Content Data (or NULL) */
+ enum OID data_type; /* Type of Data */
+ size_t data_len; /* Length of Data */
+ size_t data_hdrlen; /* Length of Data ASN.1 header */
+ const void *data; /* Content Data (or 0) */
+};
diff --git a/lib/crypto/public_key.c b/lib/crypto/public_key.c
new file mode 100644
index 0000000000..634377472f
--- /dev/null
+++ b/lib/crypto/public_key.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* In-software asymmetric public-key crypto subtype
+ *
+ * See Documentation/crypto/asymmetric-keys.txt
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#define pr_fmt(fmt) "PKEY: "fmt
+#ifdef __UBOOT__
+#include <linux/compat.h>
+#else
+#include <linux/module.h>
+#include <linux/export.h>
+#endif
+#include <linux/kernel.h>
+#ifndef __UBOOT__
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/scatterlist.h>
+#include <keys/asymmetric-subtype.h>
+#endif
+#include <crypto/public_key.h>
+#ifndef __UBOOT__
+#include <crypto/akcipher.h>
+#endif
+
+MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+#ifndef __UBOOT__
+/*
+ * Provide a part of a description of the key for /proc/keys.
+ */
+static void public_key_describe(const struct key *asymmetric_key,
+ struct seq_file *m)
+{
+ struct public_key *key = asymmetric_key->payload.data[asym_crypto];
+
+ if (key)
+ seq_printf(m, "%s.%s", key->id_type, key->pkey_algo);
+}
+#endif
+
+/*
+ * Destroy a public key algorithm key.
+ */
+void public_key_free(struct public_key *key)
+{
+ if (key) {
+ kfree(key->key);
+ kfree(key->params);
+ kfree(key);
+ }
+}
+EXPORT_SYMBOL_GPL(public_key_free);
+
+#ifdef __UBOOT__
+/*
+ * from <linux>/crypto/asymmetric_keys/signature.c
+ *
+ * Destroy a public key signature.
+ */
+void public_key_signature_free(struct public_key_signature *sig)
+{
+ int i;
+
+ if (sig) {
+ for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
+ free(sig->auth_ids[i]);
+ free(sig->s);
+ free(sig->digest);
+ free(sig);
+ }
+}
+EXPORT_SYMBOL_GPL(public_key_signature_free);
+
+#else
+/*
+ * Destroy a public key algorithm key.
+ */
+static void public_key_destroy(void *payload0, void *payload3)
+{
+ public_key_free(payload0);
+ public_key_signature_free(payload3);
+}
+
+/*
+ * Determine the crypto algorithm name.
+ */
+static
+int software_key_determine_akcipher(const char *encoding,
+ const char *hash_algo,
+ const struct public_key *pkey,
+ char alg_name[CRYPTO_MAX_ALG_NAME])
+{
+ int n;
+
+ if (strcmp(encoding, "pkcs1") == 0) {
+ /* The data wangled by the RSA algorithm is typically padded
+ * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
+ * sec 8.2].
+ */
+ if (!hash_algo)
+ n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
+ "pkcs1pad(%s)",
+ pkey->pkey_algo);
+ else
+ n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
+ "pkcs1pad(%s,%s)",
+ pkey->pkey_algo, hash_algo);
+ return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
+ }
+
+ if (strcmp(encoding, "raw") == 0) {
+ strcpy(alg_name, pkey->pkey_algo);
+ return 0;
+ }
+
+ return -ENOPKG;
+}
+
+static u8 *pkey_pack_u32(u8 *dst, u32 val)
+{
+ memcpy(dst, &val, sizeof(val));
+ return dst + sizeof(val);
+}
+
+/*
+ * Query information about a key.
+ */
+static int software_key_query(const struct kernel_pkey_params *params,
+ struct kernel_pkey_query *info)
+{
+ struct crypto_akcipher *tfm;
+ struct public_key *pkey = params->key->payload.data[asym_crypto];
+ char alg_name[CRYPTO_MAX_ALG_NAME];
+ u8 *key, *ptr;
+ int ret, len;
+
+ ret = software_key_determine_akcipher(params->encoding,
+ params->hash_algo,
+ pkey, alg_name);
+ if (ret < 0)
+ return ret;
+
+ tfm = crypto_alloc_akcipher(alg_name, 0, 0);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
+ GFP_KERNEL);
+ if (!key)
+ goto error_free_tfm;
+ memcpy(key, pkey->key, pkey->keylen);
+ ptr = key + pkey->keylen;
+ ptr = pkey_pack_u32(ptr, pkey->algo);
+ ptr = pkey_pack_u32(ptr, pkey->paramlen);
+ memcpy(ptr, pkey->params, pkey->paramlen);
+
+ if (pkey->key_is_private)
+ ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
+ else
+ ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
+ if (ret < 0)
+ goto error_free_key;
+
+ len = crypto_akcipher_maxsize(tfm);
+ info->key_size = len * 8;
+ info->max_data_size = len;
+ info->max_sig_size = len;
+ info->max_enc_size = len;
+ info->max_dec_size = len;
+ info->supported_ops = (KEYCTL_SUPPORTS_ENCRYPT |
+ KEYCTL_SUPPORTS_VERIFY);
+ if (pkey->key_is_private)
+ info->supported_ops |= (KEYCTL_SUPPORTS_DECRYPT |
+ KEYCTL_SUPPORTS_SIGN);
+ ret = 0;
+
+error_free_key:
+ kfree(key);
+error_free_tfm:
+ crypto_free_akcipher(tfm);
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+}
+
+/*
+ * Do encryption, decryption and signing ops.
+ */
+static int software_key_eds_op(struct kernel_pkey_params *params,
+ const void *in, void *out)
+{
+ const struct public_key *pkey = params->key->payload.data[asym_crypto];
+ struct akcipher_request *req;
+ struct crypto_akcipher *tfm;
+ struct crypto_wait cwait;
+ struct scatterlist in_sg, out_sg;
+ char alg_name[CRYPTO_MAX_ALG_NAME];
+ char *key, *ptr;
+ int ret;
+
+ pr_devel("==>%s()\n", __func__);
+
+ ret = software_key_determine_akcipher(params->encoding,
+ params->hash_algo,
+ pkey, alg_name);
+ if (ret < 0)
+ return ret;
+
+ tfm = crypto_alloc_akcipher(alg_name, 0, 0);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ req = akcipher_request_alloc(tfm, GFP_KERNEL);
+ if (!req)
+ goto error_free_tfm;
+
+ key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
+ GFP_KERNEL);
+ if (!key)
+ goto error_free_req;
+
+ memcpy(key, pkey->key, pkey->keylen);
+ ptr = key + pkey->keylen;
+ ptr = pkey_pack_u32(ptr, pkey->algo);
+ ptr = pkey_pack_u32(ptr, pkey->paramlen);
+ memcpy(ptr, pkey->params, pkey->paramlen);
+
+ if (pkey->key_is_private)
+ ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
+ else
+ ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
+ if (ret)
+ goto error_free_key;
+
+ sg_init_one(&in_sg, in, params->in_len);
+ sg_init_one(&out_sg, out, params->out_len);
+ akcipher_request_set_crypt(req, &in_sg, &out_sg, params->in_len,
+ params->out_len);
+ crypto_init_wait(&cwait);
+ akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP,
+ crypto_req_done, &cwait);
+
+ /* Perform the encryption calculation. */
+ switch (params->op) {
+ case kernel_pkey_encrypt:
+ ret = crypto_akcipher_encrypt(req);
+ break;
+ case kernel_pkey_decrypt:
+ ret = crypto_akcipher_decrypt(req);
+ break;
+ case kernel_pkey_sign:
+ ret = crypto_akcipher_sign(req);
+ break;
+ default:
+ BUG();
+ }
+
+ ret = crypto_wait_req(ret, &cwait);
+ if (ret == 0)
+ ret = req->dst_len;
+
+error_free_key:
+ kfree(key);
+error_free_req:
+ akcipher_request_free(req);
+error_free_tfm:
+ crypto_free_akcipher(tfm);
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+}
+
+/*
+ * Verify a signature using a public key.
+ */
+int public_key_verify_signature(const struct public_key *pkey,
+ const struct public_key_signature *sig)
+{
+ struct crypto_wait cwait;
+ struct crypto_akcipher *tfm;
+ struct akcipher_request *req;
+ struct scatterlist src_sg[2];
+ char alg_name[CRYPTO_MAX_ALG_NAME];
+ char *key, *ptr;
+ int ret;
+
+ pr_devel("==>%s()\n", __func__);
+
+ BUG_ON(!pkey);
+ BUG_ON(!sig);
+ BUG_ON(!sig->s);
+
+ ret = software_key_determine_akcipher(sig->encoding,
+ sig->hash_algo,
+ pkey, alg_name);
+ if (ret < 0)
+ return ret;
+
+ tfm = crypto_alloc_akcipher(alg_name, 0, 0);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ ret = -ENOMEM;
+ req = akcipher_request_alloc(tfm, GFP_KERNEL);
+ if (!req)
+ goto error_free_tfm;
+
+ key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
+ GFP_KERNEL);
+ if (!key)
+ goto error_free_req;
+
+ memcpy(key, pkey->key, pkey->keylen);
+ ptr = key + pkey->keylen;
+ ptr = pkey_pack_u32(ptr, pkey->algo);
+ ptr = pkey_pack_u32(ptr, pkey->paramlen);
+ memcpy(ptr, pkey->params, pkey->paramlen);
+
+ if (pkey->key_is_private)
+ ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
+ else
+ ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
+ if (ret)
+ goto error_free_key;
+
+ sg_init_table(src_sg, 2);
+ sg_set_buf(&src_sg[0], sig->s, sig->s_size);
+ sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
+ akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
+ sig->digest_size);
+ crypto_init_wait(&cwait);
+ akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP,
+ crypto_req_done, &cwait);
+ ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
+
+error_free_key:
+ kfree(key);
+error_free_req:
+ akcipher_request_free(req);
+error_free_tfm:
+ crypto_free_akcipher(tfm);
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ if (WARN_ON_ONCE(ret > 0))
+ ret = -EINVAL;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(public_key_verify_signature);
+
+static int public_key_verify_signature_2(const struct key *key,
+ const struct public_key_signature *sig)
+{
+ const struct public_key *pk = key->payload.data[asym_crypto];
+ return public_key_verify_signature(pk, sig);
+}
+
+/*
+ * Public key algorithm asymmetric key subtype
+ */
+struct asymmetric_key_subtype public_key_subtype = {
+ .owner = THIS_MODULE,
+ .name = "public_key",
+ .name_len = sizeof("public_key") - 1,
+ .describe = public_key_describe,
+ .destroy = public_key_destroy,
+ .query = software_key_query,
+ .eds_op = software_key_eds_op,
+ .verify_signature = public_key_verify_signature_2,
+};
+EXPORT_SYMBOL_GPL(public_key_subtype);
+#endif /* !__UBOOT__ */
diff --git a/lib/crypto/rsa_helper.c b/lib/crypto/rsa_helper.c
new file mode 100644
index 0000000000..aca627a4a6
--- /dev/null
+++ b/lib/crypto/rsa_helper.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * RSA key extract helper
+ *
+ * Copyright (c) 2015, Intel Corporation
+ * Authors: Tadeusz Struk <tadeusz.struk@intel.com>
+ */
+#ifndef __UBOOT__
+#include <linux/kernel.h>
+#include <linux/export.h>
+#endif
+#include <linux/err.h>
+#ifndef __UBOOT__
+#include <linux/fips.h>
+#endif
+#include <crypto/internal/rsa.h>
+#include "rsapubkey.asn1.h"
+#ifndef __UBOOT__
+#include "rsaprivkey.asn1.h"
+#endif
+
+int rsa_get_n(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+#ifndef __UBOOT__
+ const u8 *ptr = value;
+ size_t n_sz = vlen;
+#endif
+
+ /* invalid key provided */
+ if (!value || !vlen)
+ return -EINVAL;
+
+#ifndef __UBOOT__
+ if (fips_enabled) {
+ while (n_sz && !*ptr) {
+ ptr++;
+ n_sz--;
+ }
+
+ /* In FIPS mode only allow key size 2K and higher */
+ if (n_sz < 256) {
+ pr_err("RSA: key size not allowed in FIPS mode\n");
+ return -EINVAL;
+ }
+ }
+#endif
+
+ key->n = value;
+ key->n_sz = vlen;
+
+ return 0;
+}
+
+int rsa_get_e(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+
+ /* invalid key provided */
+ if (!value || !key->n_sz || !vlen || vlen > key->n_sz)
+ return -EINVAL;
+
+ key->e = value;
+ key->e_sz = vlen;
+
+ return 0;
+}
+
+int rsa_get_d(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+
+ /* invalid key provided */
+ if (!value || !key->n_sz || !vlen || vlen > key->n_sz)
+ return -EINVAL;
+
+ key->d = value;
+ key->d_sz = vlen;
+
+ return 0;
+}
+
+int rsa_get_p(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+
+ /* invalid key provided */
+ if (!value || !vlen || vlen > key->n_sz)
+ return -EINVAL;
+
+ key->p = value;
+ key->p_sz = vlen;
+
+ return 0;
+}
+
+int rsa_get_q(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+
+ /* invalid key provided */
+ if (!value || !vlen || vlen > key->n_sz)
+ return -EINVAL;
+
+ key->q = value;
+ key->q_sz = vlen;
+
+ return 0;
+}
+
+int rsa_get_dp(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+
+ /* invalid key provided */
+ if (!value || !vlen || vlen > key->n_sz)
+ return -EINVAL;
+
+ key->dp = value;
+ key->dp_sz = vlen;
+
+ return 0;
+}
+
+int rsa_get_dq(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+
+ /* invalid key provided */
+ if (!value || !vlen || vlen > key->n_sz)
+ return -EINVAL;
+
+ key->dq = value;
+ key->dq_sz = vlen;
+
+ return 0;
+}
+
+int rsa_get_qinv(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+
+ /* invalid key provided */
+ if (!value || !vlen || vlen > key->n_sz)
+ return -EINVAL;
+
+ key->qinv = value;
+ key->qinv_sz = vlen;
+
+ return 0;
+}
+
+/**
+ * rsa_parse_pub_key() - decodes the BER encoded buffer and stores in the
+ * provided struct rsa_key, pointers to the raw key as is,
+ * so that the caller can copy it or MPI parse it, etc.
+ *
+ * @rsa_key: struct rsa_key key representation
+ * @key: key in BER format
+ * @key_len: length of key
+ *
+ * Return: 0 on success or error code in case of error
+ */
+int rsa_parse_pub_key(struct rsa_key *rsa_key, const void *key,
+ unsigned int key_len)
+{
+ return asn1_ber_decoder(&rsapubkey_decoder, rsa_key, key, key_len);
+}
+EXPORT_SYMBOL_GPL(rsa_parse_pub_key);
+
+#ifndef __UBOOT__
+/**
+ * rsa_parse_priv_key() - decodes the BER encoded buffer and stores in the
+ * provided struct rsa_key, pointers to the raw key
+ * as is, so that the caller can copy it or MPI parse it,
+ * etc.
+ *
+ * @rsa_key: struct rsa_key key representation
+ * @key: key in BER format
+ * @key_len: length of key
+ *
+ * Return: 0 on success or error code in case of error
+ */
+int rsa_parse_priv_key(struct rsa_key *rsa_key, const void *key,
+ unsigned int key_len)
+{
+ return asn1_ber_decoder(&rsaprivkey_decoder, rsa_key, key, key_len);
+}
+EXPORT_SYMBOL_GPL(rsa_parse_priv_key);
+#endif
diff --git a/lib/crypto/rsapubkey.asn1 b/lib/crypto/rsapubkey.asn1
new file mode 100644
index 0000000000..725498e461
--- /dev/null
+++ b/lib/crypto/rsapubkey.asn1
@@ -0,0 +1,4 @@
+RsaPubKey ::= SEQUENCE {
+ n INTEGER ({ rsa_get_n }),
+ e INTEGER ({ rsa_get_e })
+}
diff --git a/lib/crypto/x509.asn1 b/lib/crypto/x509.asn1
new file mode 100644
index 0000000000..5c9f4e4a52
--- /dev/null
+++ b/lib/crypto/x509.asn1
@@ -0,0 +1,60 @@
+Certificate ::= SEQUENCE {
+ tbsCertificate TBSCertificate ({ x509_note_tbs_certificate }),
+ signatureAlgorithm AlgorithmIdentifier,
+ signature BIT STRING ({ x509_note_signature })
+ }
+
+TBSCertificate ::= SEQUENCE {
+ version [ 0 ] Version DEFAULT,
+ serialNumber CertificateSerialNumber ({ x509_note_serial }),
+ signature AlgorithmIdentifier ({ x509_note_pkey_algo }),
+ issuer Name ({ x509_note_issuer }),
+ validity Validity,
+ subject Name ({ x509_note_subject }),
+ subjectPublicKeyInfo SubjectPublicKeyInfo,
+ issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ extensions [ 3 ] Extensions OPTIONAL
+ }
+
+Version ::= INTEGER
+CertificateSerialNumber ::= INTEGER
+
+AlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER ({ x509_note_OID }),
+ parameters ANY OPTIONAL ({ x509_note_params })
+}
+
+Name ::= SEQUENCE OF RelativeDistinguishedName
+
+RelativeDistinguishedName ::= SET OF AttributeValueAssertion
+
+AttributeValueAssertion ::= SEQUENCE {
+ attributeType OBJECT IDENTIFIER ({ x509_note_OID }),
+ attributeValue ANY ({ x509_extract_name_segment })
+ }
+
+Validity ::= SEQUENCE {
+ notBefore Time ({ x509_note_not_before }),
+ notAfter Time ({ x509_note_not_after })
+ }
+
+Time ::= CHOICE {
+ utcTime UTCTime,
+ generalTime GeneralizedTime
+ }
+
+SubjectPublicKeyInfo ::= SEQUENCE {
+ algorithm AlgorithmIdentifier,
+ subjectPublicKey BIT STRING ({ x509_extract_key_data })
+ }
+
+UniqueIdentifier ::= BIT STRING
+
+Extensions ::= SEQUENCE OF Extension
+
+Extension ::= SEQUENCE {
+ extnid OBJECT IDENTIFIER ({ x509_note_OID }),
+ critical BOOLEAN DEFAULT,
+ extnValue OCTET STRING ({ x509_process_extension })
+ }
diff --git a/lib/crypto/x509_akid.asn1 b/lib/crypto/x509_akid.asn1
new file mode 100644
index 0000000000..1a33231a75
--- /dev/null
+++ b/lib/crypto/x509_akid.asn1
@@ -0,0 +1,35 @@
+-- X.509 AuthorityKeyIdentifier
+-- rfc5280 section 4.2.1.1
+
+AuthorityKeyIdentifier ::= SEQUENCE {
+ keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL,
+ authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL,
+ authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL
+ }
+
+KeyIdentifier ::= OCTET STRING ({ x509_akid_note_kid })
+
+CertificateSerialNumber ::= INTEGER ({ x509_akid_note_serial })
+
+GeneralNames ::= SEQUENCE OF GeneralName
+
+GeneralName ::= CHOICE {
+ otherName [0] ANY,
+ rfc822Name [1] IA5String,
+ dNSName [2] IA5String,
+ x400Address [3] ANY,
+ directoryName [4] Name ({ x509_akid_note_name }),
+ ediPartyName [5] ANY,
+ uniformResourceIdentifier [6] IA5String,
+ iPAddress [7] OCTET STRING,
+ registeredID [8] OBJECT IDENTIFIER
+ }
+
+Name ::= SEQUENCE OF RelativeDistinguishedName
+
+RelativeDistinguishedName ::= SET OF AttributeValueAssertion
+
+AttributeValueAssertion ::= SEQUENCE {
+ attributeType OBJECT IDENTIFIER ({ x509_note_OID }),
+ attributeValue ANY ({ x509_extract_name_segment })
+ }
diff --git a/lib/crypto/x509_cert_parser.c b/lib/crypto/x509_cert_parser.c
new file mode 100644
index 0000000000..e6d2a426a0
--- /dev/null
+++ b/lib/crypto/x509_cert_parser.c
@@ -0,0 +1,697 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* X.509 certificate parser
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#define pr_fmt(fmt) "X.509: "fmt
+#include <linux/kernel.h>
+#ifndef __UBOOT__
+#include <linux/export.h>
+#include <linux/slab.h>
+#endif
+#include <linux/err.h>
+#include <linux/oid_registry.h>
+#ifdef __UBOOT__
+#include <linux/string.h>
+#endif
+#include <crypto/public_key.h>
+#include "x509_parser.h"
+#include "x509.asn1.h"
+#include "x509_akid.asn1.h"
+
+struct x509_parse_context {
+ struct x509_certificate *cert; /* Certificate being constructed */
+ unsigned long data; /* Start of data */
+ const void *cert_start; /* Start of cert content */
+ const void *key; /* Key data */
+ size_t key_size; /* Size of key data */
+ const void *params; /* Key parameters */
+ size_t params_size; /* Size of key parameters */
+ enum OID key_algo; /* Public key algorithm */
+ enum OID last_oid; /* Last OID encountered */
+ enum OID algo_oid; /* Algorithm OID */
+ unsigned char nr_mpi; /* Number of MPIs stored */
+ u8 o_size; /* Size of organizationName (O) */
+ u8 cn_size; /* Size of commonName (CN) */
+ u8 email_size; /* Size of emailAddress */
+ u16 o_offset; /* Offset of organizationName (O) */
+ u16 cn_offset; /* Offset of commonName (CN) */
+ u16 email_offset; /* Offset of emailAddress */
+ unsigned raw_akid_size;
+ const void *raw_akid; /* Raw authorityKeyId in ASN.1 */
+ const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */
+ unsigned akid_raw_issuer_size;
+};
+
+/*
+ * Free an X.509 certificate
+ */
+void x509_free_certificate(struct x509_certificate *cert)
+{
+ if (cert) {
+ public_key_free(cert->pub);
+ public_key_signature_free(cert->sig);
+ kfree(cert->issuer);
+ kfree(cert->subject);
+ kfree(cert->id);
+ kfree(cert->skid);
+ kfree(cert);
+ }
+}
+EXPORT_SYMBOL_GPL(x509_free_certificate);
+
+/*
+ * Parse an X.509 certificate
+ */
+struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
+{
+ struct x509_certificate *cert;
+ struct x509_parse_context *ctx;
+ struct asymmetric_key_id *kid;
+ long ret;
+
+ ret = -ENOMEM;
+ cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
+ if (!cert)
+ goto error_no_cert;
+ cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
+ if (!cert->pub)
+ goto error_no_ctx;
+ cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
+ if (!cert->sig)
+ goto error_no_ctx;
+ ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
+ if (!ctx)
+ goto error_no_ctx;
+
+ ctx->cert = cert;
+ ctx->data = (unsigned long)data;
+
+ /* Attempt to decode the certificate */
+ ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen);
+ if (ret < 0)
+ goto error_decode;
+
+ /* Decode the AuthorityKeyIdentifier */
+ if (ctx->raw_akid) {
+ pr_devel("AKID: %u %*phN\n",
+ ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid);
+ ret = asn1_ber_decoder(&x509_akid_decoder, ctx,
+ ctx->raw_akid, ctx->raw_akid_size);
+ if (ret < 0) {
+ pr_warn("Couldn't decode AuthKeyIdentifier\n");
+ goto error_decode;
+ }
+ }
+
+ ret = -ENOMEM;
+ cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
+ if (!cert->pub->key)
+ goto error_decode;
+
+ cert->pub->keylen = ctx->key_size;
+
+ cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL);
+ if (!cert->pub->params)
+ goto error_decode;
+
+ cert->pub->paramlen = ctx->params_size;
+ cert->pub->algo = ctx->key_algo;
+
+ /* Grab the signature bits */
+ ret = x509_get_sig_params(cert);
+ if (ret < 0)
+ goto error_decode;
+
+ /* Generate cert issuer + serial number key ID */
+ kid = asymmetric_key_generate_id(cert->raw_serial,
+ cert->raw_serial_size,
+ cert->raw_issuer,
+ cert->raw_issuer_size);
+ if (IS_ERR(kid)) {
+ ret = PTR_ERR(kid);
+ goto error_decode;
+ }
+ cert->id = kid;
+
+#ifndef __UBOOT__
+ /* Detect self-signed certificates */
+ ret = x509_check_for_self_signed(cert);
+ if (ret < 0)
+ goto error_decode;
+#endif
+
+ kfree(ctx);
+ return cert;
+
+error_decode:
+ kfree(ctx);
+error_no_ctx:
+ x509_free_certificate(cert);
+error_no_cert:
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(x509_cert_parse);
+
+/*
+ * Note an OID when we find one for later processing when we know how
+ * to interpret it.
+ */
+int x509_note_OID(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+
+ ctx->last_oid = look_up_OID(value, vlen);
+ if (ctx->last_oid == OID__NR) {
+ char buffer[50];
+ sprint_oid(value, vlen, buffer, sizeof(buffer));
+ pr_debug("Unknown OID: [%lu] %s\n",
+ (unsigned long)value - ctx->data, buffer);
+ }
+ return 0;
+}
+
+/*
+ * Save the position of the TBS data so that we can check the signature over it
+ * later.
+ */
+int x509_note_tbs_certificate(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+
+ pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n",
+ hdrlen, tag, (unsigned long)value - ctx->data, vlen);
+
+ ctx->cert->tbs = value - hdrlen;
+ ctx->cert->tbs_size = vlen + hdrlen;
+ return 0;
+}
+
+/*
+ * Record the public key algorithm
+ */
+int x509_note_pkey_algo(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+
+ pr_debug("PubKey Algo: %u\n", ctx->last_oid);
+
+ switch (ctx->last_oid) {
+ case OID_md2WithRSAEncryption:
+ case OID_md3WithRSAEncryption:
+ default:
+ return -ENOPKG; /* Unsupported combination */
+
+ case OID_md4WithRSAEncryption:
+ ctx->cert->sig->hash_algo = "md4";
+ goto rsa_pkcs1;
+
+ case OID_sha1WithRSAEncryption:
+ ctx->cert->sig->hash_algo = "sha1";
+ goto rsa_pkcs1;
+
+ case OID_sha256WithRSAEncryption:
+ ctx->cert->sig->hash_algo = "sha256";
+ goto rsa_pkcs1;
+
+ case OID_sha384WithRSAEncryption:
+ ctx->cert->sig->hash_algo = "sha384";
+ goto rsa_pkcs1;
+
+ case OID_sha512WithRSAEncryption:
+ ctx->cert->sig->hash_algo = "sha512";
+ goto rsa_pkcs1;
+
+ case OID_sha224WithRSAEncryption:
+ ctx->cert->sig->hash_algo = "sha224";
+ goto rsa_pkcs1;
+
+ case OID_gost2012Signature256:
+ ctx->cert->sig->hash_algo = "streebog256";
+ goto ecrdsa;
+
+ case OID_gost2012Signature512:
+ ctx->cert->sig->hash_algo = "streebog512";
+ goto ecrdsa;
+ }
+
+rsa_pkcs1:
+ ctx->cert->sig->pkey_algo = "rsa";
+ ctx->cert->sig->encoding = "pkcs1";
+ ctx->algo_oid = ctx->last_oid;
+ return 0;
+ecrdsa:
+ ctx->cert->sig->pkey_algo = "ecrdsa";
+ ctx->cert->sig->encoding = "raw";
+ ctx->algo_oid = ctx->last_oid;
+ return 0;
+}
+
+/*
+ * Note the whereabouts and type of the signature.
+ */
+int x509_note_signature(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+
+ pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen);
+
+ if (ctx->last_oid != ctx->algo_oid) {
+ pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n",
+ ctx->algo_oid, ctx->last_oid);
+ return -EINVAL;
+ }
+
+ if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 ||
+ strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0) {
+ /* Discard the BIT STRING metadata */
+ if (vlen < 1 || *(const u8 *)value != 0)
+ return -EBADMSG;
+
+ value++;
+ vlen--;
+ }
+
+ ctx->cert->raw_sig = value;
+ ctx->cert->raw_sig_size = vlen;
+ return 0;
+}
+
+/*
+ * Note the certificate serial number
+ */
+int x509_note_serial(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ ctx->cert->raw_serial = value;
+ ctx->cert->raw_serial_size = vlen;
+ return 0;
+}
+
+/*
+ * Note some of the name segments from which we'll fabricate a name.
+ */
+int x509_extract_name_segment(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+
+ switch (ctx->last_oid) {
+ case OID_commonName:
+ ctx->cn_size = vlen;
+ ctx->cn_offset = (unsigned long)value - ctx->data;
+ break;
+ case OID_organizationName:
+ ctx->o_size = vlen;
+ ctx->o_offset = (unsigned long)value - ctx->data;
+ break;
+ case OID_email_address:
+ ctx->email_size = vlen;
+ ctx->email_offset = (unsigned long)value - ctx->data;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Fabricate and save the issuer and subject names
+ */
+static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen,
+ unsigned char tag,
+ char **_name, size_t vlen)
+{
+ const void *name, *data = (const void *)ctx->data;
+ size_t namesize;
+ char *buffer;
+
+ if (*_name)
+ return -EINVAL;
+
+ /* Empty name string if no material */
+ if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) {
+ buffer = kmalloc(1, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ buffer[0] = 0;
+ goto done;
+ }
+
+ if (ctx->cn_size && ctx->o_size) {
+ /* Consider combining O and CN, but use only the CN if it is
+ * prefixed by the O, or a significant portion thereof.
+ */
+ namesize = ctx->cn_size;
+ name = data + ctx->cn_offset;
+ if (ctx->cn_size >= ctx->o_size &&
+ memcmp(data + ctx->cn_offset, data + ctx->o_offset,
+ ctx->o_size) == 0)
+ goto single_component;
+ if (ctx->cn_size >= 7 &&
+ ctx->o_size >= 7 &&
+ memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0)
+ goto single_component;
+
+ buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1,
+ GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ memcpy(buffer,
+ data + ctx->o_offset, ctx->o_size);
+ buffer[ctx->o_size + 0] = ':';
+ buffer[ctx->o_size + 1] = ' ';
+ memcpy(buffer + ctx->o_size + 2,
+ data + ctx->cn_offset, ctx->cn_size);
+ buffer[ctx->o_size + 2 + ctx->cn_size] = 0;
+ goto done;
+
+ } else if (ctx->cn_size) {
+ namesize = ctx->cn_size;
+ name = data + ctx->cn_offset;
+ } else if (ctx->o_size) {
+ namesize = ctx->o_size;
+ name = data + ctx->o_offset;
+ } else {
+ namesize = ctx->email_size;
+ name = data + ctx->email_offset;
+ }
+
+single_component:
+ buffer = kmalloc(namesize + 1, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ memcpy(buffer, name, namesize);
+ buffer[namesize] = 0;
+
+done:
+ *_name = buffer;
+ ctx->cn_size = 0;
+ ctx->o_size = 0;
+ ctx->email_size = 0;
+ return 0;
+}
+
+int x509_note_issuer(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ ctx->cert->raw_issuer = value;
+ ctx->cert->raw_issuer_size = vlen;
+ return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
+}
+
+int x509_note_subject(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ ctx->cert->raw_subject = value;
+ ctx->cert->raw_subject_size = vlen;
+ return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
+}
+
+/*
+ * Extract the parameters for the public key
+ */
+int x509_note_params(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+
+ /*
+ * AlgorithmIdentifier is used three times in the x509, we should skip
+ * first and ignore third, using second one which is after subject and
+ * before subjectPublicKey.
+ */
+ if (!ctx->cert->raw_subject || ctx->key)
+ return 0;
+ ctx->params = value - hdrlen;
+ ctx->params_size = vlen + hdrlen;
+ return 0;
+}
+
+/*
+ * Extract the data for the public key algorithm
+ */
+int x509_extract_key_data(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+
+ ctx->key_algo = ctx->last_oid;
+ if (ctx->last_oid == OID_rsaEncryption)
+ ctx->cert->pub->pkey_algo = "rsa";
+ else if (ctx->last_oid == OID_gost2012PKey256 ||
+ ctx->last_oid == OID_gost2012PKey512)
+ ctx->cert->pub->pkey_algo = "ecrdsa";
+ else
+ return -ENOPKG;
+
+ /* Discard the BIT STRING metadata */
+ if (vlen < 1 || *(const u8 *)value != 0)
+ return -EBADMSG;
+ ctx->key = value + 1;
+ ctx->key_size = vlen - 1;
+ return 0;
+}
+
+/* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */
+#define SEQ_TAG_KEYID (ASN1_CONT << 6)
+
+/*
+ * Process certificate extensions that are used to qualify the certificate.
+ */
+int x509_process_extension(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ struct asymmetric_key_id *kid;
+ const unsigned char *v = value;
+
+ pr_debug("Extension: %u\n", ctx->last_oid);
+
+ if (ctx->last_oid == OID_subjectKeyIdentifier) {
+ /* Get hold of the key fingerprint */
+ if (ctx->cert->skid || vlen < 3)
+ return -EBADMSG;
+ if (v[0] != ASN1_OTS || v[1] != vlen - 2)
+ return -EBADMSG;
+ v += 2;
+ vlen -= 2;
+
+ ctx->cert->raw_skid_size = vlen;
+ ctx->cert->raw_skid = v;
+ kid = asymmetric_key_generate_id(v, vlen, "", 0);
+ if (IS_ERR(kid))
+ return PTR_ERR(kid);
+ ctx->cert->skid = kid;
+ pr_debug("subjkeyid %*phN\n", kid->len, kid->data);
+ return 0;
+ }
+
+ if (ctx->last_oid == OID_authorityKeyIdentifier) {
+ /* Get hold of the CA key fingerprint */
+ ctx->raw_akid = v;
+ ctx->raw_akid_size = vlen;
+ return 0;
+ }
+
+ return 0;
+}
+
+/**
+ * x509_decode_time - Decode an X.509 time ASN.1 object
+ * @_t: The time to fill in
+ * @hdrlen: The length of the object header
+ * @tag: The object tag
+ * @value: The object value
+ * @vlen: The size of the object value
+ *
+ * Decode an ASN.1 universal time or generalised time field into a struct the
+ * kernel can handle and check it for validity. The time is decoded thus:
+ *
+ * [RFC5280 §4.1.2.5]
+ * CAs conforming to this profile MUST always encode certificate validity
+ * dates through the year 2049 as UTCTime; certificate validity dates in
+ * 2050 or later MUST be encoded as GeneralizedTime. Conforming
+ * applications MUST be able to process validity dates that are encoded in
+ * either UTCTime or GeneralizedTime.
+ */
+int x509_decode_time(time64_t *_t, size_t hdrlen,
+ unsigned char tag,
+ const unsigned char *value, size_t vlen)
+{
+ static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31 };
+ const unsigned char *p = value;
+ unsigned year, mon, day, hour, min, sec, mon_len;
+
+#define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; })
+#define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; })
+
+ if (tag == ASN1_UNITIM) {
+ /* UTCTime: YYMMDDHHMMSSZ */
+ if (vlen != 13)
+ goto unsupported_time;
+ year = DD2bin(p);
+ if (year >= 50)
+ year += 1900;
+ else
+ year += 2000;
+ } else if (tag == ASN1_GENTIM) {
+ /* GenTime: YYYYMMDDHHMMSSZ */
+ if (vlen != 15)
+ goto unsupported_time;
+ year = DD2bin(p) * 100 + DD2bin(p);
+ if (year >= 1950 && year <= 2049)
+ goto invalid_time;
+ } else {
+ goto unsupported_time;
+ }
+
+ mon = DD2bin(p);
+ day = DD2bin(p);
+ hour = DD2bin(p);
+ min = DD2bin(p);
+ sec = DD2bin(p);
+
+ if (*p != 'Z')
+ goto unsupported_time;
+
+ if (year < 1970 ||
+ mon < 1 || mon > 12)
+ goto invalid_time;
+
+ mon_len = month_lengths[mon - 1];
+ if (mon == 2) {
+ if (year % 4 == 0) {
+ mon_len = 29;
+ if (year % 100 == 0) {
+ mon_len = 28;
+ if (year % 400 == 0)
+ mon_len = 29;
+ }
+ }
+ }
+
+ if (day < 1 || day > mon_len ||
+ hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */
+ min > 59 ||
+ sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */
+ goto invalid_time;
+
+ *_t = mktime64(year, mon, day, hour, min, sec);
+ return 0;
+
+unsupported_time:
+ pr_debug("Got unsupported time [tag %02x]: '%*phN'\n",
+ tag, (int)vlen, value);
+ return -EBADMSG;
+invalid_time:
+ pr_debug("Got invalid time [tag %02x]: '%*phN'\n",
+ tag, (int)vlen, value);
+ return -EBADMSG;
+}
+EXPORT_SYMBOL_GPL(x509_decode_time);
+
+int x509_note_not_before(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
+}
+
+int x509_note_not_after(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
+}
+
+/*
+ * Note a key identifier-based AuthorityKeyIdentifier
+ */
+int x509_akid_note_kid(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ struct asymmetric_key_id *kid;
+
+ pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
+
+ if (ctx->cert->sig->auth_ids[1])
+ return 0;
+
+ kid = asymmetric_key_generate_id(value, vlen, "", 0);
+ if (IS_ERR(kid))
+ return PTR_ERR(kid);
+ pr_debug("authkeyid %*phN\n", kid->len, kid->data);
+ ctx->cert->sig->auth_ids[1] = kid;
+ return 0;
+}
+
+/*
+ * Note a directoryName in an AuthorityKeyIdentifier
+ */
+int x509_akid_note_name(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+
+ pr_debug("AKID: name: %*phN\n", (int)vlen, value);
+
+ ctx->akid_raw_issuer = value;
+ ctx->akid_raw_issuer_size = vlen;
+ return 0;
+}
+
+/*
+ * Note a serial number in an AuthorityKeyIdentifier
+ */
+int x509_akid_note_serial(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ struct asymmetric_key_id *kid;
+
+ pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
+
+ if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
+ return 0;
+
+ kid = asymmetric_key_generate_id(value,
+ vlen,
+ ctx->akid_raw_issuer,
+ ctx->akid_raw_issuer_size);
+ if (IS_ERR(kid))
+ return PTR_ERR(kid);
+
+ pr_debug("authkeyid %*phN\n", kid->len, kid->data);
+ ctx->cert->sig->auth_ids[0] = kid;
+ return 0;
+}
diff --git a/lib/crypto/x509_parser.h b/lib/crypto/x509_parser.h
new file mode 100644
index 0000000000..c233f136fb
--- /dev/null
+++ b/lib/crypto/x509_parser.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* X.509 certificate parser internal definitions
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#include <linux/time.h>
+#include <crypto/public_key.h>
+#include <keys/asymmetric-type.h>
+
+struct x509_certificate {
+ struct x509_certificate *next;
+ struct x509_certificate *signer; /* Certificate that signed this one */
+ struct public_key *pub; /* Public key details */
+ struct public_key_signature *sig; /* Signature parameters */
+ char *issuer; /* Name of certificate issuer */
+ char *subject; /* Name of certificate subject */
+ struct asymmetric_key_id *id; /* Issuer + Serial number */
+ struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */
+ time64_t valid_from;
+ time64_t valid_to;
+ const void *tbs; /* Signed data */
+ unsigned tbs_size; /* Size of signed data */
+ unsigned raw_sig_size; /* Size of sigature */
+ const void *raw_sig; /* Signature data */
+ const void *raw_serial; /* Raw serial number in ASN.1 */
+ unsigned raw_serial_size;
+ unsigned raw_issuer_size;
+ const void *raw_issuer; /* Raw issuer name in ASN.1 */
+ const void *raw_subject; /* Raw subject name in ASN.1 */
+ unsigned raw_subject_size;
+ unsigned raw_skid_size;
+ const void *raw_skid; /* Raw subjectKeyId in ASN.1 */
+ unsigned index;
+ bool seen; /* Infinite recursion prevention */
+ bool verified;
+ bool self_signed; /* T if self-signed (check unsupported_sig too) */
+ bool unsupported_key; /* T if key uses unsupported crypto */
+ bool unsupported_sig; /* T if signature uses unsupported crypto */
+ bool blacklisted;
+};
+
+/*
+ * x509_cert_parser.c
+ */
+extern void x509_free_certificate(struct x509_certificate *cert);
+extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen);
+extern int x509_decode_time(time64_t *_t, size_t hdrlen,
+ unsigned char tag,
+ const unsigned char *value, size_t vlen);
+
+/*
+ * x509_public_key.c
+ */
+extern int x509_get_sig_params(struct x509_certificate *cert);
+extern int x509_check_for_self_signed(struct x509_certificate *cert);
diff --git a/lib/crypto/x509_public_key.c b/lib/crypto/x509_public_key.c
new file mode 100644
index 0000000000..04bdb672b4
--- /dev/null
+++ b/lib/crypto/x509_public_key.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Instantiate a public key crypto key from an X.509 Certificate
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#define pr_fmt(fmt) "X.509: "fmt
+#ifdef __UBOOT__
+#include <common.h>
+#include <linux/compat.h>
+#include <linux/errno.h>
+#else
+#include <linux/module.h>
+#endif
+#include <linux/kernel.h>
+#ifndef __UBOOT__
+#include <linux/slab.h>
+#include <keys/asymmetric-subtype.h>
+#include <keys/asymmetric-parser.h>
+#include <keys/system_keyring.h>
+#include <crypto/hash.h>
+#include "asymmetric_keys.h"
+#endif
+#include "x509_parser.h"
+
+/*
+ * Set up the signature parameters in an X.509 certificate. This involves
+ * digesting the signed data and extracting the signature.
+ */
+int x509_get_sig_params(struct x509_certificate *cert)
+{
+ struct public_key_signature *sig = cert->sig;
+#ifndef __UBOOT__
+ struct crypto_shash *tfm;
+ struct shash_desc *desc;
+ size_t desc_size;
+#endif
+ int ret;
+
+ pr_devel("==>%s()\n", __func__);
+
+ if (!cert->pub->pkey_algo)
+ cert->unsupported_key = true;
+
+ if (!sig->pkey_algo)
+ cert->unsupported_sig = true;
+
+ /* We check the hash if we can - even if we can't then verify it */
+ if (!sig->hash_algo) {
+ cert->unsupported_sig = true;
+ return 0;
+ }
+
+ sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
+ if (!sig->s)
+ return -ENOMEM;
+
+ sig->s_size = cert->raw_sig_size;
+
+#ifdef __UBOOT__
+ /*
+ * Note:
+ * This part (filling sig->digest) should be implemented if
+ * x509_check_for_self_signed() is enabled x509_cert_parse().
+ * Currently, this check won't affect UEFI secure boot.
+ */
+ ret = 0;
+#else
+ /* Allocate the hashing algorithm we're going to need and find out how
+ * big the hash operational data will be.
+ */
+ tfm = crypto_alloc_shash(sig->hash_algo, 0, 0);
+ if (IS_ERR(tfm)) {
+ if (PTR_ERR(tfm) == -ENOENT) {
+ cert->unsupported_sig = true;
+ return 0;
+ }
+ return PTR_ERR(tfm);
+ }
+
+ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+ sig->digest_size = crypto_shash_digestsize(tfm);
+
+ ret = -ENOMEM;
+ sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
+ if (!sig->digest)
+ goto error;
+
+ desc = kzalloc(desc_size, GFP_KERNEL);
+ if (!desc)
+ goto error;
+
+ desc->tfm = tfm;
+
+ ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, sig->digest);
+ if (ret < 0)
+ goto error_2;
+
+ ret = is_hash_blacklisted(sig->digest, sig->digest_size, "tbs");
+ if (ret == -EKEYREJECTED) {
+ pr_err("Cert %*phN is blacklisted\n",
+ sig->digest_size, sig->digest);
+ cert->blacklisted = true;
+ ret = 0;
+ }
+
+error_2:
+ kfree(desc);
+error:
+ crypto_free_shash(tfm);
+#endif /* __UBOOT__ */
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+}
+
+#ifndef __UBOOT__
+/*
+ * Check for self-signedness in an X.509 cert and if found, check the signature
+ * immediately if we can.
+ */
+int x509_check_for_self_signed(struct x509_certificate *cert)
+{
+ int ret = 0;
+
+ pr_devel("==>%s()\n", __func__);
+
+ if (cert->raw_subject_size != cert->raw_issuer_size ||
+ memcmp(cert->raw_subject, cert->raw_issuer,
+ cert->raw_issuer_size) != 0)
+ goto not_self_signed;
+
+ if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) {
+ /* If the AKID is present it may have one or two parts. If
+ * both are supplied, both must match.
+ */
+ bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]);
+ bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]);
+
+ if (!a && !b)
+ goto not_self_signed;
+
+ ret = -EKEYREJECTED;
+ if (((a && !b) || (b && !a)) &&
+ cert->sig->auth_ids[0] && cert->sig->auth_ids[1])
+ goto out;
+ }
+
+ ret = -EKEYREJECTED;
+ if (strcmp(cert->pub->pkey_algo, cert->sig->pkey_algo) != 0)
+ goto out;
+
+ ret = public_key_verify_signature(cert->pub, cert->sig);
+ if (ret < 0) {
+ if (ret == -ENOPKG) {
+ cert->unsupported_sig = true;
+ ret = 0;
+ }
+ goto out;
+ }
+
+ pr_devel("Cert Self-signature verified");
+ cert->self_signed = true;
+
+out:
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+
+not_self_signed:
+ pr_devel("<==%s() = 0 [not]\n", __func__);
+ return 0;
+}
+
+/*
+ * Attempt to parse a data blob for a key as an X509 certificate.
+ */
+static int x509_key_preparse(struct key_preparsed_payload *prep)
+{
+ struct asymmetric_key_ids *kids;
+ struct x509_certificate *cert;
+ const char *q;
+ size_t srlen, sulen;
+ char *desc = NULL, *p;
+ int ret;
+
+ cert = x509_cert_parse(prep->data, prep->datalen);
+ if (IS_ERR(cert))
+ return PTR_ERR(cert);
+
+ pr_devel("Cert Issuer: %s\n", cert->issuer);
+ pr_devel("Cert Subject: %s\n", cert->subject);
+
+ if (cert->unsupported_key) {
+ ret = -ENOPKG;
+ goto error_free_cert;
+ }
+
+ pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo);
+ pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
+
+ cert->pub->id_type = "X509";
+
+ if (cert->unsupported_sig) {
+ public_key_signature_free(cert->sig);
+ cert->sig = NULL;
+ } else {
+ pr_devel("Cert Signature: %s + %s\n",
+ cert->sig->pkey_algo, cert->sig->hash_algo);
+ }
+
+ /* Don't permit addition of blacklisted keys */
+ ret = -EKEYREJECTED;
+ if (cert->blacklisted)
+ goto error_free_cert;
+
+ /* Propose a description */
+ sulen = strlen(cert->subject);
+ if (cert->raw_skid) {
+ srlen = cert->raw_skid_size;
+ q = cert->raw_skid;
+ } else {
+ srlen = cert->raw_serial_size;
+ q = cert->raw_serial;
+ }
+
+ ret = -ENOMEM;
+ desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL);
+ if (!desc)
+ goto error_free_cert;
+ p = memcpy(desc, cert->subject, sulen);
+ p += sulen;
+ *p++ = ':';
+ *p++ = ' ';
+ p = bin2hex(p, q, srlen);
+ *p = 0;
+
+ kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL);
+ if (!kids)
+ goto error_free_desc;
+ kids->id[0] = cert->id;
+ kids->id[1] = cert->skid;
+
+ /* We're pinning the module by being linked against it */
+ __module_get(public_key_subtype.owner);
+ prep->payload.data[asym_subtype] = &public_key_subtype;
+ prep->payload.data[asym_key_ids] = kids;
+ prep->payload.data[asym_crypto] = cert->pub;
+ prep->payload.data[asym_auth] = cert->sig;
+ prep->description = desc;
+ prep->quotalen = 100;
+
+ /* We've finished with the certificate */
+ cert->pub = NULL;
+ cert->id = NULL;
+ cert->skid = NULL;
+ cert->sig = NULL;
+ desc = NULL;
+ ret = 0;
+
+error_free_desc:
+ kfree(desc);
+error_free_cert:
+ x509_free_certificate(cert);
+ return ret;
+}
+
+static struct asymmetric_key_parser x509_key_parser = {
+ .owner = THIS_MODULE,
+ .name = "x509",
+ .parse = x509_key_preparse,
+};
+
+/*
+ * Module stuff
+ */
+static int __init x509_key_init(void)
+{
+ return register_asymmetric_key_parser(&x509_key_parser);
+}
+
+static void __exit x509_key_exit(void)
+{
+ unregister_asymmetric_key_parser(&x509_key_parser);
+}
+
+module_init(x509_key_init);
+module_exit(x509_key_exit);
+#endif /* !__UBOOT__ */
+
+MODULE_DESCRIPTION("X.509 certificate parser");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/date.c b/lib/date.c
index c57317d2c2..0456de78ab 100644
--- a/drivers/rtc/date.c
+++ b/lib/date.c
@@ -8,9 +8,9 @@
#include <command.h>
#include <errno.h>
#include <rtc.h>
+#include <linux/time.h>
-#if defined(CONFIG_CMD_DATE) || defined(CONFIG_DM_RTC) || \
- defined(CONFIG_TIMESTAMP)
+#if defined(CONFIG_LIB_DATE) || defined(CONFIG_TIMESTAMP)
#define FEBRUARY 2
#define STARTOFTIME 1970
@@ -97,4 +97,23 @@ unsigned long rtc_mktime(const struct rtc_time *tm)
return (hours * 60 + tm->tm_min) * 60 + tm->tm_sec;
}
+#endif /* CONFIG_LIB_DATE || CONFIG_TIMESTAMP */
+
+#ifdef CONFIG_LIB_DATE
+/* for compatibility with linux code */
+time64_t mktime64(const unsigned int year, const unsigned int mon,
+ const unsigned int day, const unsigned int hour,
+ const unsigned int min, const unsigned int sec)
+{
+ struct rtc_time time;
+
+ time.tm_year = year;
+ time.tm_mon = mon;
+ time.tm_mday = day;
+ time.tm_hour = hour;
+ time.tm_min = min;
+ time.tm_sec = sec;
+
+ return (time64_t)rtc_mktime((const struct rtc_time *)&time);
+}
#endif
diff --git a/lib/linux_compat.c b/lib/linux_compat.c
index 81ea8fb126..3f440deaa0 100644
--- a/lib/linux_compat.c
+++ b/lib/linux_compat.c
@@ -40,3 +40,22 @@ void *kmem_cache_alloc(struct kmem_cache *obj, int flag)
{
return malloc_cache_aligned(obj->sz);
}
+
+/**
+ * kmemdup - duplicate region of memory
+ *
+ * @src: memory region to duplicate
+ * @len: memory region length
+ * @gfp: GFP mask to use
+ *
+ * Return: newly allocated copy of @src or %NULL in case of error
+ */
+void *kmemdup(const void *src, size_t len, gfp_t gfp)
+{
+ void *p;
+
+ p = kmalloc(len, gfp);
+ if (p)
+ memcpy(p, src, len);
+ return p;
+}
diff --git a/lib/net_utils.c b/lib/net_utils.c
index 9fb9d4a4b0..ed5044c3de 100644
--- a/lib/net_utils.c
+++ b/lib/net_utils.c
@@ -41,3 +41,18 @@ struct in_addr string_to_ip(const char *s)
addr.s_addr = htonl(addr.s_addr);
return addr;
}
+
+void string_to_enetaddr(const char *addr, uint8_t *enetaddr)
+{
+ char *end;
+ int i;
+
+ if (!enetaddr)
+ return;
+
+ for (i = 0; i < 6; ++i) {
+ enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
+ if (addr)
+ addr = (*end) ? end + 1 : end;
+ }
+}
diff --git a/lib/oid_registry.c b/lib/oid_registry.c
new file mode 100644
index 0000000000..209edc73b9
--- /dev/null
+++ b/lib/oid_registry.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* ASN.1 Object identifier (OID) registry
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifdef __UBOOT__
+#include <linux/compat.h>
+#else
+#include <linux/module.h>
+#include <linux/export.h>
+#endif
+#include <linux/oid_registry.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include "oid_registry_data.c"
+
+MODULE_DESCRIPTION("OID Registry");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+/**
+ * look_up_OID - Find an OID registration for the specified data
+ * @data: Binary representation of the OID
+ * @datasize: Size of the binary representation
+ */
+enum OID look_up_OID(const void *data, size_t datasize)
+{
+ const unsigned char *octets = data;
+ enum OID oid;
+ unsigned char xhash;
+ unsigned i, j, k, hash;
+ size_t len;
+
+ /* Hash the OID data */
+ hash = datasize - 1;
+
+ for (i = 0; i < datasize; i++)
+ hash += octets[i] * 33;
+ hash = (hash >> 24) ^ (hash >> 16) ^ (hash >> 8) ^ hash;
+ hash &= 0xff;
+
+ /* Binary search the OID registry. OIDs are stored in ascending order
+ * of hash value then ascending order of size and then in ascending
+ * order of reverse value.
+ */
+ i = 0;
+ k = OID__NR;
+ while (i < k) {
+ j = (i + k) / 2;
+
+ xhash = oid_search_table[j].hash;
+ if (xhash > hash) {
+ k = j;
+ continue;
+ }
+ if (xhash < hash) {
+ i = j + 1;
+ continue;
+ }
+
+ oid = oid_search_table[j].oid;
+ len = oid_index[oid + 1] - oid_index[oid];
+ if (len > datasize) {
+ k = j;
+ continue;
+ }
+ if (len < datasize) {
+ i = j + 1;
+ continue;
+ }
+
+ /* Variation is most likely to be at the tail end of the
+ * OID, so do the comparison in reverse.
+ */
+ while (len > 0) {
+ unsigned char a = oid_data[oid_index[oid] + --len];
+ unsigned char b = octets[len];
+ if (a > b) {
+ k = j;
+ goto next;
+ }
+ if (a < b) {
+ i = j + 1;
+ goto next;
+ }
+ }
+ return oid;
+ next:
+ ;
+ }
+
+ return OID__NR;
+}
+EXPORT_SYMBOL_GPL(look_up_OID);
+
+/*
+ * sprint_OID - Print an Object Identifier into a buffer
+ * @data: The encoded OID to print
+ * @datasize: The size of the encoded OID
+ * @buffer: The buffer to render into
+ * @bufsize: The size of the buffer
+ *
+ * The OID is rendered into the buffer in "a.b.c.d" format and the number of
+ * bytes is returned. -EBADMSG is returned if the data could not be intepreted
+ * and -ENOBUFS if the buffer was too small.
+ */
+int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
+{
+ const unsigned char *v = data, *end = v + datasize;
+ unsigned long num;
+ unsigned char n;
+ size_t ret;
+ int count;
+
+ if (v >= end)
+ goto bad;
+
+ n = *v++;
+ ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
+ if (count >= bufsize)
+ return -ENOBUFS;
+ buffer += count;
+ bufsize -= count;
+
+ while (v < end) {
+ num = 0;
+ n = *v++;
+ if (!(n & 0x80)) {
+ num = n;
+ } else {
+ num = n & 0x7f;
+ do {
+ if (v >= end)
+ goto bad;
+ n = *v++;
+ num <<= 7;
+ num |= n & 0x7f;
+ } while (n & 0x80);
+ }
+ ret += count = snprintf(buffer, bufsize, ".%lu", num);
+ if (count >= bufsize)
+ return -ENOBUFS;
+ buffer += count;
+ bufsize -= count;
+ }
+
+ return ret;
+
+bad:
+ snprintf(buffer, bufsize, "(bad)");
+ return -EBADMSG;
+}
+EXPORT_SYMBOL_GPL(sprint_oid);
+
+/**
+ * sprint_OID - Print an Object Identifier into a buffer
+ * @oid: The OID to print
+ * @buffer: The buffer to render into
+ * @bufsize: The size of the buffer
+ *
+ * The OID is rendered into the buffer in "a.b.c.d" format and the number of
+ * bytes is returned.
+ */
+int sprint_OID(enum OID oid, char *buffer, size_t bufsize)
+{
+ int ret;
+
+ BUG_ON(oid >= OID__NR);
+
+ ret = sprint_oid(oid_data + oid_index[oid],
+ oid_index[oid + 1] - oid_index[oid],
+ buffer, bufsize);
+ BUG_ON(ret == -EBADMSG);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sprint_OID);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index c6467ecd5f..b4edee29b0 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -320,7 +320,6 @@ static char *device_path_string(char *buf, char *end, void *dp, int field_width,
#endif
#endif
-#ifdef CONFIG_CMD_NET
static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
int precision, int flags)
{
@@ -382,7 +381,6 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
return string(buf, end, ip4_addr, field_width, precision,
flags & ~SPECIAL);
}
-#endif
#ifdef CONFIG_LIB_UUID
/*
@@ -474,7 +472,6 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
break;
}
break;
-#ifdef CONFIG_CMD_NET
case 'm':
flags |= SPECIAL;
/* Fallthrough */
@@ -493,7 +490,6 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
precision, flags);
flags &= ~SPECIAL;
break;
-#endif
#ifdef CONFIG_LIB_UUID
case 'U':
return uuid_string(buf, end, ptr, field_width, precision,
diff --git a/net/Kconfig b/net/Kconfig
index 68cecf75a2..a07f6746c5 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -31,7 +31,7 @@ config IP_DEFRAG
config TFTP_BLOCKSIZE
int "TFTP block size"
- default 512
+ default 1468
help
Default TFTP block size.
diff --git a/net/eth-uclass.c b/net/eth-uclass.c
index 3bd98b01ad..ed81cbd537 100644
--- a/net/eth-uclass.c
+++ b/net/eth-uclass.c
@@ -227,7 +227,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op,
switch (op) {
case env_op_create:
case env_op_overwrite:
- eth_parse_enetaddr(value, pdata->enetaddr);
+ string_to_enetaddr(value, pdata->enetaddr);
eth_write_hwaddr(dev);
break;
case env_op_delete:
@@ -420,20 +420,25 @@ int eth_initialize(void)
bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
do {
- if (num_devices)
- printf(", ");
+ if (dev->seq != -1) {
+ if (num_devices)
+ printf(", ");
- printf("eth%d: %s", dev->seq, dev->name);
+ printf("eth%d: %s", dev->seq, dev->name);
- if (ethprime && dev == prime_dev)
- printf(" [PRIME]");
+ if (ethprime && dev == prime_dev)
+ printf(" [PRIME]");
+ }
eth_write_hwaddr(dev);
+ if (dev->seq != -1)
+ num_devices++;
uclass_next_device_check(&dev);
- num_devices++;
} while (dev);
+ if (!num_devices)
+ printf("No ethernet found.\n");
putc('\n');
}
diff --git a/net/eth_legacy.c b/net/eth_legacy.c
index 41f5263526..5d6b0d7d7f 100644
--- a/net/eth_legacy.c
+++ b/net/eth_legacy.c
@@ -117,7 +117,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op,
switch (op) {
case env_op_create:
case env_op_overwrite:
- eth_parse_enetaddr(value, dev->enetaddr);
+ string_to_enetaddr(value, dev->enetaddr);
eth_write_hwaddr(dev, "eth", dev->index);
break;
case env_op_delete:
diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c
index 6f922e80b6..f75e4df626 100644
--- a/net/mdio-uclass.c
+++ b/net/mdio-uclass.c
@@ -10,6 +10,16 @@
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
+/* DT node properties for MAC-PHY interface */
+#define PHY_MODE_STR_CNT 2
+static const char *phy_mode_str[PHY_MODE_STR_CNT] = { "phy-mode",
+ "phy-connection-type" };
+/* DT node properties that reference a PHY node */
+#define PHY_HANDLE_STR_CNT 3
+const char *phy_handle_str[PHY_HANDLE_STR_CNT] = { "phy-handle",
+ "phy",
+ "phy-device" };
+
void dm_mdio_probe_devices(void)
{
struct udevice *it;
@@ -104,16 +114,96 @@ static int dm_mdio_pre_remove(struct udevice *dev)
return 0;
}
-struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr,
+struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr,
struct udevice *ethdev,
phy_interface_t interface)
{
- struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev);
+ struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdiodev);
- if (device_probe(dev))
- return 0;
+ if (device_probe(mdiodev))
+ return NULL;
+
+ return phy_connect(pdata->mii_bus, phyaddr, ethdev, interface);
+}
+
+static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev,
+ phy_interface_t interface)
+{
+ u32 phy_addr;
+ struct udevice *mdiodev;
+ struct phy_device *phy;
+ struct ofnode_phandle_args phandle = {.node = ofnode_null()};
+ int i;
+
+ for (i = 0; i < PHY_HANDLE_STR_CNT; i++)
+ if (!dev_read_phandle_with_args(ethdev, phy_handle_str[i], NULL,
+ 0, 0, &phandle))
+ break;
+
+ if (!ofnode_valid(phandle.node)) {
+ dev_dbg(dev, "can't find PHY node\n");
+ return NULL;
+ }
+
+ /*
+ * reading 'reg' directly should be fine. This is a PHY node, the
+ * address is always size 1 and requires no translation
+ */
+ if (ofnode_read_u32(phandle.node, "reg", &phy_addr)) {
+ dev_dbg(ethdev, "missing reg property in phy node\n");
+ return NULL;
+ }
+
+ if (uclass_get_device_by_ofnode(UCLASS_MDIO,
+ ofnode_get_parent(phandle.node),
+ &mdiodev)) {
+ dev_dbg(dev, "can't find MDIO bus for node %s\n",
+ ofnode_get_name(ofnode_get_parent(phandle.node)));
+ return NULL;
+ }
+
+ phy = dm_mdio_phy_connect(mdiodev, phy_addr, ethdev, interface);
+
+ if (phy)
+ phy->node = phandle.node;
+
+ return phy;
+}
+
+/* Connect to a PHY linked in eth DT node */
+struct phy_device *dm_eth_phy_connect(struct udevice *ethdev)
+{
+ const char *if_str;
+ phy_interface_t interface;
+ struct phy_device *phy;
+ int i;
+
+ if (!ofnode_valid(ethdev->node)) {
+ debug("%s: supplied eth dev has no DT node!\n", ethdev->name);
+ return NULL;
+ }
+
+ interface = PHY_INTERFACE_MODE_NONE;
+ for (i = 0; i < PHY_MODE_STR_CNT; i++) {
+ if_str = ofnode_read_string(ethdev->node, phy_mode_str[i]);
+ if (if_str) {
+ interface = phy_get_interface_by_name(if_str);
+ break;
+ }
+ }
+ if (interface < 0)
+ interface = PHY_INTERFACE_MODE_NONE;
+ if (interface == PHY_INTERFACE_MODE_NONE)
+ dev_dbg(ethdev, "can't find interface mode, default to NONE\n");
+
+ phy = dm_eth_connect_phy_handle(ethdev, interface);
+
+ if (!phy)
+ return NULL;
+
+ phy->interface = interface;
- return phy_connect(pdata->mii_bus, addr, ethdev, interface);
+ return phy;
}
UCLASS_DRIVER(mdio) = {
diff --git a/net/net.c b/net/net.c
index 0513444eb7..5199d679a1 100644
--- a/net/net.c
+++ b/net/net.c
@@ -308,7 +308,7 @@ U_BOOT_ENV_CALLBACK(dnsip, on_dnsip);
*/
void net_auto_load(void)
{
-#if defined(CONFIG_CMD_NFS)
+#if defined(CONFIG_CMD_NFS) && !defined(CONFIG_SPL_BUILD)
const char *s = env_get("autoload");
if (s != NULL && strcmp(s, "NFS") == 0) {
@@ -496,7 +496,7 @@ restart:
ping_start();
break;
#endif
-#if defined(CONFIG_CMD_NFS)
+#if defined(CONFIG_CMD_NFS) && !defined(CONFIG_SPL_BUILD)
case NFS:
nfs_start();
break;
@@ -1271,7 +1271,7 @@ void net_process_received_packet(uchar *in_packet, int len)
#ifdef CONFIG_UDP_CHECKSUM
if (ip->udp_xsum != 0) {
ulong xsum;
- ushort *sumptr;
+ u8 *sumptr;
ushort sumlen;
xsum = ip->ip_p;
@@ -1282,22 +1282,16 @@ void net_process_received_packet(uchar *in_packet, int len)
xsum += (ntohl(ip->ip_dst.s_addr) >> 0) & 0x0000ffff;
sumlen = ntohs(ip->udp_len);
- sumptr = (ushort *)&(ip->udp_src);
+ sumptr = (u8 *)&ip->udp_src;
while (sumlen > 1) {
- ushort sumdata;
-
- sumdata = *sumptr++;
- xsum += ntohs(sumdata);
+ /* inlined ntohs() to avoid alignment errors */
+ xsum += (sumptr[0] << 8) + sumptr[1];
+ sumptr += 2;
sumlen -= 2;
}
- if (sumlen > 0) {
- ushort sumdata;
-
- sumdata = *(unsigned char *)sumptr;
- sumdata = (sumdata << 8) & 0xff00;
- xsum += sumdata;
- }
+ if (sumlen > 0)
+ xsum += (sumptr[0] << 8) + sumptr[0];
while ((xsum >> 16) != 0) {
xsum = (xsum & 0x0000ffff) +
((xsum >> 16) & 0x0000ffff);
@@ -1625,15 +1619,3 @@ ushort env_get_vlan(char *var)
{
return string_to_vlan(env_get(var));
}
-
-void eth_parse_enetaddr(const char *addr, uint8_t *enetaddr)
-{
- char *end;
- int i;
-
- for (i = 0; i < 6; ++i) {
- enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
- if (addr)
- addr = (*end) ? end + 1 : end;
- }
-}
diff --git a/net/tftp.c b/net/tftp.c
index 5a69bca641..1e3c18ae69 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -171,8 +171,13 @@ static inline int store_block(int block, uchar *src, unsigned int len)
void *ptr;
#ifdef CONFIG_LMB
+ ulong end_addr = tftp_load_addr + tftp_load_size;
+
+ if (!end_addr)
+ end_addr = ULONG_MAX;
+
if (store_addr < tftp_load_addr ||
- store_addr + len > tftp_load_addr + tftp_load_size) {
+ store_addr + len > end_addr) {
puts("\nTFTP error: ");
puts("trying to overwrite reserved memory...\n");
return -1;
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index f7a041296d..26eb701f8d 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -328,10 +328,10 @@ $(obj)/%.lds: $(src)/%.lds.S FORCE
# ASN.1 grammar
# ---------------------------------------------------------------------------
quiet_cmd_asn1_compiler = ASN.1 $@
- cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \
+ cmd_asn1_compiler = $(objtree)/tools/asn1_compiler $< \
$(subst .h,.c,$@) $(subst .c,.h,$@)
-$(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler
+$(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/tools/asn1_compiler
$(call cmd,asn1_compiler)
# Build the compiled-in targets
diff --git a/scripts/build_OID_registry b/scripts/build_OID_registry
new file mode 100755
index 0000000000..d7fc32ea8a
--- /dev/null
+++ b/scripts/build_OID_registry
@@ -0,0 +1,203 @@
+#!/usr/bin/perl -w
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Build a static ASN.1 Object Identified (OID) registry
+#
+# Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+#
+
+use strict;
+
+my @names = ();
+my @oids = ();
+
+if ($#ARGV != 1) {
+ print STDERR "Format: ", $0, " <in-h-file> <out-c-file>\n";
+ exit(2);
+}
+
+#
+# Open the file to read from
+#
+open IN_FILE, "<$ARGV[0]" || die;
+while (<IN_FILE>) {
+ chomp;
+ if (m!\s+OID_([a-zA-z][a-zA-Z0-9_]+),\s+/[*]\s+([012][.0-9]*)\s+[*]/!) {
+ push @names, $1;
+ push @oids, $2;
+ }
+}
+close IN_FILE || die;
+
+#
+# Open the files to write into
+#
+open C_FILE, ">$ARGV[1]" or die;
+print C_FILE "/*\n";
+print C_FILE " * Automatically generated by ", $0, ". Do not edit\n";
+print C_FILE " */\n";
+
+#
+# Split the data up into separate lists and also determine the lengths of the
+# encoded data arrays.
+#
+my @indices = ();
+my @lengths = ();
+my $total_length = 0;
+
+for (my $i = 0; $i <= $#names; $i++) {
+ my $name = $names[$i];
+ my $oid = $oids[$i];
+
+ my @components = split(/[.]/, $oid);
+
+ # Determine the encoded length of this OID
+ my $size = $#components;
+ for (my $loop = 2; $loop <= $#components; $loop++) {
+ my $c = $components[$loop];
+
+ # We will base128 encode the number
+ my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
+ $tmp = int($tmp / 7);
+ $size += $tmp;
+ }
+ push @lengths, $size;
+ push @indices, $total_length;
+ $total_length += $size;
+}
+
+#
+# Emit the look-up-by-OID index table
+#
+print C_FILE "\n";
+if ($total_length <= 255) {
+ print C_FILE "static const unsigned char oid_index[OID__NR + 1] = {\n";
+} else {
+ print C_FILE "static const unsigned short oid_index[OID__NR + 1] = {\n";
+}
+for (my $i = 0; $i <= $#names; $i++) {
+ print C_FILE "\t[OID_", $names[$i], "] = ", $indices[$i], ",\n"
+}
+print C_FILE "\t[OID__NR] = ", $total_length, "\n";
+print C_FILE "};\n";
+
+#
+# Encode the OIDs
+#
+my @encoded_oids = ();
+
+for (my $i = 0; $i <= $#names; $i++) {
+ my @octets = ();
+
+ my @components = split(/[.]/, $oids[$i]);
+
+ push @octets, $components[0] * 40 + $components[1];
+
+ for (my $loop = 2; $loop <= $#components; $loop++) {
+ my $c = $components[$loop];
+
+ # Base128 encode the number
+ my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
+ $tmp = int($tmp / 7);
+
+ for (; $tmp > 0; $tmp--) {
+ push @octets, (($c >> $tmp * 7) & 0x7f) | 0x80;
+ }
+ push @octets, $c & 0x7f;
+ }
+
+ push @encoded_oids, \@octets;
+}
+
+#
+# Create a hash value for each OID
+#
+my @hash_values = ();
+for (my $i = 0; $i <= $#names; $i++) {
+ my @octets = @{$encoded_oids[$i]};
+
+ my $hash = $#octets;
+ foreach (@octets) {
+ $hash += $_ * 33;
+ }
+
+ $hash = ($hash >> 24) ^ ($hash >> 16) ^ ($hash >> 8) ^ ($hash);
+
+ push @hash_values, $hash & 0xff;
+}
+
+#
+# Emit the OID data
+#
+print C_FILE "\n";
+print C_FILE "static const unsigned char oid_data[", $total_length, "] = {\n";
+for (my $i = 0; $i <= $#names; $i++) {
+ my @octets = @{$encoded_oids[$i]};
+ print C_FILE "\t";
+ print C_FILE $_, ", " foreach (@octets);
+ print C_FILE "\t// ", $names[$i];
+ print C_FILE "\n";
+}
+print C_FILE "};\n";
+
+#
+# Build the search index table (ordered by length then hash then content)
+#
+my @index_table = ( 0 .. $#names );
+
+@index_table = sort {
+ my @octets_a = @{$encoded_oids[$a]};
+ my @octets_b = @{$encoded_oids[$b]};
+
+ return $hash_values[$a] <=> $hash_values[$b]
+ if ($hash_values[$a] != $hash_values[$b]);
+ return $#octets_a <=> $#octets_b
+ if ($#octets_a != $#octets_b);
+ for (my $i = $#octets_a; $i >= 0; $i--) {
+ return $octets_a[$i] <=> $octets_b[$i]
+ if ($octets_a[$i] != $octets_b[$i]);
+ }
+ return 0;
+
+} @index_table;
+
+#
+# Emit the search index and hash value table
+#
+print C_FILE "\n";
+print C_FILE "static const struct {\n";
+print C_FILE "\tunsigned char hash;\n";
+if ($#names <= 255) {
+ print C_FILE "\tenum OID oid : 8;\n";
+} else {
+ print C_FILE "\tenum OID oid : 16;\n";
+}
+print C_FILE "} oid_search_table[OID__NR] = {\n";
+for (my $i = 0; $i <= $#names; $i++) {
+ my @octets = @{$encoded_oids[$index_table[$i]]};
+ printf(C_FILE "\t[%3u] = { %3u, OID_%-35s }, // ",
+ $i,
+ $hash_values[$index_table[$i]],
+ $names[$index_table[$i]]);
+ printf C_FILE "%02x", $_ foreach (@octets);
+ print C_FILE "\n";
+}
+print C_FILE "};\n";
+
+#
+# Emit the OID debugging name table
+#
+#print C_FILE "\n";
+#print C_FILE "const char *const oid_name_table[OID__NR + 1] = {\n";
+#
+#for (my $i = 0; $i <= $#names; $i++) {
+# print C_FILE "\t\"", $names[$i], "\",\n"
+#}
+#print C_FILE "\t\"Unknown-OID\"\n";
+#print C_FILE "};\n";
+
+#
+# Polish off
+#
+close C_FILE or die;
diff --git a/test/Kconfig b/test/Kconfig
index f53629aac5..cb51b46721 100644
--- a/test/Kconfig
+++ b/test/Kconfig
@@ -12,7 +12,23 @@ config UT_LIB
default y
help
Enables the 'ut lib' command which tests library functions like
- memcat(), memcyp(), memmove().
+ memcat(), memcyp(), memmove() and ASN1 compiler/decoder.
+
+if UT_LIB
+
+config UT_LIB_ASN1
+ bool "Unit test for asn1 compiler and decoder function"
+ default y
+ imply ASYMMETRIC_KEY_TYPE
+ imply ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+ imply X509_CERTIFICATE_PARSER
+ imply PKCS7_MESSAGE_PARSER
+ imply RSA_PUBLIC_KEY_PARSER
+ help
+ Enables a test which exercises asn1 compiler and decoder function
+ via various parsers.
+
+endif
config UT_TIME
bool "Unit tests for time functions"
diff --git a/test/lib/Makefile b/test/lib/Makefile
index b13aaca7ce..72d2ec74b5 100644
--- a/test/lib/Makefile
+++ b/test/lib/Makefile
@@ -7,3 +7,4 @@ obj-y += hexdump.o
obj-y += lmb.o
obj-y += string.o
obj-$(CONFIG_ERRNO_STR) += test_errno_str.o
+obj-$(CONFIG_UT_LIB_ASN1) += asn1.o
diff --git a/test/lib/asn1.c b/test/lib/asn1.c
new file mode 100644
index 0000000000..d2b3f67e68
--- /dev/null
+++ b/test/lib/asn1.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019 Linaro Limited
+ * Author: AKASHI Takahiro
+ *
+ * Unit test for asn1 compiler and asn1 decoder function via various parsers
+ */
+
+#include <common.h>
+#include <command.h>
+#include <test/lib.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+#ifdef CONFIG_PKCS7_MESSAGE_PARSER
+#include "../../lib/crypto/pkcs7_parser.h"
+#else
+#ifdef CONFIG_X509_CERTIFICATE_PARSER
+#include "../../lib/crypto/x509_parser.h"
+#endif
+#endif
+
+#ifdef CONFIG_X509_CERTIFICATE_PARSER
+static const unsigned char cert_data[] = {
+ 0x30, 0x82, 0x03, 0xc7, 0x30, 0x82, 0x02, 0xaf, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x09, 0x00, 0xd7, 0x17, 0x0a, 0x76, 0xd5, 0xd3, 0x4d, 0xeb,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x0b, 0x05, 0x00, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03,
+ 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31, 0x0e,
+ 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x54, 0x6f, 0x6b,
+ 0x79, 0x6f, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+ 0x06, 0x4c, 0x69, 0x6e, 0x61, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x53, 0x57, 0x31, 0x0f, 0x30, 0x0d,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x54, 0x65, 0x73, 0x74, 0x65,
+ 0x72, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x40, 0x74,
+ 0x65, 0x73, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+ 0x39, 0x31, 0x30, 0x31, 0x38, 0x30, 0x33, 0x31, 0x33, 0x33, 0x31, 0x5a,
+ 0x17, 0x0d, 0x32, 0x30, 0x31, 0x30, 0x31, 0x37, 0x30, 0x33, 0x31, 0x33,
+ 0x33, 0x31, 0x5a, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03,
+ 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31, 0x0e,
+ 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x54, 0x6f, 0x6b,
+ 0x79, 0x6f, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+ 0x06, 0x4c, 0x69, 0x6e, 0x61, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x53, 0x57, 0x31, 0x0f, 0x30, 0x0d,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x54, 0x65, 0x73, 0x74, 0x65,
+ 0x72, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x40, 0x74,
+ 0x65, 0x73, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x82, 0x01, 0x22, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+ 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
+ 0x82, 0x01, 0x01, 0x00, 0x9f, 0x37, 0x4d, 0x95, 0x7e, 0x36, 0xb7, 0xaf,
+ 0xf4, 0xd6, 0xce, 0x39, 0x04, 0xee, 0xbf, 0x36, 0xb2, 0xcc, 0xa3, 0x8b,
+ 0x9e, 0xac, 0x62, 0x8a, 0xe9, 0xae, 0x18, 0xcf, 0xe8, 0x95, 0xfd, 0xcb,
+ 0xad, 0x34, 0x8a, 0x5f, 0x55, 0xe6, 0x0c, 0x5e, 0xf8, 0x76, 0xc1, 0xa2,
+ 0xc3, 0xd4, 0x73, 0x13, 0x8a, 0x71, 0x1b, 0xfd, 0x58, 0x27, 0xea, 0x4d,
+ 0x41, 0xff, 0x63, 0xbb, 0xad, 0x97, 0x62, 0xba, 0xe4, 0xe5, 0x97, 0x45,
+ 0xa3, 0x5b, 0xd5, 0x5b, 0x53, 0x55, 0x10, 0x19, 0xfa, 0xac, 0xbd, 0xdb,
+ 0x77, 0x62, 0x23, 0x50, 0x3f, 0x35, 0xdb, 0x8a, 0xf6, 0xee, 0x7a, 0x31,
+ 0xec, 0x92, 0xf5, 0x78, 0x35, 0x92, 0x76, 0x3c, 0x5f, 0xe7, 0xee, 0xc9,
+ 0xed, 0x01, 0x1c, 0x42, 0x55, 0xd6, 0x7e, 0xa6, 0xca, 0x7c, 0xd1, 0x15,
+ 0x16, 0x87, 0x7c, 0x99, 0x63, 0xc0, 0xa9, 0x25, 0x49, 0xbc, 0x4e, 0xdc,
+ 0x2d, 0x4b, 0xcb, 0x52, 0xd7, 0x67, 0xe9, 0x83, 0x6b, 0x5e, 0x5b, 0x48,
+ 0x80, 0x33, 0xe9, 0xcc, 0xe8, 0xfe, 0x19, 0xc8, 0xc2, 0x61, 0x74, 0x52,
+ 0x25, 0x92, 0x48, 0xea, 0xad, 0x15, 0x16, 0x64, 0x6e, 0x53, 0x30, 0x77,
+ 0xa2, 0xef, 0x61, 0x92, 0x1b, 0x5e, 0xbe, 0x07, 0xf2, 0x3c, 0xf8, 0x35,
+ 0x7d, 0x76, 0x4f, 0x78, 0xa9, 0x2a, 0xf1, 0x32, 0xff, 0xec, 0x89, 0xa9,
+ 0x22, 0x4c, 0x3d, 0xc8, 0x65, 0xca, 0xf4, 0xa2, 0x6d, 0x3f, 0xa4, 0x0a,
+ 0xfa, 0x9e, 0xe4, 0xf0, 0xdb, 0x39, 0xb1, 0xf9, 0xf0, 0xfb, 0x04, 0x81,
+ 0x44, 0xa7, 0xd7, 0x61, 0xdf, 0x2d, 0x13, 0x45, 0x2c, 0xae, 0xf0, 0x0e,
+ 0xc4, 0x07, 0x5d, 0x7d, 0x2b, 0xb2, 0x20, 0x75, 0x33, 0x6b, 0x5b, 0xf7,
+ 0xe7, 0x17, 0x51, 0xf1, 0xab, 0xc1, 0x9e, 0xc6, 0xf0, 0x30, 0xc6, 0x25,
+ 0x26, 0x3e, 0xd7, 0xd7, 0xa3, 0xcc, 0x15, 0x95, 0x02, 0x03, 0x01, 0x00,
+ 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+ 0x04, 0x16, 0x04, 0x14, 0x45, 0x8a, 0x76, 0xf7, 0x4f, 0xf4, 0x0e, 0xa0,
+ 0xf2, 0x02, 0xe1, 0xe7, 0xe9, 0xc7, 0x7d, 0x51, 0x55, 0x92, 0x33, 0xcd,
+ 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
+ 0x14, 0x45, 0x8a, 0x76, 0xf7, 0x4f, 0xf4, 0x0e, 0xa0, 0xf2, 0x02, 0xe1,
+ 0xe7, 0xe9, 0xc7, 0x7d, 0x51, 0x55, 0x92, 0x33, 0xcd, 0x30, 0x0c, 0x06,
+ 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+ 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x47, 0x93, 0x82, 0x0e, 0x8a,
+ 0x70, 0x9d, 0x6c, 0x7a, 0xdb, 0x04, 0xb4, 0xc9, 0xef, 0x98, 0x28, 0xc6,
+ 0xd9, 0x53, 0x90, 0xc8, 0x25, 0x83, 0x07, 0x23, 0xe7, 0x59, 0x38, 0xc1,
+ 0xc0, 0x50, 0x28, 0x99, 0x92, 0xfb, 0x21, 0x24, 0x72, 0xe5, 0xa6, 0x57,
+ 0x30, 0x31, 0xb3, 0xdf, 0xa0, 0x17, 0xa9, 0x73, 0x9c, 0x39, 0x83, 0xfb,
+ 0xe4, 0xfa, 0x20, 0x1d, 0xfa, 0x33, 0x20, 0x0c, 0x72, 0x2a, 0x50, 0x40,
+ 0xbd, 0x2d, 0x33, 0xa2, 0xfc, 0x06, 0xf9, 0xfe, 0x86, 0x4f, 0x50, 0x1d,
+ 0x65, 0x37, 0xe9, 0x30, 0x33, 0x82, 0xa1, 0x75, 0x8f, 0x5d, 0x33, 0x84,
+ 0x0d, 0xf2, 0x09, 0x04, 0xc0, 0x7a, 0x12, 0x79, 0xdb, 0x4f, 0x77, 0x04,
+ 0xe4, 0xd8, 0x0b, 0x87, 0x19, 0xba, 0xb7, 0x3c, 0xa6, 0x45, 0xaa, 0x91,
+ 0x62, 0x7f, 0x01, 0x7d, 0xc6, 0x20, 0x6d, 0x71, 0x15, 0x74, 0x5e, 0x87,
+ 0xb3, 0x60, 0x17, 0x9c, 0xc0, 0xed, 0x01, 0x4b, 0xb3, 0x23, 0x24, 0xc1,
+ 0xcb, 0x7a, 0x83, 0x03, 0x26, 0x2d, 0xde, 0x47, 0xc5, 0x11, 0x94, 0x28,
+ 0x27, 0x15, 0x92, 0x00, 0x8b, 0x2e, 0x51, 0x42, 0xca, 0x4b, 0x4a, 0x2c,
+ 0x51, 0x37, 0x56, 0xd0, 0xbc, 0x33, 0xd5, 0xd5, 0x3e, 0x79, 0x5c, 0x3f,
+ 0x9d, 0x6e, 0xb1, 0xe9, 0x71, 0xf1, 0x2c, 0xe9, 0xb4, 0x88, 0x2c, 0xd2,
+ 0x49, 0x97, 0xce, 0x29, 0x94, 0x16, 0xc9, 0xf9, 0x64, 0x0e, 0xd0, 0xd9,
+ 0x7a, 0x53, 0x10, 0x1a, 0xee, 0x83, 0x73, 0x93, 0x1b, 0xdf, 0x8a, 0x77,
+ 0xc0, 0x56, 0x63, 0xab, 0x5a, 0x65, 0xc5, 0xc5, 0x3b, 0xf3, 0x30, 0x80,
+ 0xfc, 0x38, 0x8b, 0xc9, 0xcd, 0xc3, 0x4f, 0x2e, 0x2d, 0x67, 0xcc, 0x17,
+ 0x18, 0x9b, 0x3e, 0xc6, 0x47, 0x03, 0xfc, 0x35, 0xa8, 0x35, 0x06, 0x5a,
+ 0x77, 0xe5, 0x97, 0x71, 0xbb, 0x27, 0x93, 0x0d, 0x1f, 0x0e, 0x8c
+};
+
+static unsigned int cert_data_len = 971;
+
+/**
+ * lib_asn1_x509() - unit test for asn1 decoder function
+ * with x509 certificate parser
+ *
+ * @uts: unit test state
+ * Return: 0 = success, 1 = failure
+ */
+static int lib_asn1_x509(struct unit_test_state *uts)
+{
+ struct x509_certificate *cert;
+
+ cert = x509_cert_parse(cert_data, cert_data_len);
+
+ ut_assertf(cert != NULL, "decoding failed\n");
+ ut_assertf(!strcmp(cert->subject, "Linaro: Tester"),
+ "subject doesn't match\n");
+ ut_assertf(!strcmp(cert->issuer, "Linaro: Tester"),
+ "issuer doesn't match\n");
+ ut_assertf(cert->pub, "public key doesn't exist\n");
+ ut_assertf(cert->pub->keylen == 0x10e, "key length doesn't match\n");
+ ut_assertf(!strcmp(cert->pub->pkey_algo, "rsa"), "algo isn't rsa\n");
+ ut_assertf(cert->valid_from == 0x5da92ddb,
+ "valid_from doesn't match\n");
+ ut_assertf(cert->valid_to == 0x5f8a615b, "valid_to doesn't match\n");
+
+ x509_free_certificate(cert);
+
+ return CMD_RET_SUCCESS;
+}
+
+LIB_TEST(lib_asn1_x509, 0);
+#endif /* CONFIG_X509_CERTIFICATE_PARSER */
+
+#ifdef CONFIG_PKCS7_MESSAGE_PARSER
+/*
+ * sbsign --key priv.pem --cert cert.pem --detach --out Image.pk Image
+ */
+static const unsigned char image_pk7[] = {
+ 0x30, 0x82, 0x07, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x07, 0x02, 0xa0, 0x82, 0x07, 0x00, 0x30, 0x82, 0x06, 0xfc, 0x02,
+ 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+ 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30, 0x78, 0x06, 0x0a, 0x2b,
+ 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x04, 0xa0, 0x6a, 0x30,
+ 0x68, 0x30, 0x33, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37,
+ 0x02, 0x01, 0x0f, 0x30, 0x25, 0x03, 0x01, 0x00, 0xa0, 0x20, 0xa2, 0x1e,
+ 0x80, 0x1c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62,
+ 0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x65,
+ 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04,
+ 0x20, 0x9e, 0x90, 0x99, 0x6d, 0xf2, 0xb5, 0x3d, 0x3f, 0xfc, 0x38, 0xb6,
+ 0xf2, 0x1f, 0xd2, 0x24, 0x88, 0x43, 0x77, 0x7d, 0xc1, 0x2c, 0x9e, 0x8a,
+ 0xf6, 0xf7, 0xdd, 0x9e, 0x9c, 0x5f, 0x18, 0x36, 0xc5, 0xa0, 0x82, 0x03,
+ 0xcb, 0x30, 0x82, 0x03, 0xc7, 0x30, 0x82, 0x02, 0xaf, 0xa0, 0x03, 0x02,
+ 0x01, 0x02, 0x02, 0x09, 0x00, 0xd7, 0x17, 0x0a, 0x76, 0xd5, 0xd3, 0x4d,
+ 0xeb, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31,
+ 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x54, 0x6f,
+ 0x6b, 0x79, 0x6f, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x0c, 0x06, 0x4c, 0x69, 0x6e, 0x61, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x53, 0x57, 0x31, 0x0f, 0x30,
+ 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x54, 0x65, 0x73, 0x74,
+ 0x65, 0x72, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x40,
+ 0x74, 0x65, 0x73, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x39, 0x31, 0x30, 0x31, 0x38, 0x30, 0x33, 0x31, 0x33, 0x33, 0x31,
+ 0x5a, 0x17, 0x0d, 0x32, 0x30, 0x31, 0x30, 0x31, 0x37, 0x30, 0x33, 0x31,
+ 0x33, 0x33, 0x31, 0x5a, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31,
+ 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x54, 0x6f,
+ 0x6b, 0x79, 0x6f, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x0c, 0x06, 0x4c, 0x69, 0x6e, 0x61, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x53, 0x57, 0x31, 0x0f, 0x30,
+ 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x54, 0x65, 0x73, 0x74,
+ 0x65, 0x72, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x40,
+ 0x74, 0x65, 0x73, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0x9f, 0x37, 0x4d, 0x95, 0x7e, 0x36, 0xb7,
+ 0xaf, 0xf4, 0xd6, 0xce, 0x39, 0x04, 0xee, 0xbf, 0x36, 0xb2, 0xcc, 0xa3,
+ 0x8b, 0x9e, 0xac, 0x62, 0x8a, 0xe9, 0xae, 0x18, 0xcf, 0xe8, 0x95, 0xfd,
+ 0xcb, 0xad, 0x34, 0x8a, 0x5f, 0x55, 0xe6, 0x0c, 0x5e, 0xf8, 0x76, 0xc1,
+ 0xa2, 0xc3, 0xd4, 0x73, 0x13, 0x8a, 0x71, 0x1b, 0xfd, 0x58, 0x27, 0xea,
+ 0x4d, 0x41, 0xff, 0x63, 0xbb, 0xad, 0x97, 0x62, 0xba, 0xe4, 0xe5, 0x97,
+ 0x45, 0xa3, 0x5b, 0xd5, 0x5b, 0x53, 0x55, 0x10, 0x19, 0xfa, 0xac, 0xbd,
+ 0xdb, 0x77, 0x62, 0x23, 0x50, 0x3f, 0x35, 0xdb, 0x8a, 0xf6, 0xee, 0x7a,
+ 0x31, 0xec, 0x92, 0xf5, 0x78, 0x35, 0x92, 0x76, 0x3c, 0x5f, 0xe7, 0xee,
+ 0xc9, 0xed, 0x01, 0x1c, 0x42, 0x55, 0xd6, 0x7e, 0xa6, 0xca, 0x7c, 0xd1,
+ 0x15, 0x16, 0x87, 0x7c, 0x99, 0x63, 0xc0, 0xa9, 0x25, 0x49, 0xbc, 0x4e,
+ 0xdc, 0x2d, 0x4b, 0xcb, 0x52, 0xd7, 0x67, 0xe9, 0x83, 0x6b, 0x5e, 0x5b,
+ 0x48, 0x80, 0x33, 0xe9, 0xcc, 0xe8, 0xfe, 0x19, 0xc8, 0xc2, 0x61, 0x74,
+ 0x52, 0x25, 0x92, 0x48, 0xea, 0xad, 0x15, 0x16, 0x64, 0x6e, 0x53, 0x30,
+ 0x77, 0xa2, 0xef, 0x61, 0x92, 0x1b, 0x5e, 0xbe, 0x07, 0xf2, 0x3c, 0xf8,
+ 0x35, 0x7d, 0x76, 0x4f, 0x78, 0xa9, 0x2a, 0xf1, 0x32, 0xff, 0xec, 0x89,
+ 0xa9, 0x22, 0x4c, 0x3d, 0xc8, 0x65, 0xca, 0xf4, 0xa2, 0x6d, 0x3f, 0xa4,
+ 0x0a, 0xfa, 0x9e, 0xe4, 0xf0, 0xdb, 0x39, 0xb1, 0xf9, 0xf0, 0xfb, 0x04,
+ 0x81, 0x44, 0xa7, 0xd7, 0x61, 0xdf, 0x2d, 0x13, 0x45, 0x2c, 0xae, 0xf0,
+ 0x0e, 0xc4, 0x07, 0x5d, 0x7d, 0x2b, 0xb2, 0x20, 0x75, 0x33, 0x6b, 0x5b,
+ 0xf7, 0xe7, 0x17, 0x51, 0xf1, 0xab, 0xc1, 0x9e, 0xc6, 0xf0, 0x30, 0xc6,
+ 0x25, 0x26, 0x3e, 0xd7, 0xd7, 0xa3, 0xcc, 0x15, 0x95, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x45, 0x8a, 0x76, 0xf7, 0x4f, 0xf4, 0x0e,
+ 0xa0, 0xf2, 0x02, 0xe1, 0xe7, 0xe9, 0xc7, 0x7d, 0x51, 0x55, 0x92, 0x33,
+ 0xcd, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x45, 0x8a, 0x76, 0xf7, 0x4f, 0xf4, 0x0e, 0xa0, 0xf2, 0x02,
+ 0xe1, 0xe7, 0xe9, 0xc7, 0x7d, 0x51, 0x55, 0x92, 0x33, 0xcd, 0x30, 0x0c,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x47, 0x93, 0x82, 0x0e,
+ 0x8a, 0x70, 0x9d, 0x6c, 0x7a, 0xdb, 0x04, 0xb4, 0xc9, 0xef, 0x98, 0x28,
+ 0xc6, 0xd9, 0x53, 0x90, 0xc8, 0x25, 0x83, 0x07, 0x23, 0xe7, 0x59, 0x38,
+ 0xc1, 0xc0, 0x50, 0x28, 0x99, 0x92, 0xfb, 0x21, 0x24, 0x72, 0xe5, 0xa6,
+ 0x57, 0x30, 0x31, 0xb3, 0xdf, 0xa0, 0x17, 0xa9, 0x73, 0x9c, 0x39, 0x83,
+ 0xfb, 0xe4, 0xfa, 0x20, 0x1d, 0xfa, 0x33, 0x20, 0x0c, 0x72, 0x2a, 0x50,
+ 0x40, 0xbd, 0x2d, 0x33, 0xa2, 0xfc, 0x06, 0xf9, 0xfe, 0x86, 0x4f, 0x50,
+ 0x1d, 0x65, 0x37, 0xe9, 0x30, 0x33, 0x82, 0xa1, 0x75, 0x8f, 0x5d, 0x33,
+ 0x84, 0x0d, 0xf2, 0x09, 0x04, 0xc0, 0x7a, 0x12, 0x79, 0xdb, 0x4f, 0x77,
+ 0x04, 0xe4, 0xd8, 0x0b, 0x87, 0x19, 0xba, 0xb7, 0x3c, 0xa6, 0x45, 0xaa,
+ 0x91, 0x62, 0x7f, 0x01, 0x7d, 0xc6, 0x20, 0x6d, 0x71, 0x15, 0x74, 0x5e,
+ 0x87, 0xb3, 0x60, 0x17, 0x9c, 0xc0, 0xed, 0x01, 0x4b, 0xb3, 0x23, 0x24,
+ 0xc1, 0xcb, 0x7a, 0x83, 0x03, 0x26, 0x2d, 0xde, 0x47, 0xc5, 0x11, 0x94,
+ 0x28, 0x27, 0x15, 0x92, 0x00, 0x8b, 0x2e, 0x51, 0x42, 0xca, 0x4b, 0x4a,
+ 0x2c, 0x51, 0x37, 0x56, 0xd0, 0xbc, 0x33, 0xd5, 0xd5, 0x3e, 0x79, 0x5c,
+ 0x3f, 0x9d, 0x6e, 0xb1, 0xe9, 0x71, 0xf1, 0x2c, 0xe9, 0xb4, 0x88, 0x2c,
+ 0xd2, 0x49, 0x97, 0xce, 0x29, 0x94, 0x16, 0xc9, 0xf9, 0x64, 0x0e, 0xd0,
+ 0xd9, 0x7a, 0x53, 0x10, 0x1a, 0xee, 0x83, 0x73, 0x93, 0x1b, 0xdf, 0x8a,
+ 0x77, 0xc0, 0x56, 0x63, 0xab, 0x5a, 0x65, 0xc5, 0xc5, 0x3b, 0xf3, 0x30,
+ 0x80, 0xfc, 0x38, 0x8b, 0xc9, 0xcd, 0xc3, 0x4f, 0x2e, 0x2d, 0x67, 0xcc,
+ 0x17, 0x18, 0x9b, 0x3e, 0xc6, 0x47, 0x03, 0xfc, 0x35, 0xa8, 0x35, 0x06,
+ 0x5a, 0x77, 0xe5, 0x97, 0x71, 0xbb, 0x27, 0x93, 0x0d, 0x1f, 0x0e, 0x8c,
+ 0x31, 0x82, 0x02, 0x9b, 0x30, 0x82, 0x02, 0x97, 0x02, 0x01, 0x01, 0x30,
+ 0x81, 0x87, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55,
+ 0x04, 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31, 0x0e, 0x30,
+ 0x0c, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79,
+ 0x6f, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06,
+ 0x4c, 0x69, 0x6e, 0x61, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x53, 0x57, 0x31, 0x0f, 0x30, 0x0d, 0x06,
+ 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x54, 0x65, 0x73, 0x74, 0x65, 0x72,
+ 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x09, 0x01, 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x40, 0x74, 0x65,
+ 0x73, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x02, 0x09, 0x00, 0xd7, 0x17, 0x0a,
+ 0x76, 0xd5, 0xd3, 0x4d, 0xeb, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
+ 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xa0, 0x81, 0xe5, 0x30,
+ 0x19, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x03,
+ 0x31, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02,
+ 0x01, 0x04, 0x30, 0x1c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x09, 0x05, 0x31, 0x0f, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x31,
+ 0x38, 0x30, 0x35, 0x35, 0x35, 0x32, 0x36, 0x5a, 0x30, 0x2f, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04, 0x31, 0x22, 0x04,
+ 0x20, 0x13, 0xe9, 0x2d, 0xcd, 0x35, 0x43, 0xe0, 0x13, 0x34, 0xc5, 0x67,
+ 0xde, 0xdd, 0x75, 0xdc, 0x62, 0x97, 0x76, 0x7d, 0x5b, 0xa0, 0xb4, 0x4d,
+ 0x4f, 0xef, 0xb8, 0xa7, 0x95, 0x50, 0xcb, 0x0f, 0xec, 0x30, 0x79, 0x06,
+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x0f, 0x31, 0x6c,
+ 0x30, 0x6a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+ 0x04, 0x01, 0x2a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
+ 0x03, 0x04, 0x01, 0x16, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+ 0x65, 0x03, 0x04, 0x01, 0x02, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x03, 0x07, 0x30, 0x0e, 0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x02, 0x00, 0x80, 0x30, 0x0d, 0x06,
+ 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x01, 0x40,
+ 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x07, 0x30, 0x0d, 0x06,
+ 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x01, 0x28,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x38, 0x40, 0x09, 0xc7, 0xc4,
+ 0xf7, 0x78, 0x48, 0x75, 0x1e, 0xb2, 0x50, 0x95, 0x0a, 0x52, 0xee, 0x57,
+ 0x60, 0xc5, 0xf4, 0xdb, 0xca, 0x67, 0xb0, 0x19, 0xad, 0x68, 0xb1, 0xe1,
+ 0x1e, 0xb7, 0xf6, 0x53, 0x3d, 0x13, 0xb1, 0x11, 0x37, 0xa7, 0x6e, 0x9b,
+ 0x18, 0x1d, 0x0e, 0xbd, 0xc4, 0xb2, 0xd0, 0x36, 0x6c, 0x0c, 0x5a, 0x11,
+ 0x50, 0xcc, 0xdb, 0x1f, 0x6b, 0xcb, 0x28, 0x80, 0xd5, 0x3c, 0x4f, 0x93,
+ 0x0b, 0xd1, 0x45, 0x75, 0xa1, 0x89, 0x00, 0x71, 0x7d, 0x55, 0xcc, 0x1c,
+ 0x0a, 0xc9, 0xc4, 0xe6, 0x87, 0xf2, 0x87, 0x0d, 0x2e, 0x79, 0x71, 0x85,
+ 0x01, 0xd7, 0x32, 0x87, 0x9a, 0x11, 0xc6, 0x9a, 0xbb, 0x0a, 0x7b, 0xce,
+ 0xfe, 0xc8, 0xee, 0x10, 0x3c, 0xa6, 0x47, 0xdd, 0xbb, 0xa7, 0xf5, 0x19,
+ 0x50, 0xd5, 0x2a, 0x11, 0x44, 0x2f, 0x65, 0x09, 0x69, 0x50, 0xfa, 0xbd,
+ 0x02, 0xe4, 0x90, 0xdc, 0x2a, 0x7c, 0xdb, 0x82, 0x03, 0xa5, 0x28, 0x91,
+ 0x74, 0x7c, 0xd3, 0x83, 0xc8, 0x11, 0x1a, 0x14, 0x1b, 0xba, 0xb1, 0x82,
+ 0xbd, 0x53, 0xad, 0x9c, 0x34, 0x05, 0xfa, 0x2d, 0x14, 0x58, 0x5e, 0x50,
+ 0x64, 0x60, 0x5c, 0x21, 0x7c, 0xe6, 0xf0, 0x2b, 0xa2, 0xec, 0xe5, 0xeb,
+ 0xda, 0x88, 0xe2, 0x19, 0x36, 0x96, 0x65, 0xf7, 0x4c, 0x62, 0x9b, 0x75,
+ 0x24, 0xb4, 0xb1, 0x34, 0x83, 0xba, 0x05, 0x01, 0xd8, 0xe1, 0x33, 0xd3,
+ 0x1a, 0xd6, 0x09, 0x84, 0x31, 0xd0, 0x67, 0xf3, 0x3b, 0x0e, 0x19, 0x98,
+ 0x7e, 0x07, 0xdc, 0xe1, 0xd8, 0x45, 0x84, 0xa2, 0xdd, 0x8a, 0x04, 0x6a,
+ 0x43, 0xcf, 0xff, 0x7c, 0x9e, 0x83, 0xa8, 0x5d, 0xbc, 0x1f, 0x45, 0x86,
+ 0x5b, 0x2d, 0xcd, 0x9d, 0xa0, 0xba, 0x4d, 0xd2, 0xc6, 0xb9, 0xc5, 0x34,
+ 0x39, 0x29, 0x20, 0xee, 0x27, 0x60, 0x46, 0x9c, 0x62, 0xbe, 0xf2
+};
+
+static unsigned int image_pk7_len = 1811;
+
+/**
+ * lib_asn1_pkcs7() - unit test for asn1 decoder function
+ * with pkcs7 message parser
+ *
+ * @uts: unit test state
+ * Return: 0 = success, 1 = failure
+ */
+static int lib_asn1_pkcs7(struct unit_test_state *uts)
+{
+ struct pkcs7_message *pkcs7;
+
+ pkcs7 = pkcs7_parse_message(image_pk7, image_pk7_len);
+
+ ut_assertf(pkcs7 != NULL, "decoding failed\n");
+ ut_assertf(pkcs7->data_len == 104, "signature size doesn't match\n");
+ ut_assertf(pkcs7->signed_infos != NULL, "sign-info doesn't exist\n");
+ ut_assertf(pkcs7->signed_infos->msgdigest_len == 32,
+ "digest size doesn't match\n");
+ ut_assertf(pkcs7->signed_infos->aa_set == 0xf,
+ "authenticated attributes doesn't match\n");
+
+ pkcs7_free_message(pkcs7);
+
+ return CMD_RET_SUCCESS;
+}
+
+LIB_TEST(lib_asn1_pkcs7, 0);
+#endif /* CONFIG_PKCS7_MESSAGE_PARSER */
+
+#ifdef CONFIG_RSA_PUBLIC_KEY_PARSER
+#include <crypto/internal/rsa.h>
+
+/*
+ * openssl genrsa 2048 -out private.pem
+ * openssl rsa -in private.pem -pubout -outform der -out public.der
+ * dd if=public.der of=public.raw bs=24 skip=1
+ */
+static const unsigned char public_key[] = {
+ 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xca, 0x25, 0x23,
+ 0xe0, 0x0a, 0x4d, 0x8f, 0x56, 0xfc, 0xc9, 0x06, 0x4c, 0xcc, 0x94, 0x43,
+ 0xe0, 0x56, 0x44, 0x6e, 0x37, 0x54, 0x87, 0x12, 0x84, 0xf9, 0x07, 0x4f,
+ 0xe4, 0x23, 0x40, 0xc3, 0x43, 0x84, 0x37, 0x86, 0xd3, 0x9d, 0x95, 0x1c,
+ 0xe4, 0x8a, 0x66, 0x02, 0x09, 0xe2, 0x3d, 0xce, 0x2c, 0xc6, 0x02, 0x6a,
+ 0xd4, 0x65, 0x61, 0xff, 0x85, 0x6f, 0x88, 0x63, 0xba, 0x31, 0x62, 0x1e,
+ 0xb7, 0x95, 0xe9, 0x08, 0x3c, 0xe9, 0x35, 0xde, 0xfd, 0x65, 0x92, 0xb8,
+ 0x9e, 0x71, 0xa4, 0xcd, 0x47, 0xfd, 0x04, 0x26, 0xb9, 0x78, 0xbf, 0x05,
+ 0x0d, 0xfc, 0x00, 0x84, 0x08, 0xfc, 0xc4, 0x4b, 0xea, 0xf5, 0x97, 0x68,
+ 0x0d, 0x97, 0xd7, 0xff, 0x4f, 0x92, 0x82, 0xd7, 0xbb, 0xef, 0xb7, 0x67,
+ 0x8e, 0x72, 0x54, 0xe8, 0xc5, 0x9e, 0xfd, 0xd8, 0x38, 0xe9, 0xbe, 0x19,
+ 0x37, 0x5b, 0x36, 0x8b, 0xbf, 0x49, 0xa1, 0x59, 0x3a, 0x9d, 0xad, 0x92,
+ 0x08, 0x0b, 0xe3, 0xa4, 0xa4, 0x7d, 0xd3, 0x70, 0xc0, 0xb8, 0xfb, 0xc7,
+ 0xda, 0xd3, 0x19, 0x86, 0x37, 0x9a, 0xcd, 0xab, 0x30, 0x96, 0xab, 0xa4,
+ 0xa2, 0x31, 0xa0, 0x38, 0xfb, 0xbf, 0x85, 0xd3, 0x24, 0x39, 0xed, 0xbf,
+ 0xe1, 0x31, 0xed, 0x6c, 0x39, 0xc1, 0xe5, 0x05, 0x2e, 0x12, 0x30, 0x36,
+ 0x73, 0x5d, 0x62, 0xf3, 0x82, 0xaf, 0x38, 0xc8, 0xca, 0xfa, 0xa1, 0x99,
+ 0x57, 0x3c, 0xe1, 0xc1, 0x7b, 0x05, 0x0b, 0xcc, 0x2e, 0xa9, 0x10, 0xc8,
+ 0x68, 0xbd, 0x27, 0xb6, 0x19, 0x9c, 0xd2, 0xad, 0xb3, 0x1f, 0xca, 0x35,
+ 0x6e, 0x84, 0x23, 0xa1, 0xe9, 0xa4, 0x4c, 0xab, 0x19, 0x09, 0x79, 0x6e,
+ 0x3c, 0x7b, 0x74, 0xfc, 0x33, 0x05, 0xcf, 0xa4, 0x2e, 0xeb, 0x55, 0x60,
+ 0x05, 0xc7, 0xcf, 0x3f, 0x92, 0xac, 0x2d, 0x69, 0x0b, 0x19, 0x16, 0x79,
+ 0x75, 0x02, 0x03, 0x01, 0x00, 0x01
+};
+
+static unsigned int public_key_len = 270;
+
+/**
+ * lib_asn1_pkey() - unit test for asn1 decoder function
+ * with RSA public key parser
+ *
+ * @uts: unit test state
+ * Return: 0 = success, 1 = failure
+ */
+static int lib_asn1_pkey(struct unit_test_state *uts)
+{
+ struct rsa_key pkey;
+ int ret;
+
+ ret = rsa_parse_pub_key(&pkey, public_key, public_key_len);
+
+ ut_assertf(ret == 0, "decoding failed (%d)\n", ret);
+ ut_assertf(pkey.n_sz == 257, "public key modulus size doesn't match\n");
+ ut_assertf(pkey.e_sz == 3, "public key exponent size doesn't match\n");
+ ut_assertf(pkey.e[0] == 0x01 && pkey.e[1] == 0x00 && pkey.e[2] == 0x01,
+ "public key exponent doesn't match\n");
+
+ return CMD_RET_SUCCESS;
+}
+
+LIB_TEST(lib_asn1_pkey, 0);
+#endif /* CONFIG_RSA_PUBLIC_KEY_PARSER */
diff --git a/tools/Makefile b/tools/Makefile
index 24581adccd..345bc84e48 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -207,6 +207,9 @@ endif
hostprogs-$(CONFIG_MIPS) += mips-relocs
+hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler
+HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
+
# We build some files with extra pedantic flags to try to minimize things
# that won't build on some weird host compiler -- though there are lots of
# exceptions for files that aren't complaint.
diff --git a/tools/asn1_compiler.c b/tools/asn1_compiler.c
new file mode 100644
index 0000000000..adabd41452
--- /dev/null
+++ b/tools/asn1_compiler.c
@@ -0,0 +1,1611 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Simplified ASN.1 notation parser
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <linux/asn1_ber_bytecode.h>
+
+enum token_type {
+ DIRECTIVE_ABSENT,
+ DIRECTIVE_ALL,
+ DIRECTIVE_ANY,
+ DIRECTIVE_APPLICATION,
+ DIRECTIVE_AUTOMATIC,
+ DIRECTIVE_BEGIN,
+ DIRECTIVE_BIT,
+ DIRECTIVE_BMPString,
+ DIRECTIVE_BOOLEAN,
+ DIRECTIVE_BY,
+ DIRECTIVE_CHARACTER,
+ DIRECTIVE_CHOICE,
+ DIRECTIVE_CLASS,
+ DIRECTIVE_COMPONENT,
+ DIRECTIVE_COMPONENTS,
+ DIRECTIVE_CONSTRAINED,
+ DIRECTIVE_CONTAINING,
+ DIRECTIVE_DEFAULT,
+ DIRECTIVE_DEFINED,
+ DIRECTIVE_DEFINITIONS,
+ DIRECTIVE_EMBEDDED,
+ DIRECTIVE_ENCODED,
+ DIRECTIVE_ENCODING_CONTROL,
+ DIRECTIVE_END,
+ DIRECTIVE_ENUMERATED,
+ DIRECTIVE_EXCEPT,
+ DIRECTIVE_EXPLICIT,
+ DIRECTIVE_EXPORTS,
+ DIRECTIVE_EXTENSIBILITY,
+ DIRECTIVE_EXTERNAL,
+ DIRECTIVE_FALSE,
+ DIRECTIVE_FROM,
+ DIRECTIVE_GeneralString,
+ DIRECTIVE_GeneralizedTime,
+ DIRECTIVE_GraphicString,
+ DIRECTIVE_IA5String,
+ DIRECTIVE_IDENTIFIER,
+ DIRECTIVE_IMPLICIT,
+ DIRECTIVE_IMPLIED,
+ DIRECTIVE_IMPORTS,
+ DIRECTIVE_INCLUDES,
+ DIRECTIVE_INSTANCE,
+ DIRECTIVE_INSTRUCTIONS,
+ DIRECTIVE_INTEGER,
+ DIRECTIVE_INTERSECTION,
+ DIRECTIVE_ISO646String,
+ DIRECTIVE_MAX,
+ DIRECTIVE_MIN,
+ DIRECTIVE_MINUS_INFINITY,
+ DIRECTIVE_NULL,
+ DIRECTIVE_NumericString,
+ DIRECTIVE_OBJECT,
+ DIRECTIVE_OCTET,
+ DIRECTIVE_OF,
+ DIRECTIVE_OPTIONAL,
+ DIRECTIVE_ObjectDescriptor,
+ DIRECTIVE_PATTERN,
+ DIRECTIVE_PDV,
+ DIRECTIVE_PLUS_INFINITY,
+ DIRECTIVE_PRESENT,
+ DIRECTIVE_PRIVATE,
+ DIRECTIVE_PrintableString,
+ DIRECTIVE_REAL,
+ DIRECTIVE_RELATIVE_OID,
+ DIRECTIVE_SEQUENCE,
+ DIRECTIVE_SET,
+ DIRECTIVE_SIZE,
+ DIRECTIVE_STRING,
+ DIRECTIVE_SYNTAX,
+ DIRECTIVE_T61String,
+ DIRECTIVE_TAGS,
+ DIRECTIVE_TRUE,
+ DIRECTIVE_TeletexString,
+ DIRECTIVE_UNION,
+ DIRECTIVE_UNIQUE,
+ DIRECTIVE_UNIVERSAL,
+ DIRECTIVE_UTCTime,
+ DIRECTIVE_UTF8String,
+ DIRECTIVE_UniversalString,
+ DIRECTIVE_VideotexString,
+ DIRECTIVE_VisibleString,
+ DIRECTIVE_WITH,
+ NR__DIRECTIVES,
+ TOKEN_ASSIGNMENT = NR__DIRECTIVES,
+ TOKEN_OPEN_CURLY,
+ TOKEN_CLOSE_CURLY,
+ TOKEN_OPEN_SQUARE,
+ TOKEN_CLOSE_SQUARE,
+ TOKEN_OPEN_ACTION,
+ TOKEN_CLOSE_ACTION,
+ TOKEN_COMMA,
+ TOKEN_NUMBER,
+ TOKEN_TYPE_NAME,
+ TOKEN_ELEMENT_NAME,
+ NR__TOKENS
+};
+
+static const unsigned char token_to_tag[NR__TOKENS] = {
+ /* EOC goes first */
+ [DIRECTIVE_BOOLEAN] = ASN1_BOOL,
+ [DIRECTIVE_INTEGER] = ASN1_INT,
+ [DIRECTIVE_BIT] = ASN1_BTS,
+ [DIRECTIVE_OCTET] = ASN1_OTS,
+ [DIRECTIVE_NULL] = ASN1_NULL,
+ [DIRECTIVE_OBJECT] = ASN1_OID,
+ [DIRECTIVE_ObjectDescriptor] = ASN1_ODE,
+ [DIRECTIVE_EXTERNAL] = ASN1_EXT,
+ [DIRECTIVE_REAL] = ASN1_REAL,
+ [DIRECTIVE_ENUMERATED] = ASN1_ENUM,
+ [DIRECTIVE_EMBEDDED] = 0,
+ [DIRECTIVE_UTF8String] = ASN1_UTF8STR,
+ [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID,
+ /* 14 */
+ /* 15 */
+ [DIRECTIVE_SEQUENCE] = ASN1_SEQ,
+ [DIRECTIVE_SET] = ASN1_SET,
+ [DIRECTIVE_NumericString] = ASN1_NUMSTR,
+ [DIRECTIVE_PrintableString] = ASN1_PRNSTR,
+ [DIRECTIVE_T61String] = ASN1_TEXSTR,
+ [DIRECTIVE_TeletexString] = ASN1_TEXSTR,
+ [DIRECTIVE_VideotexString] = ASN1_VIDSTR,
+ [DIRECTIVE_IA5String] = ASN1_IA5STR,
+ [DIRECTIVE_UTCTime] = ASN1_UNITIM,
+ [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM,
+ [DIRECTIVE_GraphicString] = ASN1_GRASTR,
+ [DIRECTIVE_VisibleString] = ASN1_VISSTR,
+ [DIRECTIVE_GeneralString] = ASN1_GENSTR,
+ [DIRECTIVE_UniversalString] = ASN1_UNITIM,
+ [DIRECTIVE_CHARACTER] = ASN1_CHRSTR,
+ [DIRECTIVE_BMPString] = ASN1_BMPSTR,
+};
+
+static const char asn1_classes[4][5] = {
+ [ASN1_UNIV] = "UNIV",
+ [ASN1_APPL] = "APPL",
+ [ASN1_CONT] = "CONT",
+ [ASN1_PRIV] = "PRIV"
+};
+
+static const char asn1_methods[2][5] = {
+ [ASN1_UNIV] = "PRIM",
+ [ASN1_APPL] = "CONS"
+};
+
+static const char *const asn1_universal_tags[32] = {
+ "EOC",
+ "BOOL",
+ "INT",
+ "BTS",
+ "OTS",
+ "NULL",
+ "OID",
+ "ODE",
+ "EXT",
+ "REAL",
+ "ENUM",
+ "EPDV",
+ "UTF8STR",
+ "RELOID",
+ NULL, /* 14 */
+ NULL, /* 15 */
+ "SEQ",
+ "SET",
+ "NUMSTR",
+ "PRNSTR",
+ "TEXSTR",
+ "VIDSTR",
+ "IA5STR",
+ "UNITIM",
+ "GENTIM",
+ "GRASTR",
+ "VISSTR",
+ "GENSTR",
+ "UNISTR",
+ "CHRSTR",
+ "BMPSTR",
+ NULL /* 31 */
+};
+
+static const char *filename;
+static const char *grammar_name;
+static const char *outputname;
+static const char *headername;
+
+static const char *const directives[NR__DIRECTIVES] = {
+#define _(X) [DIRECTIVE_##X] = #X
+ _(ABSENT),
+ _(ALL),
+ _(ANY),
+ _(APPLICATION),
+ _(AUTOMATIC),
+ _(BEGIN),
+ _(BIT),
+ _(BMPString),
+ _(BOOLEAN),
+ _(BY),
+ _(CHARACTER),
+ _(CHOICE),
+ _(CLASS),
+ _(COMPONENT),
+ _(COMPONENTS),
+ _(CONSTRAINED),
+ _(CONTAINING),
+ _(DEFAULT),
+ _(DEFINED),
+ _(DEFINITIONS),
+ _(EMBEDDED),
+ _(ENCODED),
+ [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
+ _(END),
+ _(ENUMERATED),
+ _(EXCEPT),
+ _(EXPLICIT),
+ _(EXPORTS),
+ _(EXTENSIBILITY),
+ _(EXTERNAL),
+ _(FALSE),
+ _(FROM),
+ _(GeneralString),
+ _(GeneralizedTime),
+ _(GraphicString),
+ _(IA5String),
+ _(IDENTIFIER),
+ _(IMPLICIT),
+ _(IMPLIED),
+ _(IMPORTS),
+ _(INCLUDES),
+ _(INSTANCE),
+ _(INSTRUCTIONS),
+ _(INTEGER),
+ _(INTERSECTION),
+ _(ISO646String),
+ _(MAX),
+ _(MIN),
+ [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
+ [DIRECTIVE_NULL] = "NULL",
+ _(NumericString),
+ _(OBJECT),
+ _(OCTET),
+ _(OF),
+ _(OPTIONAL),
+ _(ObjectDescriptor),
+ _(PATTERN),
+ _(PDV),
+ [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
+ _(PRESENT),
+ _(PRIVATE),
+ _(PrintableString),
+ _(REAL),
+ [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
+ _(SEQUENCE),
+ _(SET),
+ _(SIZE),
+ _(STRING),
+ _(SYNTAX),
+ _(T61String),
+ _(TAGS),
+ _(TRUE),
+ _(TeletexString),
+ _(UNION),
+ _(UNIQUE),
+ _(UNIVERSAL),
+ _(UTCTime),
+ _(UTF8String),
+ _(UniversalString),
+ _(VideotexString),
+ _(VisibleString),
+ _(WITH)
+};
+
+struct action {
+ struct action *next;
+ char *name;
+ unsigned char index;
+};
+
+static struct action *action_list;
+static unsigned nr_actions;
+
+struct token {
+ unsigned short line;
+ enum token_type token_type : 8;
+ unsigned char size;
+ struct action *action;
+ char *content;
+ struct type *type;
+};
+
+static struct token *token_list;
+static unsigned nr_tokens;
+static bool verbose_opt;
+static bool debug_opt;
+
+#define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)
+#define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)
+
+static int directive_compare(const void *_key, const void *_pdir)
+{
+ const struct token *token = _key;
+ const char *const *pdir = _pdir, *dir = *pdir;
+ size_t dlen, clen;
+ int val;
+
+ dlen = strlen(dir);
+ clen = (dlen < token->size) ? dlen : token->size;
+
+ //debug("cmp(%s,%s) = ", token->content, dir);
+
+ val = memcmp(token->content, dir, clen);
+ if (val != 0) {
+ //debug("%d [cmp]\n", val);
+ return val;
+ }
+
+ if (dlen == token->size) {
+ //debug("0\n");
+ return 0;
+ }
+ //debug("%d\n", (int)dlen - (int)token->size);
+ return dlen - token->size; /* shorter -> negative */
+}
+
+/*
+ * Tokenise an ASN.1 grammar
+ */
+static void tokenise(char *buffer, char *end)
+{
+ struct token *tokens;
+ char *line, *nl, *start, *p, *q;
+ unsigned tix, lineno;
+
+ /* Assume we're going to have half as many tokens as we have
+ * characters
+ */
+ token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
+ if (!tokens) {
+ perror(NULL);
+ exit(1);
+ }
+ tix = 0;
+
+ lineno = 0;
+ while (buffer < end) {
+ /* First of all, break out a line */
+ lineno++;
+ line = buffer;
+ nl = memchr(line, '\n', end - buffer);
+ if (!nl) {
+ buffer = nl = end;
+ } else {
+ buffer = nl + 1;
+ *nl = '\0';
+ }
+
+ /* Remove "--" comments */
+ p = line;
+ next_comment:
+ while ((p = memchr(p, '-', nl - p))) {
+ if (p[1] == '-') {
+ /* Found a comment; see if there's a terminator */
+ q = p + 2;
+ while ((q = memchr(q, '-', nl - q))) {
+ if (q[1] == '-') {
+ /* There is - excise the comment */
+ q += 2;
+ memmove(p, q, nl - q);
+ goto next_comment;
+ }
+ q++;
+ }
+ *p = '\0';
+ nl = p;
+ break;
+ } else {
+ p++;
+ }
+ }
+
+ p = line;
+ while (p < nl) {
+ /* Skip white space */
+ while (p < nl && isspace(*p))
+ *(p++) = 0;
+ if (p >= nl)
+ break;
+
+ tokens[tix].line = lineno;
+ start = p;
+
+ /* Handle string tokens */
+ if (isalpha(*p)) {
+ const char **dir;
+
+ /* Can be a directive, type name or element
+ * name. Find the end of the name.
+ */
+ q = p + 1;
+ while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
+ q++;
+ tokens[tix].size = q - p;
+ p = q;
+
+ tokens[tix].content = malloc(tokens[tix].size + 1);
+ if (!tokens[tix].content) {
+ perror(NULL);
+ exit(1);
+ }
+ memcpy(tokens[tix].content, start, tokens[tix].size);
+ tokens[tix].content[tokens[tix].size] = 0;
+
+ /* If it begins with a lowercase letter then
+ * it's an element name
+ */
+ if (islower(tokens[tix].content[0])) {
+ tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
+ continue;
+ }
+
+ /* Otherwise we need to search the directive
+ * table
+ */
+ dir = bsearch(&tokens[tix], directives,
+ sizeof(directives) / sizeof(directives[1]),
+ sizeof(directives[1]),
+ directive_compare);
+ if (dir) {
+ tokens[tix++].token_type = dir - directives;
+ continue;
+ }
+
+ tokens[tix++].token_type = TOKEN_TYPE_NAME;
+ continue;
+ }
+
+ /* Handle numbers */
+ if (isdigit(*p)) {
+ /* Find the end of the number */
+ q = p + 1;
+ while (q < nl && (isdigit(*q)))
+ q++;
+ tokens[tix].size = q - p;
+ p = q;
+ tokens[tix].content = malloc(tokens[tix].size + 1);
+ if (!tokens[tix].content) {
+ perror(NULL);
+ exit(1);
+ }
+ memcpy(tokens[tix].content, start, tokens[tix].size);
+ tokens[tix].content[tokens[tix].size] = 0;
+ tokens[tix++].token_type = TOKEN_NUMBER;
+ continue;
+ }
+
+ if (nl - p >= 3) {
+ if (memcmp(p, "::=", 3) == 0) {
+ p += 3;
+ tokens[tix].size = 3;
+ tokens[tix].content = "::=";
+ tokens[tix++].token_type = TOKEN_ASSIGNMENT;
+ continue;
+ }
+ }
+
+ if (nl - p >= 2) {
+ if (memcmp(p, "({", 2) == 0) {
+ p += 2;
+ tokens[tix].size = 2;
+ tokens[tix].content = "({";
+ tokens[tix++].token_type = TOKEN_OPEN_ACTION;
+ continue;
+ }
+ if (memcmp(p, "})", 2) == 0) {
+ p += 2;
+ tokens[tix].size = 2;
+ tokens[tix].content = "})";
+ tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
+ continue;
+ }
+ }
+
+ if (nl - p >= 1) {
+ tokens[tix].size = 1;
+ switch (*p) {
+ case '{':
+ p += 1;
+ tokens[tix].content = "{";
+ tokens[tix++].token_type = TOKEN_OPEN_CURLY;
+ continue;
+ case '}':
+ p += 1;
+ tokens[tix].content = "}";
+ tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
+ continue;
+ case '[':
+ p += 1;
+ tokens[tix].content = "[";
+ tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
+ continue;
+ case ']':
+ p += 1;
+ tokens[tix].content = "]";
+ tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
+ continue;
+ case ',':
+ p += 1;
+ tokens[tix].content = ",";
+ tokens[tix++].token_type = TOKEN_COMMA;
+ continue;
+ default:
+ break;
+ }
+ }
+
+ fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
+ filename, lineno, *p);
+ exit(1);
+ }
+ }
+
+ nr_tokens = tix;
+ verbose("Extracted %u tokens\n", nr_tokens);
+
+#if 0
+ {
+ int n;
+ for (n = 0; n < nr_tokens; n++)
+ debug("Token %3u: '%s'\n", n, token_list[n].content);
+ }
+#endif
+}
+
+static void build_type_list(void);
+static void parse(void);
+static void dump_elements(void);
+static void render(FILE *out, FILE *hdr);
+
+/*
+ *
+ */
+int main(int argc, char **argv)
+{
+ struct stat st;
+ ssize_t readlen;
+ FILE *out, *hdr;
+ char *buffer, *p;
+ char *kbuild_verbose;
+ int fd;
+
+ kbuild_verbose = getenv("KBUILD_VERBOSE");
+ if (kbuild_verbose)
+ verbose_opt = atoi(kbuild_verbose);
+
+ while (argc > 4) {
+ if (strcmp(argv[1], "-v") == 0)
+ verbose_opt = true;
+ else if (strcmp(argv[1], "-d") == 0)
+ debug_opt = true;
+ else
+ break;
+ memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *));
+ argc--;
+ }
+
+ if (argc != 4) {
+ fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n",
+ argv[0]);
+ exit(2);
+ }
+
+ filename = argv[1];
+ outputname = argv[2];
+ headername = argv[3];
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ if (fstat(fd, &st) < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ if (!(buffer = malloc(st.st_size + 1))) {
+ perror(NULL);
+ exit(1);
+ }
+
+ if ((readlen = read(fd, buffer, st.st_size)) < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ if (close(fd) < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ if (readlen != st.st_size) {
+ fprintf(stderr, "%s: Short read\n", filename);
+ exit(1);
+ }
+
+ p = strrchr(argv[1], '/');
+ p = p ? p + 1 : argv[1];
+ grammar_name = strdup(p);
+ if (!p) {
+ perror(NULL);
+ exit(1);
+ }
+ p = strchr(grammar_name, '.');
+ if (p)
+ *p = '\0';
+
+ buffer[readlen] = 0;
+ tokenise(buffer, buffer + readlen);
+ build_type_list();
+ parse();
+ dump_elements();
+
+ out = fopen(outputname, "w");
+ if (!out) {
+ perror(outputname);
+ exit(1);
+ }
+
+ hdr = fopen(headername, "w");
+ if (!hdr) {
+ perror(headername);
+ exit(1);
+ }
+
+ render(out, hdr);
+
+ if (fclose(out) < 0) {
+ perror(outputname);
+ exit(1);
+ }
+
+ if (fclose(hdr) < 0) {
+ perror(headername);
+ exit(1);
+ }
+
+ return 0;
+}
+
+enum compound {
+ NOT_COMPOUND,
+ SET,
+ SET_OF,
+ SEQUENCE,
+ SEQUENCE_OF,
+ CHOICE,
+ ANY,
+ TYPE_REF,
+ TAG_OVERRIDE
+};
+
+struct element {
+ struct type *type_def;
+ struct token *name;
+ struct token *type;
+ struct action *action;
+ struct element *children;
+ struct element *next;
+ struct element *render_next;
+ struct element *list_next;
+ uint8_t n_elements;
+ enum compound compound : 8;
+ enum asn1_class class : 8;
+ enum asn1_method method : 8;
+ uint8_t tag;
+ unsigned entry_index;
+ unsigned flags;
+#define ELEMENT_IMPLICIT 0x0001
+#define ELEMENT_EXPLICIT 0x0002
+#define ELEMENT_TAG_SPECIFIED 0x0004
+#define ELEMENT_RENDERED 0x0008
+#define ELEMENT_SKIPPABLE 0x0010
+#define ELEMENT_CONDITIONAL 0x0020
+};
+
+struct type {
+ struct token *name;
+ struct token *def;
+ struct element *element;
+ unsigned ref_count;
+ unsigned flags;
+#define TYPE_STOP_MARKER 0x0001
+#define TYPE_BEGIN 0x0002
+};
+
+static struct type *type_list;
+static struct type **type_index;
+static unsigned nr_types;
+
+static int type_index_compare(const void *_a, const void *_b)
+{
+ const struct type *const *a = _a, *const *b = _b;
+
+ if ((*a)->name->size != (*b)->name->size)
+ return (*a)->name->size - (*b)->name->size;
+ else
+ return memcmp((*a)->name->content, (*b)->name->content,
+ (*a)->name->size);
+}
+
+static int type_finder(const void *_key, const void *_ti)
+{
+ const struct token *token = _key;
+ const struct type *const *ti = _ti;
+ const struct type *type = *ti;
+
+ if (token->size != type->name->size)
+ return token->size - type->name->size;
+ else
+ return memcmp(token->content, type->name->content,
+ token->size);
+}
+
+/*
+ * Build up a list of types and a sorted index to that list.
+ */
+static void build_type_list(void)
+{
+ struct type *types;
+ unsigned nr, t, n;
+
+ nr = 0;
+ for (n = 0; n < nr_tokens - 1; n++)
+ if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
+ token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
+ nr++;
+
+ if (nr == 0) {
+ fprintf(stderr, "%s: No defined types\n", filename);
+ exit(1);
+ }
+
+ nr_types = nr;
+ types = type_list = calloc(nr + 1, sizeof(type_list[0]));
+ if (!type_list) {
+ perror(NULL);
+ exit(1);
+ }
+ type_index = calloc(nr, sizeof(type_index[0]));
+ if (!type_index) {
+ perror(NULL);
+ exit(1);
+ }
+
+ t = 0;
+ types[t].flags |= TYPE_BEGIN;
+ for (n = 0; n < nr_tokens - 1; n++) {
+ if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
+ token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
+ types[t].name = &token_list[n];
+ type_index[t] = &types[t];
+ t++;
+ }
+ }
+ types[t].name = &token_list[n + 1];
+ types[t].flags |= TYPE_STOP_MARKER;
+
+ qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
+
+ verbose("Extracted %u types\n", nr_types);
+#if 0
+ for (n = 0; n < nr_types; n++) {
+ struct type *type = type_index[n];
+ debug("- %*.*s\n", type->name->content);
+ }
+#endif
+}
+
+static struct element *parse_type(struct token **_cursor, struct token *stop,
+ struct token *name);
+
+/*
+ * Parse the token stream
+ */
+static void parse(void)
+{
+ struct token *cursor;
+ struct type *type;
+
+ /* Parse one type definition statement at a time */
+ type = type_list;
+ do {
+ cursor = type->name;
+
+ if (cursor[0].token_type != TOKEN_TYPE_NAME ||
+ cursor[1].token_type != TOKEN_ASSIGNMENT)
+ abort();
+ cursor += 2;
+
+ type->element = parse_type(&cursor, type[1].name, NULL);
+ type->element->type_def = type;
+
+ if (cursor != type[1].name) {
+ fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+ }
+
+ } while (type++, !(type->flags & TYPE_STOP_MARKER));
+
+ verbose("Extracted %u actions\n", nr_actions);
+}
+
+static struct element *element_list;
+
+static struct element *alloc_elem(struct token *type)
+{
+ struct element *e = calloc(1, sizeof(*e));
+ if (!e) {
+ perror(NULL);
+ exit(1);
+ }
+ e->list_next = element_list;
+ element_list = e;
+ return e;
+}
+
+static struct element *parse_compound(struct token **_cursor, struct token *end,
+ int alternates);
+
+/*
+ * Parse one type definition statement
+ */
+static struct element *parse_type(struct token **_cursor, struct token *end,
+ struct token *name)
+{
+ struct element *top, *element;
+ struct action *action, **ppaction;
+ struct token *cursor = *_cursor;
+ struct type **ref;
+ char *p;
+ int labelled = 0, implicit = 0;
+
+ top = element = alloc_elem(cursor);
+ element->class = ASN1_UNIV;
+ element->method = ASN1_PRIM;
+ element->tag = token_to_tag[cursor->token_type];
+ element->name = name;
+
+ /* Extract the tag value if one given */
+ if (cursor->token_type == TOKEN_OPEN_SQUARE) {
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ switch (cursor->token_type) {
+ case DIRECTIVE_UNIVERSAL:
+ element->class = ASN1_UNIV;
+ cursor++;
+ break;
+ case DIRECTIVE_APPLICATION:
+ element->class = ASN1_APPL;
+ cursor++;
+ break;
+ case TOKEN_NUMBER:
+ element->class = ASN1_CONT;
+ break;
+ case DIRECTIVE_PRIVATE:
+ element->class = ASN1_PRIV;
+ cursor++;
+ break;
+ default:
+ fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+ }
+
+ if (cursor >= end)
+ goto overrun_error;
+ if (cursor->token_type != TOKEN_NUMBER) {
+ fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+ }
+
+ element->tag &= ~0x1f;
+ element->tag |= strtoul(cursor->content, &p, 10);
+ element->flags |= ELEMENT_TAG_SPECIFIED;
+ if (p - cursor->content != cursor->size)
+ abort();
+ cursor++;
+
+ if (cursor >= end)
+ goto overrun_error;
+ if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
+ fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+ }
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ labelled = 1;
+ }
+
+ /* Handle implicit and explicit markers */
+ if (cursor->token_type == DIRECTIVE_IMPLICIT) {
+ element->flags |= ELEMENT_IMPLICIT;
+ implicit = 1;
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
+ element->flags |= ELEMENT_EXPLICIT;
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ }
+
+ if (labelled) {
+ if (!implicit)
+ element->method |= ASN1_CONS;
+ element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
+ element->children = alloc_elem(cursor);
+ element = element->children;
+ element->class = ASN1_UNIV;
+ element->method = ASN1_PRIM;
+ element->tag = token_to_tag[cursor->token_type];
+ element->name = name;
+ }
+
+ /* Extract the type we're expecting here */
+ element->type = cursor;
+ switch (cursor->token_type) {
+ case DIRECTIVE_ANY:
+ element->compound = ANY;
+ cursor++;
+ break;
+
+ case DIRECTIVE_NULL:
+ case DIRECTIVE_BOOLEAN:
+ case DIRECTIVE_ENUMERATED:
+ case DIRECTIVE_INTEGER:
+ element->compound = NOT_COMPOUND;
+ cursor++;
+ break;
+
+ case DIRECTIVE_EXTERNAL:
+ element->method = ASN1_CONS;
+
+ case DIRECTIVE_BMPString:
+ case DIRECTIVE_GeneralString:
+ case DIRECTIVE_GraphicString:
+ case DIRECTIVE_IA5String:
+ case DIRECTIVE_ISO646String:
+ case DIRECTIVE_NumericString:
+ case DIRECTIVE_PrintableString:
+ case DIRECTIVE_T61String:
+ case DIRECTIVE_TeletexString:
+ case DIRECTIVE_UniversalString:
+ case DIRECTIVE_UTF8String:
+ case DIRECTIVE_VideotexString:
+ case DIRECTIVE_VisibleString:
+ case DIRECTIVE_ObjectDescriptor:
+ case DIRECTIVE_GeneralizedTime:
+ case DIRECTIVE_UTCTime:
+ element->compound = NOT_COMPOUND;
+ cursor++;
+ break;
+
+ case DIRECTIVE_BIT:
+ case DIRECTIVE_OCTET:
+ element->compound = NOT_COMPOUND;
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ if (cursor->token_type != DIRECTIVE_STRING)
+ goto parse_error;
+ cursor++;
+ break;
+
+ case DIRECTIVE_OBJECT:
+ element->compound = NOT_COMPOUND;
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ if (cursor->token_type != DIRECTIVE_IDENTIFIER)
+ goto parse_error;
+ cursor++;
+ break;
+
+ case TOKEN_TYPE_NAME:
+ element->compound = TYPE_REF;
+ ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
+ type_finder);
+ if (!ref) {
+ fprintf(stderr, "%s:%d: Type '%s' undefined\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+ }
+ cursor->type = *ref;
+ (*ref)->ref_count++;
+ cursor++;
+ break;
+
+ case DIRECTIVE_CHOICE:
+ element->compound = CHOICE;
+ cursor++;
+ element->children = parse_compound(&cursor, end, 1);
+ break;
+
+ case DIRECTIVE_SEQUENCE:
+ element->compound = SEQUENCE;
+ element->method = ASN1_CONS;
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ if (cursor->token_type == DIRECTIVE_OF) {
+ element->compound = SEQUENCE_OF;
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ element->children = parse_type(&cursor, end, NULL);
+ } else {
+ element->children = parse_compound(&cursor, end, 0);
+ }
+ break;
+
+ case DIRECTIVE_SET:
+ element->compound = SET;
+ element->method = ASN1_CONS;
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ if (cursor->token_type == DIRECTIVE_OF) {
+ element->compound = SET_OF;
+ cursor++;
+ if (cursor >= end)
+ goto parse_error;
+ element->children = parse_type(&cursor, end, NULL);
+ } else {
+ element->children = parse_compound(&cursor, end, 1);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+ }
+
+ /* Handle elements that are optional */
+ if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
+ cursor->token_type == DIRECTIVE_DEFAULT)
+ ) {
+ cursor++;
+ top->flags |= ELEMENT_SKIPPABLE;
+ }
+
+ if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ if (cursor->token_type != TOKEN_ELEMENT_NAME) {
+ fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+ }
+
+ action = malloc(sizeof(struct action));
+ if (!action) {
+ perror(NULL);
+ exit(1);
+ }
+ action->index = 0;
+ action->name = cursor->content;
+
+ for (ppaction = &action_list;
+ *ppaction;
+ ppaction = &(*ppaction)->next
+ ) {
+ int cmp = strcmp(action->name, (*ppaction)->name);
+ if (cmp == 0) {
+ free(action);
+ action = *ppaction;
+ goto found;
+ }
+ if (cmp < 0) {
+ action->next = *ppaction;
+ *ppaction = action;
+ nr_actions++;
+ goto found;
+ }
+ }
+ action->next = NULL;
+ *ppaction = action;
+ nr_actions++;
+ found:
+
+ element->action = action;
+ cursor->action = action;
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ if (cursor->token_type != TOKEN_CLOSE_ACTION) {
+ fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+ }
+ cursor++;
+ }
+
+ *_cursor = cursor;
+ return top;
+
+parse_error:
+ fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+
+overrun_error:
+ fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
+ exit(1);
+}
+
+/*
+ * Parse a compound type list
+ */
+static struct element *parse_compound(struct token **_cursor, struct token *end,
+ int alternates)
+{
+ struct element *children, **child_p = &children, *element;
+ struct token *cursor = *_cursor, *name;
+
+ if (cursor->token_type != TOKEN_OPEN_CURLY) {
+ fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+ }
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+
+ if (cursor->token_type == TOKEN_OPEN_CURLY) {
+ fprintf(stderr, "%s:%d: Empty compound\n",
+ filename, cursor->line);
+ exit(1);
+ }
+
+ for (;;) {
+ name = NULL;
+ if (cursor->token_type == TOKEN_ELEMENT_NAME) {
+ name = cursor;
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ }
+
+ element = parse_type(&cursor, end, name);
+ if (alternates)
+ element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
+
+ *child_p = element;
+ child_p = &element->next;
+
+ if (cursor >= end)
+ goto overrun_error;
+ if (cursor->token_type != TOKEN_COMMA)
+ break;
+ cursor++;
+ if (cursor >= end)
+ goto overrun_error;
+ }
+
+ children->flags &= ~ELEMENT_CONDITIONAL;
+
+ if (cursor->token_type != TOKEN_CLOSE_CURLY) {
+ fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
+ filename, cursor->line, cursor->content);
+ exit(1);
+ }
+ cursor++;
+
+ *_cursor = cursor;
+ return children;
+
+overrun_error:
+ fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
+ exit(1);
+}
+
+static void dump_element(const struct element *e, int level)
+{
+ const struct element *c;
+ const struct type *t = e->type_def;
+ const char *name = e->name ? e->name->content : ".";
+ const char *tname = t && t->name ? t->name->content : ".";
+ char tag[32];
+
+ if (e->class == 0 && e->method == 0 && e->tag == 0)
+ strcpy(tag, "<...>");
+ else if (e->class == ASN1_UNIV)
+ sprintf(tag, "%s %s %s",
+ asn1_classes[e->class],
+ asn1_methods[e->method],
+ asn1_universal_tags[e->tag]);
+ else
+ sprintf(tag, "%s %s %u",
+ asn1_classes[e->class],
+ asn1_methods[e->method],
+ e->tag);
+
+ printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
+ e->flags & ELEMENT_IMPLICIT ? 'I' : '-',
+ e->flags & ELEMENT_EXPLICIT ? 'E' : '-',
+ e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-',
+ e->flags & ELEMENT_SKIPPABLE ? 'S' : '-',
+ e->flags & ELEMENT_CONDITIONAL ? 'C' : '-',
+ "-tTqQcaro"[e->compound],
+ level, "",
+ tag,
+ tname,
+ name,
+ e->action ? e->action->name : "");
+ if (e->compound == TYPE_REF)
+ dump_element(e->type->type->element, level + 3);
+ else
+ for (c = e->children; c; c = c->next)
+ dump_element(c, level + 3);
+}
+
+static void dump_elements(void)
+{
+ if (debug_opt)
+ dump_element(type_list[0].element, 0);
+}
+
+static void render_element(FILE *out, struct element *e, struct element *tag);
+static void render_out_of_line_list(FILE *out);
+
+static int nr_entries;
+static int render_depth = 1;
+static struct element *render_list, **render_list_p = &render_list;
+
+__attribute__((format(printf, 2, 3)))
+static void render_opcode(FILE *out, const char *fmt, ...)
+{
+ va_list va;
+
+ if (out) {
+ fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
+ va_start(va, fmt);
+ vfprintf(out, fmt, va);
+ va_end(va);
+ }
+ nr_entries++;
+}
+
+__attribute__((format(printf, 2, 3)))
+static void render_more(FILE *out, const char *fmt, ...)
+{
+ va_list va;
+
+ if (out) {
+ va_start(va, fmt);
+ vfprintf(out, fmt, va);
+ va_end(va);
+ }
+}
+
+/*
+ * Render the grammar into a state machine definition.
+ */
+static void render(FILE *out, FILE *hdr)
+{
+ struct element *e;
+ struct action *action;
+ struct type *root;
+ int index;
+
+ fprintf(hdr, "/*\n");
+ fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n");
+ fprintf(hdr, " *\n");
+ fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
+ fprintf(hdr, " */\n");
+ fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
+ fprintf(hdr, "\n");
+ fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
+ if (ferror(hdr)) {
+ perror(headername);
+ exit(1);
+ }
+
+ fprintf(out, "/*\n");
+ fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n");
+ fprintf(out, " *\n");
+ fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
+ fprintf(out, " */\n");
+ fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
+ fprintf(out, "#include \"%s.asn1.h\"\n", grammar_name);
+ fprintf(out, "\n");
+ if (ferror(out)) {
+ perror(outputname);
+ exit(1);
+ }
+
+ /* Tabulate the action functions we might have to call */
+ fprintf(hdr, "\n");
+ index = 0;
+ for (action = action_list; action; action = action->next) {
+ action->index = index++;
+ fprintf(hdr,
+ "extern int %s(void *, size_t, unsigned char,"
+ " const void *, size_t);\n",
+ action->name);
+ }
+ fprintf(hdr, "\n");
+
+ fprintf(out, "enum %s_actions {\n", grammar_name);
+ for (action = action_list; action; action = action->next)
+ fprintf(out, "\tACT_%s = %u,\n",
+ action->name, action->index);
+ fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
+ fprintf(out, "};\n");
+
+ fprintf(out, "\n");
+ fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
+ grammar_name, grammar_name);
+ for (action = action_list; action; action = action->next)
+ fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
+ fprintf(out, "};\n");
+
+ if (ferror(out)) {
+ perror(outputname);
+ exit(1);
+ }
+
+ /* We do two passes - the first one calculates all the offsets */
+ verbose("Pass 1\n");
+ nr_entries = 0;
+ root = &type_list[0];
+ render_element(NULL, root->element, NULL);
+ render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
+ render_out_of_line_list(NULL);
+
+ for (e = element_list; e; e = e->list_next)
+ e->flags &= ~ELEMENT_RENDERED;
+
+ /* And then we actually render */
+ verbose("Pass 2\n");
+ fprintf(out, "\n");
+ fprintf(out, "static const unsigned char %s_machine[] = {\n",
+ grammar_name);
+
+ nr_entries = 0;
+ root = &type_list[0];
+ render_element(out, root->element, NULL);
+ render_opcode(out, "ASN1_OP_COMPLETE,\n");
+ render_out_of_line_list(out);
+
+ fprintf(out, "};\n");
+
+ fprintf(out, "\n");
+ fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
+ fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
+ fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
+ fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
+ fprintf(out, "};\n");
+}
+
+/*
+ * Render the out-of-line elements
+ */
+static void render_out_of_line_list(FILE *out)
+{
+ struct element *e, *ce;
+ const char *act;
+ int entry;
+
+ while ((e = render_list)) {
+ render_list = e->render_next;
+ if (!render_list)
+ render_list_p = &render_list;
+
+ render_more(out, "\n");
+ e->entry_index = entry = nr_entries;
+ render_depth++;
+ for (ce = e->children; ce; ce = ce->next)
+ render_element(out, ce, NULL);
+ render_depth--;
+
+ act = e->action ? "_ACT" : "";
+ switch (e->compound) {
+ case SEQUENCE:
+ render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
+ break;
+ case SEQUENCE_OF:
+ render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
+ render_opcode(out, "_jump_target(%u),\n", entry);
+ break;
+ case SET:
+ render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
+ break;
+ case SET_OF:
+ render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
+ render_opcode(out, "_jump_target(%u),\n", entry);
+ break;
+ default:
+ break;
+ }
+ if (e->action)
+ render_opcode(out, "_action(ACT_%s),\n",
+ e->action->name);
+ render_opcode(out, "ASN1_OP_RETURN,\n");
+ }
+}
+
+/*
+ * Render an element.
+ */
+static void render_element(FILE *out, struct element *e, struct element *tag)
+{
+ struct element *ec, *x;
+ const char *cond, *act;
+ int entry, skippable = 0, outofline = 0;
+
+ if (e->flags & ELEMENT_SKIPPABLE ||
+ (tag && tag->flags & ELEMENT_SKIPPABLE))
+ skippable = 1;
+
+ if ((e->type_def && e->type_def->ref_count > 1) ||
+ skippable)
+ outofline = 1;
+
+ if (e->type_def && out) {
+ render_more(out, "\t// %s\n", e->type_def->name->content);
+ }
+
+ /* Render the operation */
+ cond = (e->flags & ELEMENT_CONDITIONAL ||
+ (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
+ act = e->action ? "_ACT" : "";
+ switch (e->compound) {
+ case ANY:
+ render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
+ cond, act, skippable ? "_OR_SKIP" : "");
+ if (e->name)
+ render_more(out, "\t\t// %s", e->name->content);
+ render_more(out, "\n");
+ goto dont_render_tag;
+
+ case TAG_OVERRIDE:
+ render_element(out, e->children, e);
+ return;
+
+ case SEQUENCE:
+ case SEQUENCE_OF:
+ case SET:
+ case SET_OF:
+ render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
+ cond,
+ outofline ? "_JUMP" : "",
+ skippable ? "_OR_SKIP" : "");
+ break;
+
+ case CHOICE:
+ goto dont_render_tag;
+
+ case TYPE_REF:
+ if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
+ goto dont_render_tag;
+ default:
+ render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
+ cond, act,
+ skippable ? "_OR_SKIP" : "");
+ break;
+ }
+
+ x = tag ?: e;
+ if (x->name)
+ render_more(out, "\t\t// %s", x->name->content);
+ render_more(out, "\n");
+
+ /* Render the tag */
+ if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
+ tag = e;
+
+ if (tag->class == ASN1_UNIV &&
+ tag->tag != 14 &&
+ tag->tag != 15 &&
+ tag->tag != 31)
+ render_opcode(out, "_tag(%s, %s, %s),\n",
+ asn1_classes[tag->class],
+ asn1_methods[tag->method | e->method],
+ asn1_universal_tags[tag->tag]);
+ else
+ render_opcode(out, "_tagn(%s, %s, %2u),\n",
+ asn1_classes[tag->class],
+ asn1_methods[tag->method | e->method],
+ tag->tag);
+ tag = NULL;
+dont_render_tag:
+
+ /* Deal with compound types */
+ switch (e->compound) {
+ case TYPE_REF:
+ render_element(out, e->type->type->element, tag);
+ if (e->action)
+ render_opcode(out, "ASN1_OP_%sACT,\n",
+ skippable ? "MAYBE_" : "");
+ break;
+
+ case SEQUENCE:
+ if (outofline) {
+ /* Render out-of-line for multiple use or
+ * skipability */
+ render_opcode(out, "_jump_target(%u),", e->entry_index);
+ if (e->type_def && e->type_def->name)
+ render_more(out, "\t\t// --> %s",
+ e->type_def->name->content);
+ render_more(out, "\n");
+ if (!(e->flags & ELEMENT_RENDERED)) {
+ e->flags |= ELEMENT_RENDERED;
+ *render_list_p = e;
+ render_list_p = &e->render_next;
+ }
+ return;
+ } else {
+ /* Render inline for single use */
+ render_depth++;
+ for (ec = e->children; ec; ec = ec->next)
+ render_element(out, ec, NULL);
+ render_depth--;
+ render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
+ }
+ break;
+
+ case SEQUENCE_OF:
+ case SET_OF:
+ if (outofline) {
+ /* Render out-of-line for multiple use or
+ * skipability */
+ render_opcode(out, "_jump_target(%u),", e->entry_index);
+ if (e->type_def && e->type_def->name)
+ render_more(out, "\t\t// --> %s",
+ e->type_def->name->content);
+ render_more(out, "\n");
+ if (!(e->flags & ELEMENT_RENDERED)) {
+ e->flags |= ELEMENT_RENDERED;
+ *render_list_p = e;
+ render_list_p = &e->render_next;
+ }
+ return;
+ } else {
+ /* Render inline for single use */
+ entry = nr_entries;
+ render_depth++;
+ render_element(out, e->children, NULL);
+ render_depth--;
+ if (e->compound == SEQUENCE_OF)
+ render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
+ else
+ render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
+ render_opcode(out, "_jump_target(%u),\n", entry);
+ }
+ break;
+
+ case SET:
+ /* I can't think of a nice way to do SET support without having
+ * a stack of bitmasks to make sure no element is repeated.
+ * The bitmask has also to be checked that no non-optional
+ * elements are left out whilst not preventing optional
+ * elements from being left out.
+ */
+ fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
+ exit(1);
+
+ case CHOICE:
+ for (ec = e->children; ec; ec = ec->next)
+ render_element(out, ec, ec);
+ if (!skippable)
+ render_opcode(out, "ASN1_OP_COND_FAIL,\n");
+ if (e->action)
+ render_opcode(out, "ASN1_OP_ACT,\n");
+ break;
+
+ default:
+ break;
+ }
+
+ if (e->action)
+ render_opcode(out, "_action(ACT_%s),\n", e->action->name);
+}