diff options
164 files changed, 6361 insertions, 3621 deletions
diff --git a/.travis.yml b/.travis.yml index 57f38e11698..937f028d6da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,6 @@ addons: - python-virtualenv - swig - libpython-dev - - gcc-powerpc-linux-gnu - iasl - grub-efi-ia32-bin - rpm2cpio @@ -29,6 +28,11 @@ addons: - device-tree-compiler - lzop +before_install: + - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + - sudo apt-get update -q + - sudo apt-get install libisl15 -y + install: # Clone uboot-test-hooks - git clone --depth=1 git://github.com/swarren/uboot-test-hooks.git /tmp/uboot-test-hooks @@ -36,10 +40,8 @@ install: - ln -s travis-ci /tmp/uboot-test-hooks/py/`hostname` # prepare buildman environment - echo -e "[toolchain]\nroot = /usr" > ~/.buildman - - echo -e "aarch64 = /tmp/gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu" >> ~/.buildman - - echo -e "arm = /tmp/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf" >> ~/.buildman - echo -e "arc = /tmp/arc_gnu_2017.09_prebuilt_uclibc_le_archs_linux_install" >> ~/.buildman - - echo -e "\n[toolchain-alias]\nsh = sh4\nopenrisc = or32" >> ~/.buildman + - echo -e "\n[toolchain-alias]\nsh = sh2\n" >> ~/.buildman - cat ~/.buildman - virtualenv /tmp/venv - . /tmp/venv/bin/activate @@ -64,10 +66,10 @@ before_script: - if [[ "${TOOLCHAIN}" == *microblaze* ]]; then ./tools/buildman/buildman --fetch-arch microblaze ; fi - if [[ "${TOOLCHAIN}" == *mips* ]]; then ./tools/buildman/buildman --fetch-arch mips ; fi - if [[ "${TOOLCHAIN}" == *or32* ]]; then ./tools/buildman/buildman --fetch-arch or32 ; fi - - if [[ "${TOOLCHAIN}" == *sh4* ]]; then ./tools/buildman/buildman --fetch-arch sh4 ; fi + - if [[ "${TOOLCHAIN}" == *sh* ]]; then ./tools/buildman/buildman --fetch-arch sh2 ; fi - if [[ "${TOOLCHAIN}" == *x86_64* ]]; then ./tools/buildman/buildman --fetch-arch x86_64; - echo -e "\n[toolchain-prefix]\nx86 = ${HOME}/.buildman-toolchains/gcc-4.9.0-nolibc/x86_64-linux/bin/x86_64-linux-" >> ~/.buildman; + echo -e "\n[toolchain-prefix]\nx86 = ${HOME}/.buildman-toolchains/gcc-7.3.0-nolibc/x86_64-linux/bin/x86_64-linux-" >> ~/.buildman; fi - if [[ "${TOOLCHAIN}" == arc ]]; then wget https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases/download/arc-2017.09-release/arc_gnu_2017.09_prebuilt_uclibc_le_archs_linux_install.tar.gz && @@ -80,11 +82,10 @@ before_script: fi # If TOOLCHAIN is unset, we're on some flavour of ARM. - if [[ "${TOOLCHAIN}" == "" ]]; then - wget http://releases.linaro.org/components/toolchain/binaries/6.3-2017.02/aarch64-linux-gnu/gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu.tar.xz && - wget http://releases.linaro.org/components/toolchain/binaries/6.3-2017.02/arm-linux-gnueabihf/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz && - tar -C /tmp -xf gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu.tar.xz && - tar -C /tmp -xf gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz; + ./tools/buildman/buildman --fetch-arch arm && + ./tools/buildman/buildman --fetch-arch aarch64; fi + - if [[ "${TOOLCHAIN}" == "powerpc" ]]; then ./tools/buildman/buildman --fetch-arch powerpc; fi - if [[ "${TOOLCHAIN}" == "riscv" ]]; then wget https://github.com/PkmX/riscv-prebuilt-toolchains/releases/download/20180111/riscv32-unknown-elf-toolchain.tar.gz && tar -C /tmp -xf riscv32-unknown-elf-toolchain.tar.gz && @@ -149,26 +150,16 @@ matrix: - BUILDMAN="arc" TOOLCHAIN="arc" - env: - - BUILDMAN="arm11" - - env: - - BUILDMAN="arm7" - - env: - - BUILDMAN="arm920t" + - BUILDMAN="arm11 arm7 arm920t arm946es" - env: - JOB="arm926ejs" BUILDMAN="arm926ejs -x mx,siemens,atmel" - env: - - BUILDMAN="arm946es" - - env: - BUILDMAN="atmel" - env: - BUILDMAN="aries" - env: - - JOB="Boundary Devices" - BUILDMAN="boundary" - - env: - - JOB="engicam" - BUILDMAN="engicam" + BUILDMAN="boundary engicam toradex" - env: - JOB="Freescale ARM32" BUILDMAN="freescale -x powerpc,m68k,aarch64" @@ -184,9 +175,7 @@ matrix: - env: - BUILDMAN="k2" - env: - - BUILDMAN="samsung" - - env: - - BUILDMAN="socfpga" + - BUILDMAN="samsung socfpga" - env: - BUILDMAN="sun4i" - env: @@ -203,13 +192,11 @@ matrix: - BUILDMAN="sun50i" - env: - JOB="Catch-all ARM" - BUILDMAN="arm -x arm11,arm7,arm9,aarch64,atmel,aries,freescale,kirkwood,mvebu,siemens,tegra,uniphier,mx,samsung,sunxi,am33xx,omap3,omap4,omap5,pxa,rockchip,toradex,socfpga,k2,xilinx" + BUILDMAN="arm -x arm11,arm7,arm9,aarch64,atmel,aries,freescale,kirkwood,mvebu,siemens,tegra,uniphier,mx,samsung,sunxi,am33xx,omap,pxa,rockchip,toradex,socfpga,k2,xilinx" - env: - BUILDMAN="sandbox x86" TOOLCHAIN="x86_64" - env: - - BUILDMAN="toradex" - - env: - BUILDMAN="kirkwood" - env: - BUILDMAN="mvebu" @@ -226,27 +213,27 @@ matrix: - BUILDMAN="mips" TOOLCHAIN="mips" - env: - - BUILDMAN="mpc83xx" + - JOB="Non-Freescale PowerPC" + BUILDMAN="powerpc -x freescale" + TOOLCHAIN="powerpc" - env: - - BUILDMAN="mpc85xx -x freescale" + - BUILDMAN="mpc85xx&freescale -x t208xrdb -x t4qds -x t102* -x p1_p2_rdb_pc -x p1010rdb -x corenet_ds -x b4860qds -x bsc91*" + TOOLCHAIN="powerpc" - env: - - BUILDMAN="mpc85xx -x t208xrdb -x t4qds -x t102* -x p1_p2_rdb_pc -x p1010rdb -x corenet_ds -x b4860qds -x sbc8548 -x bsc91*" + - BUILDMAN="t208xrdb corenet_ds" + TOOLCHAIN="powerpc" - env: - - BUILDMAN="t208xrdb" - - env: - - BUILDMAN="t4qds" + - BUILDMAN="t4qds b4860qds mpc83xx&freescale mpc86xx&freescale" + TOOLCHAIN="powerpc" - env: - BUILDMAN="t102*" + TOOLCHAIN="powerpc" - env: - BUILDMAN="p1_p2_rdb_pc" + TOOLCHAIN="powerpc" - env: - - BUILDMAN="p1010rdb" - - env: - - BUILDMAN="corenet_ds b4860qds sbc8548 bsc91*" - - env: - - BUILDMAN="mpc86xx" - - env: - - BUILDMAN="mpc8xx" + - BUILDMAN="p1010rdb bsc91" + TOOLCHAIN="powerpc" - env: - BUILDMAN="siemens" - env: @@ -256,21 +243,18 @@ matrix: - JOB="am33xx" BUILDMAN="am33xx -x siemens" - env: - - BUILDMAN="omap3" - - env: - - BUILDMAN="omap4" - - env: - - BUILDMAN="omap5" + - BUILDMAN="omap" - env: - BUILDMAN="uniphier" - env: - - JOB="aarch64" - BUILDMAN="aarch64 -x tegra,freescale,mvebu,uniphier,sunxi,samsung,rockchip" + - JOB="Catch-all AArch64" + BUILDMAN="aarch64 -x tegra,freescale,mvebu,uniphier,sunxi,samsung,rockchip,xilinx" - env: - BUILDMAN="rockchip" - env: - - BUILDMAN="sh4" - TOOLCHAIN="sh4" + - JOB="sh" + BUILDMAN="sh -x arm" + TOOLCHAIN="sh" - env: - JOB="Xilinx (ARM)" BUILDMAN="xilinx -x microblaze" @@ -376,6 +360,7 @@ matrix: TEST_PY_TEST_SPEC="not sleep" QEMU_TARGET="ppc-softmmu" BUILDMAN="^qemu-ppce500$" + TOOLCHAIN="powerpc" - env: - TEST_PY_BD="qemu-x86" TEST_PY_TEST_SPEC="not sleep" @@ -305,6 +305,12 @@ config SPL_FIT depends on SPL select SPL_OF_LIBFDT +config SPL_FIT_PRINT + bool "Support FIT printing within SPL" + depends on SPL_FIT + help + Support printing the content of the fitImage in a verbose manner in SPL. + config SPL_FIT_SIGNATURE bool "Enable signature verification of FIT firmware within SPL" depends on SPL_DM @@ -322,6 +328,17 @@ config SPL_LOAD_FIT particular it can handle selecting from multiple device tree and passing the correct one to U-Boot. +config SPL_LOAD_FIT_FULL + bool "Enable SPL loading U-Boot as a FIT" + select SPL_FIT + help + Normally with the SPL framework a legacy image is generated as part + of the build. This contains U-Boot along with information as to + where it should be loaded. This option instead enables generation + of a FIT (Flat Image Tree) which provides more flexibility. In + particular it can handle selecting from multiple device tree + and passing the correct one to U-Boot. + config SPL_FIT_IMAGE_POST_PROCESS bool "Enable post-processing of FIT artifacts after loading by the SPL" depends on SPL_LOAD_FIT diff --git a/Licenses/README b/Licenses/README index 5ad921ddfc9..486e18d0d80 100644 --- a/Licenses/README +++ b/Licenses/README @@ -1,3 +1,5 @@ +SPDX-License-Identifier: GPL-2.0 + U-Boot is Free Software. It is copyrighted by Wolfgang Denk and many others who contributed code (see the actual source code and the git commit messages for details). You can redistribute U-Boot and/or @@ -31,27 +33,107 @@ information, ...) which makes automatic processing a nightmare. To make this easier, such license headers in the source files will be replaced with a single line reference to Unique License Identifiers -as defined by the Linux Foundation's SPDX project [1]. For example, -in a source file the full "GPL v2.0 or later" header text will be -replaced by a single line: - - SPDX-License-Identifier: GPL-2.0+ - -Ideally, the license terms of all files in the source tree should be -defined by such License Identifiers; in no case a file can contain -more than one such License Identifier list. +as defined by the Linux Foundation's SPDX project [1]. If a "SPDX-License-Identifier:" line references more than one Unique License Identifier, then this means that the respective file can be used under the terms of either of these licenses, i. e. with - SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause + SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause you can choose between GPL-2.0+ and BSD-3-Clause licensing. We use the SPDX Unique License Identifiers here; these are available at [2]. +License identifier syntax +------------------------- + +1. Placement: + + The SPDX license identifier in U-Boot files shall be added at the first + possible line in a file which can contain a comment. For the majority + or files this is the first line, except for scripts which require the + '#!PATH_TO_INTERPRETER' in the first line. For those scripts the SPDX + identifier goes into the second line. + +| + +2. Style: + + The SPDX license identifier is added in form of a comment. The comment + style depends on the file type:: + + C source: // SPDX-License-Identifier: <SPDX License Expression> + C header: /* SPDX-License-Identifier: <SPDX License Expression> */ + ASM: /* SPDX-License-Identifier: <SPDX License Expression> */ + scripts: # SPDX-License-Identifier: <SPDX License Expression> + .rst: .. SPDX-License-Identifier: <SPDX License Expression> + .dts{i}: // SPDX-License-Identifier: <SPDX License Expression> + + If a specific tool cannot handle the standard comment style, then the + appropriate comment mechanism which the tool accepts shall be used. This + is the reason for having the "/\* \*/" style comment in C header + files. There was build breakage observed with generated .lds files where + 'ld' failed to parse the C++ comment. This has been fixed by now, but + there are still older assembler tools which cannot handle C++ style + comments. + +| + +3. Syntax: + + A <SPDX License Expression> is either an SPDX short form license + identifier found on the SPDX License List, or the combination of two + SPDX short form license identifiers separated by "WITH" when a license + exception applies. When multiple licenses apply, an expression consists + of keywords "AND", "OR" separating sub-expressions and surrounded by + "(", ")" . + + License identifiers for licenses like [L]GPL with the 'or later' option + are constructed by using a "+" for indicating the 'or later' option.:: + + // SPDX-License-Identifier: GPL-2.0+ + // SPDX-License-Identifier: LGPL-2.1+ + + WITH should be used when there is a modifier to a license needed. + For example, the linux kernel UAPI files use the expression:: + + // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note + // SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note + + Other examples using WITH exceptions found in the linux kernel are:: + + // SPDX-License-Identifier: GPL-2.0 WITH mif-exception + // SPDX-License-Identifier: GPL-2.0+ WITH GCC-exception-2.0 + + Exceptions can only be used with particular License identifiers. The + valid License identifiers are listed in the tags of the exception text + file. + + OR should be used if the file is dual licensed and only one license is + to be selected. For example, some dtsi files are available under dual + licenses:: + + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + + Examples from U-Boot for license expressions in dual licensed files:: + + // SPDX-License-Identifier: GPL-2.0 OR MIT + // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + + AND should be used if the file has multiple licenses whose terms all + apply to use the file. For example, if code is inherited from another + project and permission has been given to put it in U-Boot, but the + original license terms need to remain in effect:: + + // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) AND MIT + + Another other example where both sets of license terms need to be + adhered to is:: + + // SPDX-License-Identifier: GPL-1.0+ AND LGPL-2.1+ + [1] http://spdx.org/ [2] http://spdx.org/licenses/ diff --git a/MAINTAINERS b/MAINTAINERS index 5670917b41b..3209dcd3184 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -204,6 +204,7 @@ M: Patrick Delaunay <patrick.delaunay@st.com> S: Maintained F: arch/arm/mach-stm32mp F: drivers/clk/clk_stm32mp1.c +F: drivers/misc/stm32mp_fuse.c F: drivers/ram/stm32mp1/ ARM STM STV0991 @@ -258,6 +258,15 @@ HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer \ $(if $(CONFIG_TOOLS_DEBUG),-g) HOSTCXXFLAGS = -O2 +# With the move to GCC 6, we have implicitly upgraded our language +# standard to GNU11 (see https://gcc.gnu.org/gcc-5/porting_to.html). +# Some Linux distributions (including RHEL7, SLES13, Debian 8) still +# have older compilers as their default, so we make it explicit for +# these that our host tools are GNU11 (i.e. C11 w/ GNU extensions). +ifeq ($(HOSTOS),linux) +HOSTCFLAGS += --std=gnu11 +endif + ifeq ($(HOSTOS),cygwin) HOSTCFLAGS += -ansi endif @@ -1172,10 +1172,6 @@ The following options need to be configured: CONFIG_SUPPORT_EMMC_BOOT Enable some additional features of the eMMC boot partitions. - CONFIG_SUPPORT_EMMC_RPMB - Enable the commands for reading, writing and programming the - key for the Replay Protection Memory Block partition in eMMC. - - USB Device Firmware Update (DFU) class support: CONFIG_DFU_OVER_USB This enables the USB portion of the DFU USB class @@ -2695,7 +2691,7 @@ FIT uImage format: use an arch-specific makefile fragment instead, for example if more than one image needs to be produced. - CONFIG_FIT_SPL_PRINT + CONFIG_SPL_FIT_PRINT Printing information about a FIT image adds quite a bit of code to SPL. So this is normally disabled in SPL. Use this option to re-enable it. This will affect the output of the diff --git a/arch/arc/lib/start.S b/arch/arc/lib/start.S index 3fb05606c7b..e573ce7718b 100644 --- a/arch/arc/lib/start.S +++ b/arch/arc/lib/start.S @@ -75,6 +75,11 @@ ENTRY(_start) /* Initialize reserved area - note: r0 already contains address */ bl board_init_f_init_reserve +#ifdef CONFIG_DEBUG_UART + /* Earliest point to set up early debug uart */ + bl debug_uart_init +#endif + /* Zero the one and only argument of "board_init_f" */ mov_s %r0, 0 bl board_init_f diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3e05f79f638..582e84cf401 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -221,6 +221,7 @@ config CPU_V7M select THUMB2_KERNEL select SYS_CACHE_SHIFT_5 select SYS_ARM_MPU + select SYS_THUMB_BUILD config CPU_V7R bool @@ -393,7 +394,7 @@ choice config ARCH_AT91 bool "Atmel AT91" - select SPL_BOARD_INIT if SPL + select SPL_BOARD_INIT if SPL && !TARGET_SMARTWEB config TARGET_EDB93XX bool "Support edb93xx" @@ -1224,6 +1225,7 @@ config ARCH_STM32MP select DM_SERIAL select OF_CONTROL select OF_LIBFDT + select MISC select PINCTRL select REGMAP select SUPPORT_SPL diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 4d6d2761377..680c6e8516d 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -16,6 +16,7 @@ arch-$(CONFIG_CPU_ARM1136) =-march=armv5 arch-$(CONFIG_CPU_ARM1176) =-march=armv5t arch-$(CONFIG_CPU_V7A) =$(call cc-option, -march=armv7-a, \ $(call cc-option, -march=armv7, -march=armv5)) +arch-$(CONFIG_CPU_V7M) =-march=armv7-m arch-$(CONFIG_CPU_V7R) =-march=armv7-r arch-$(CONFIG_ARM64) =-march=armv8-a diff --git a/arch/arm/cpu/armv7m/config.mk b/arch/arm/cpu/armv7m/config.mk index 4e46df5a284..f50964cfb92 100644 --- a/arch/arm/cpu/armv7m/config.mk +++ b/arch/arm/cpu/armv7m/config.mk @@ -3,4 +3,4 @@ # (C) Copyright 2015 # Kamil Lulko, <kamil.lulko@gmail.com> -PLATFORM_CPPFLAGS += -march=armv7-m -mthumb -mno-unaligned-access +PLATFORM_CPPFLAGS += -mno-unaligned-access diff --git a/arch/arm/cpu/armv8/generic_timer.c b/arch/arm/cpu/armv8/generic_timer.c index 303ba3c00ef..bf07a706a02 100644 --- a/arch/arm/cpu/armv8/generic_timer.c +++ b/arch/arm/cpu/armv8/generic_timer.c @@ -61,3 +61,10 @@ unsigned long usec2ticks(unsigned long usec) return ticks; } + +ulong timer_get_boot_us(void) +{ + u64 val = get_ticks() * 1000000; + + return val / get_tbclk(); +} diff --git a/arch/arm/dts/dragonboard410c.dts b/arch/arm/dts/dragonboard410c.dts index d9d5831f4f8..182a865b0ab 100644 --- a/arch/arm/dts/dragonboard410c.dts +++ b/arch/arm/dts/dragonboard410c.dts @@ -8,6 +8,7 @@ /dts-v1/; #include "skeleton64.dtsi" +#include <dt-bindings/pinctrl/pinctrl-snapdragon.h> / { model = "Qualcomm Technologies, Inc. Dragonboard 410c"; @@ -38,6 +39,17 @@ ranges = <0x0 0x0 0x0 0xffffffff>; compatible = "simple-bus"; + pinctrl: qcom,tlmm@1000000 { + compatible = "qcom,tlmm-apq8016"; + reg = <0x1000000 0x400000>; + + blsp1_uart: uart { + function = "blsp1_uart"; + pins = "GPIO_4", "GPIO_5"; + drive-strength = <DRIVE_STRENGTH_8MA>; + bias-disable; + }; + }; clkc: qcom,gcc@1800000 { compatible = "qcom,gcc-apq8016"; reg = <0x1800000 0x80000>; @@ -49,6 +61,8 @@ compatible = "qcom,msm-uartdm-v1.4"; reg = <0x78b0000 0x200>; clock = <&clkc 4>; + pinctrl-names = "uart"; + pinctrl-0 = <&blsp1_uart>; }; soc_gpios: pinctrl@1000000 { diff --git a/arch/arm/dts/dragonboard820c-uboot.dtsi b/arch/arm/dts/dragonboard820c-uboot.dtsi index 88312b3fa16..97394cc5b04 100644 --- a/arch/arm/dts/dragonboard820c-uboot.dtsi +++ b/arch/arm/dts/dragonboard820c-uboot.dtsi @@ -5,6 +5,20 @@ * (C) Copyright 2017 Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org> */ +/ { + soc { + u-boot,dm-pre-reloc; + + clock-controller@300000 { + u-boot,dm-pre-reloc; + }; + + serial@75b0000 { + u-boot,dm-pre-reloc; + }; + }; +}; + &pm8994_pon { key_vol_down { gpios = <&pm8994_pon 1 0>; diff --git a/arch/arm/dts/dragonboard820c.dts b/arch/arm/dts/dragonboard820c.dts index 7bfae1c4266..7457d7b7e3f 100644 --- a/arch/arm/dts/dragonboard820c.dts +++ b/arch/arm/dts/dragonboard820c.dts @@ -50,6 +50,7 @@ blsp2_uart1: serial@75b0000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0x75b0000 0x1000>; + clock = <&gcc 4>; }; sdhc2: sdhci@74a4900 { diff --git a/arch/arm/dts/stm32f429-disco-u-boot.dtsi b/arch/arm/dts/stm32f429-disco-u-boot.dtsi index 8a0f642a937..10e09508aa2 100644 --- a/arch/arm/dts/stm32f429-disco-u-boot.dtsi +++ b/arch/arm/dts/stm32f429-disco-u-boot.dtsi @@ -37,6 +37,8 @@ clocks = <&rcc 0 STM32F4_AHB3_CLOCK(FMC)>; pinctrl-0 = <&fmc_pins>; pinctrl-names = "default"; + st,syscfg = <&syscfg>; + st,swp_fmc = <1>; u-boot,dm-pre-reloc; /* diff --git a/arch/arm/dts/uniphier-ld11.dtsi b/arch/arm/dts/uniphier-ld11.dtsi index bf3118eca3c..e7514f01fa0 100644 --- a/arch/arm/dts/uniphier-ld11.dtsi +++ b/arch/arm/dts/uniphier-ld11.dtsi @@ -418,7 +418,7 @@ mmc-ddr-1_8v; mmc-hs200-1_8v; mmc-pwrseq = <&emmc_pwrseq>; - cdns,phy-input-delay-legacy = <4>; + cdns,phy-input-delay-legacy = <9>; cdns,phy-input-delay-mmc-highspeed = <2>; cdns,phy-input-delay-mmc-ddr = <3>; cdns,phy-dll-delay-sdclk = <21>; @@ -553,10 +553,13 @@ status = "disabled"; reg = <0x65000000 0x8500>; interrupts = <0 66 4>; + clock-names = "ether"; clocks = <&sys_clk 6>; + reset-names = "ether"; resets = <&sys_rst 6>; - phy-mode = "rmii"; + phy-mode = "internal"; local-mac-address = [00 00 00 00 00 00]; + socionext,syscon-phy-mode = <&soc_glue 0>; mdio: mdio { #address-cells = <1>; diff --git a/arch/arm/dts/uniphier-ld20-ref.dts b/arch/arm/dts/uniphier-ld20-ref.dts index 2c1a92fafbf..440c2e6a638 100644 --- a/arch/arm/dts/uniphier-ld20-ref.dts +++ b/arch/arm/dts/uniphier-ld20-ref.dts @@ -67,3 +67,11 @@ reg = <0>; }; }; + +&pinctrl_ether_rgmii { + tx { + pins = "RGMII_TXCLK", "RGMII_TXD0", "RGMII_TXD1", + "RGMII_TXD2", "RGMII_TXD3", "RGMII_TXCTL"; + drive-strength = <9>; + }; +}; diff --git a/arch/arm/dts/uniphier-ld20.dtsi b/arch/arm/dts/uniphier-ld20.dtsi index b993df8a34a..31bc124dfca 100644 --- a/arch/arm/dts/uniphier-ld20.dtsi +++ b/arch/arm/dts/uniphier-ld20.dtsi @@ -523,7 +523,7 @@ mmc-ddr-1_8v; mmc-hs200-1_8v; mmc-pwrseq = <&emmc_pwrseq>; - cdns,phy-input-delay-legacy = <4>; + cdns,phy-input-delay-legacy = <9>; cdns,phy-input-delay-mmc-highspeed = <2>; cdns,phy-input-delay-mmc-ddr = <3>; cdns,phy-dll-delay-sdclk = <21>; @@ -622,10 +622,13 @@ interrupts = <0 66 4>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ether_rgmii>; + clock-names = "ether"; clocks = <&sys_clk 6>; + reset-names = "ether"; resets = <&sys_rst 6>; phy-mode = "rgmii"; local-mac-address = [00 00 00 00 00 00]; + socionext,syscon-phy-mode = <&soc_glue 0>; mdio: mdio { #address-cells = <1>; diff --git a/arch/arm/dts/uniphier-pro4.dtsi b/arch/arm/dts/uniphier-pro4.dtsi index 25c4b4f8fc0..00048635894 100644 --- a/arch/arm/dts/uniphier-pro4.dtsi +++ b/arch/arm/dts/uniphier-pro4.dtsi @@ -342,7 +342,7 @@ has-transaction-translator; }; - soc-glue@5f800000 { + soc_glue: soc-glue@5f800000 { compatible = "socionext,uniphier-pro4-soc-glue", "simple-mfd", "syscon"; reg = <0x5f800000 0x2000>; @@ -427,10 +427,14 @@ interrupts = <0 66 4>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ether_rgmii>; - clocks = <&sys_clk 6>; - resets = <&sys_rst 6>; + clock-names = "gio", "ether", "ether-gb", "ether-phy"; + clocks = <&sys_clk 12>, <&sys_clk 6>, <&sys_clk 7>, + <&sys_clk 10>; + reset-names = "gio", "ether"; + resets = <&sys_rst 12>, <&sys_rst 6>; phy-mode = "rgmii"; local-mac-address = [00 00 00 00 00 00]; + socionext,syscon-phy-mode = <&soc_glue 0>; mdio: mdio { #address-cells = <1>; diff --git a/arch/arm/dts/uniphier-pxs2.dtsi b/arch/arm/dts/uniphier-pxs2.dtsi index 9760f79e7ce..20f39351073 100644 --- a/arch/arm/dts/uniphier-pxs2.dtsi +++ b/arch/arm/dts/uniphier-pxs2.dtsi @@ -545,10 +545,13 @@ interrupts = <0 66 4>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ether_rgmii>; + clock-names = "ether"; clocks = <&sys_clk 6>; + reset-names = "ether"; resets = <&sys_rst 6>; phy-mode = "rgmii"; local-mac-address = [00 00 00 00 00 00]; + socionext,syscon-phy-mode = <&soc_glue 0>; mdio: mdio { #address-cells = <1>; diff --git a/arch/arm/dts/uniphier-pxs3.dtsi b/arch/arm/dts/uniphier-pxs3.dtsi index d4c458a2111..ae867cbb0ac 100644 --- a/arch/arm/dts/uniphier-pxs3.dtsi +++ b/arch/arm/dts/uniphier-pxs3.dtsi @@ -338,7 +338,7 @@ mmc-ddr-1_8v; mmc-hs200-1_8v; mmc-pwrseq = <&emmc_pwrseq>; - cdns,phy-input-delay-legacy = <4>; + cdns,phy-input-delay-legacy = <9>; cdns,phy-input-delay-mmc-highspeed = <2>; cdns,phy-input-delay-mmc-ddr = <3>; cdns,phy-dll-delay-sdclk = <21>; @@ -430,10 +430,13 @@ interrupts = <0 66 4>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ether_rgmii>; + clock-names = "ether"; clocks = <&sys_clk 6>; + reset-names = "ether"; resets = <&sys_rst 6>; phy-mode = "rgmii"; local-mac-address = [00 00 00 00 00 00]; + socionext,syscon-phy-mode = <&soc_glue 0>; mdio0: mdio { #address-cells = <1>; @@ -448,10 +451,13 @@ interrupts = <0 67 4>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ether1_rgmii>; + clock-names = "ether"; clocks = <&sys_clk 7>; + reset-names = "ether"; resets = <&sys_rst 7>; phy-mode = "rgmii"; local-mac-address = [00 00 00 00 00 00]; + socionext,syscon-phy-mode = <&soc_glue 1>; mdio1: mdio { #address-cells = <1>; diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c index 28ba3f14f36..930b25ccb81 100644 --- a/arch/arm/lib/interrupts.c +++ b/arch/arm/lib/interrupts.c @@ -56,6 +56,30 @@ static void show_efi_loaded_images(struct pt_regs *regs) efi_print_image_infos((void *)instruction_pointer(regs)); } +static void dump_instr(struct pt_regs *regs) +{ + unsigned long addr = instruction_pointer(regs); + const int thumb = thumb_mode(regs); + const int width = thumb ? 4 : 8; + int i; + + if (thumb) + addr &= ~1L; + else + addr &= ~3L; + printf("Code: "); + for (i = -4; i < 1 + !!thumb; i++) { + unsigned int val; + + if (thumb) + val = ((u16 *)addr)[i]; + else + val = ((u32 *)addr)[i]; + printf(i == 0 ? "(%0*x) " : "%0*x ", width, val); + } + printf("\n"); +} + void show_regs (struct pt_regs *regs) { unsigned long __maybe_unused flags; @@ -96,6 +120,7 @@ void show_regs (struct pt_regs *regs) fast_interrupts_enabled (regs) ? "on" : "off", processor_modes[processor_mode (regs)], thumb_mode (regs) ? " (T)" : ""); + dump_instr(regs); } /* fixup PC to point to the instruction leading to the exception */ diff --git a/arch/arm/mach-at91/spl.c b/arch/arm/mach-at91/spl.c index 7cba3825e7f..8bfb2a452b5 100644 --- a/arch/arm/mach-at91/spl.c +++ b/arch/arm/mach-at91/spl.c @@ -11,9 +11,7 @@ #include <asm/arch/clk.h> #include <spl.h> -#if defined(CONFIG_AT91SAM9_WATCHDOG) -void at91_disable_wdt(void) { } -#else +#if !defined(CONFIG_AT91SAM9_WATCHDOG) void at91_disable_wdt(void) { struct at91_wdt *wdt = (struct at91_wdt *)ATMEL_BASE_WDT; diff --git a/arch/arm/mach-at91/spl_at91.c b/arch/arm/mach-at91/spl_at91.c index d701c3586d3..8c368042a6b 100644 --- a/arch/arm/mach-at91/spl_at91.c +++ b/arch/arm/mach-at91/spl_at91.c @@ -76,7 +76,9 @@ void __weak spl_board_init(void) void board_init_f(ulong dummy) { lowlevel_clock_init(); +#if !defined(CONFIG_AT91SAM9_WATCHDOG) at91_disable_wdt(); +#endif /* * At this stage the main oscillator is supposed to be enabled diff --git a/arch/arm/mach-at91/spl_atmel.c b/arch/arm/mach-at91/spl_atmel.c index 11db1e5f8cf..597ff8c0367 100644 --- a/arch/arm/mach-at91/spl_atmel.c +++ b/arch/arm/mach-at91/spl_atmel.c @@ -98,8 +98,10 @@ void board_init_f(ulong dummy) configure_2nd_sram_as_l2_cache(); #endif +#if !defined(CONFIG_AT91SAM9_WATCHDOG) /* disable watchdog */ at91_disable_wdt(); +#endif /* PMC configuration */ at91_pmc_init(); diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index d55dc1aaa1d..bfd99db6e27 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -3,6 +3,12 @@ if ARCH_SNAPDRAGON config SYS_SOC default "snapdragon" +config SYS_MALLOC_F_LEN + default 0x2000 + +config SPL_SYS_MALLOC_F_LEN + default 0x2000 + choice prompt "Snapdragon board select" diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile index 1c23dc52cfb..1d35fea9126 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -6,4 +6,6 @@ obj-$(CONFIG_TARGET_DRAGONBOARD820C) += clock-apq8096.o obj-$(CONFIG_TARGET_DRAGONBOARD820C) += sysmap-apq8096.o obj-$(CONFIG_TARGET_DRAGONBOARD410C) += clock-apq8016.o obj-$(CONFIG_TARGET_DRAGONBOARD410C) += sysmap-apq8016.o +obj-$(CONFIG_TARGET_DRAGONBOARD410C) += pinctrl-apq8016.o +obj-$(CONFIG_TARGET_DRAGONBOARD410C) += pinctrl-snapdragon.o obj-y += clock-snapdragon.o diff --git a/arch/arm/mach-snapdragon/clock-apq8016.c b/arch/arm/mach-snapdragon/clock-apq8016.c index 9c0cc1c22cc..6e4a0ccb90a 100644 --- a/arch/arm/mach-snapdragon/clock-apq8016.c +++ b/arch/arm/mach-snapdragon/clock-apq8016.c @@ -17,7 +17,6 @@ /* GPLL0 clock control registers */ #define GPLL0_STATUS_ACTIVE BIT(17) -#define APCS_GPLL_ENA_VOTE_GPLL0 BIT(0) static const struct bcr_regs sdc_regs[] = { { @@ -36,11 +35,17 @@ static const struct bcr_regs sdc_regs[] = { } }; -static struct gpll0_ctrl gpll0_ctrl = { +static struct pll_vote_clk gpll0_vote_clk = { .status = GPLL0_STATUS, .status_bit = GPLL0_STATUS_ACTIVE, .ena_vote = APCS_GPLL_ENA_VOTE, - .vote_bit = APCS_GPLL_ENA_VOTE_GPLL0, + .vote_bit = BIT(0), +}; + +static struct vote_clk gcc_blsp1_ahb_clk = { + .cbcr_reg = BLSP1_AHB_CBCR, + .ena_vote = APCS_CLOCK_BRANCH_ENA_VOTE, + .vote_bit = BIT(10), }; /* SDHCI */ @@ -55,7 +60,7 @@ static int clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate) /* 800Mhz/div, gpll0 */ clk_rcg_set_rate_mnd(priv->base, &sdc_regs[slot], div, 0, 0, CFG_CLK_SRC_GPLL0); - clk_enable_gpll0(priv->base, &gpll0_ctrl); + clk_enable_gpll0(priv->base, &gpll0_vote_clk); clk_enable_cbc(priv->base + SDCC_APPS_CBCR(slot)); return rate; @@ -72,12 +77,16 @@ static const struct bcr_regs uart2_regs = { /* UART: 115200 */ static int clk_init_uart(struct msm_clk_priv *priv) { - /* Enable iface clk */ - clk_enable_cbc(priv->base + BLSP1_AHB_CBCR); + /* Enable AHB clock */ + clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk); + /* 7372800 uart block clock @ GPLL0 */ clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 144, 15625, CFG_CLK_SRC_GPLL0); - clk_enable_gpll0(priv->base, &gpll0_ctrl); + + /* Vote for gpll0 clock */ + clk_enable_gpll0(priv->base, &gpll0_vote_clk); + /* Enable core clk */ clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR); diff --git a/arch/arm/mach-snapdragon/clock-apq8096.c b/arch/arm/mach-snapdragon/clock-apq8096.c index 008649a4c6b..628c38785b6 100644 --- a/arch/arm/mach-snapdragon/clock-apq8096.c +++ b/arch/arm/mach-snapdragon/clock-apq8096.c @@ -27,7 +27,7 @@ static const struct bcr_regs sdc_regs = { .D = SDCC2_D, }; -static const struct gpll0_ctrl gpll0_ctrl = { +static const struct pll_vote_clk gpll0_vote_clk = { .status = GPLL0_STATUS, .status_bit = GPLL0_STATUS_ACTIVE, .ena_vote = APCS_GPLL_ENA_VOTE, @@ -41,7 +41,7 @@ static int clk_init_sdc(struct msm_clk_priv *priv, uint rate) clk_enable_cbc(priv->base + SDCC2_AHB_CBCR); clk_rcg_set_rate_mnd(priv->base, &sdc_regs, div, 0, 0, CFG_CLK_SRC_GPLL0); - clk_enable_gpll0(priv->base, &gpll0_ctrl); + clk_enable_gpll0(priv->base, &gpll0_vote_clk); clk_enable_cbc(priv->base + SDCC2_APPS_CBCR); return rate; diff --git a/arch/arm/mach-snapdragon/clock-snapdragon.c b/arch/arm/mach-snapdragon/clock-snapdragon.c index f738f57043c..85526186c60 100644 --- a/arch/arm/mach-snapdragon/clock-snapdragon.c +++ b/arch/arm/mach-snapdragon/clock-snapdragon.c @@ -30,7 +30,7 @@ void clk_enable_cbc(phys_addr_t cbcr) ; } -void clk_enable_gpll0(phys_addr_t base, const struct gpll0_ctrl *gpll0) +void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0) { if (readl(base + gpll0->status) & gpll0->status_bit) return; /* clock already enabled */ @@ -41,6 +41,21 @@ void clk_enable_gpll0(phys_addr_t base, const struct gpll0_ctrl *gpll0) ; } +#define BRANCH_ON_VAL (0) +#define BRANCH_NOC_FSM_ON_VAL BIT(29) +#define BRANCH_CHECK_MASK GENMASK(31, 28) + +void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk) +{ + u32 val; + + setbits_le32(base + vclk->ena_vote, vclk->vote_bit); + do { + val = readl(base + vclk->cbcr_reg); + val &= BRANCH_CHECK_MASK; + } while ((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL)); +} + #define APPS_CMD_RGCR_UPDATE BIT(0) /* Update clock command via CMD_RGCR */ diff --git a/arch/arm/mach-snapdragon/clock-snapdragon.h b/arch/arm/mach-snapdragon/clock-snapdragon.h index 2cff4f8a06c..58fab40a2e4 100644 --- a/arch/arm/mach-snapdragon/clock-snapdragon.h +++ b/arch/arm/mach-snapdragon/clock-snapdragon.h @@ -11,13 +11,18 @@ #define CFG_CLK_SRC_GPLL0 (1 << 8) #define CFG_CLK_SRC_MASK (7 << 8) -struct gpll0_ctrl { +struct pll_vote_clk { uintptr_t status; int status_bit; uintptr_t ena_vote; int vote_bit; }; +struct vote_clk { + uintptr_t cbcr_reg; + uintptr_t ena_vote; + int vote_bit; +}; struct bcr_regs { uintptr_t cfg_rcgr; uintptr_t cmd_rcgr; @@ -30,9 +35,10 @@ struct msm_clk_priv { phys_addr_t base; }; -void clk_enable_gpll0(phys_addr_t base, const struct gpll0_ctrl *pll0); +void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0); void clk_bcr_update(phys_addr_t apps_cmd_rgcr); void clk_enable_cbc(phys_addr_t cbcr); +void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk); void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs, int div, int m, int n, int source); diff --git a/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h index ae784387fa1..520e2e6bd7c 100644 --- a/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h +++ b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h @@ -13,6 +13,7 @@ /* Clocks: (from CLK_CTL_BASE) */ #define GPLL0_STATUS (0x2101C) #define APCS_GPLL_ENA_VOTE (0x45000) +#define APCS_CLOCK_BRANCH_ENA_VOTE (0x45004) #define SDCC_BCR(n) ((n * 0x1000) + 0x41000) #define SDCC_CMD_RCGR(n) ((n * 0x1000) + 0x41004) diff --git a/arch/arm/mach-snapdragon/pinctrl-apq8016.c b/arch/arm/mach-snapdragon/pinctrl-apq8016.c new file mode 100644 index 00000000000..bdb755d0e49 --- /dev/null +++ b/arch/arm/mach-snapdragon/pinctrl-apq8016.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Qualcomm APQ8016 pinctrl + * + * (C) Copyright 2018 Ramon Fried <ramon.fried@gmail.com> + * + */ + +#include "pinctrl-snapdragon.h" +#include <common.h> + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN]; +static const char * const msm_pinctrl_pins[] = { + "SDC1_CLK", + "SDC1_CMD", + "SDC1_DATA", + "SDC2_CLK", + "SDC2_CMD", + "SDC2_DATA", + "QDSD_CLK", + "QDSD_CMD", + "QDSD_DATA0", + "QDSD_DATA1", + "QDSD_DATA2", + "QDSD_DATA3", +}; + +static const struct pinctrl_function msm_pinctrl_functions[] = { + {"blsp1_uart", 2}, +}; + +static const char *apq8016_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *apq8016_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector < 130) { + snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector); + return pin_name; + } else { + return msm_pinctrl_pins[selector - 130]; + } +} + +static unsigned int apq8016_get_function_mux(unsigned int selector) +{ + return msm_pinctrl_functions[selector].val; +} + +struct msm_pinctrl_data apq8016_data = { + .pin_count = 140, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = apq8016_get_function_name, + .get_function_mux = apq8016_get_function_mux, + .get_pin_name = apq8016_get_pin_name, +}; + diff --git a/arch/arm/mach-snapdragon/pinctrl-snapdragon.c b/arch/arm/mach-snapdragon/pinctrl-snapdragon.c new file mode 100644 index 00000000000..5365ccdb70c --- /dev/null +++ b/arch/arm/mach-snapdragon/pinctrl-snapdragon.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * TLMM driver for Qualcomm APQ8016, APQ8096 + * + * (C) Copyright 2018 Ramon Fried <ramon.fried@gmail.com> + * + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <asm/io.h> +#include <dm/pinctrl.h> +#include "pinctrl-snapdragon.h" + +struct msm_pinctrl_priv { + phys_addr_t base; + struct msm_pinctrl_data *data; +}; + +#define GPIO_CONFIG_OFFSET(x) ((x) * 0x1000) +#define TLMM_GPIO_PULL_MASK GENMASK(1, 0) +#define TLMM_FUNC_SEL_MASK GENMASK(5, 2) +#define TLMM_DRV_STRENGTH_MASK GENMASK(8, 6) +#define TLMM_GPIO_ENABLE BIT(9) + +static const struct pinconf_param msm_conf_params[] = { + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 3 }, + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, +}; + +static int msm_get_functions_count(struct udevice *dev) +{ + struct msm_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->data->functions_count; +} + +static int msm_get_pins_count(struct udevice *dev) +{ + struct msm_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->data->pin_count; +} + +static const char *msm_get_function_name(struct udevice *dev, + unsigned int selector) +{ + struct msm_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->data->get_function_name(dev, selector); +} + +static int msm_pinctrl_probe(struct udevice *dev) +{ + struct msm_pinctrl_priv *priv = dev_get_priv(dev); + + priv->base = devfdt_get_addr(dev); + priv->data = (struct msm_pinctrl_data *)dev->driver_data; + + return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0; +} + +static const char *msm_get_pin_name(struct udevice *dev, unsigned int selector) +{ + struct msm_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->data->get_pin_name(dev, selector); +} + +static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector, + unsigned int func_selector) +{ + struct msm_pinctrl_priv *priv = dev_get_priv(dev); + + clrsetbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector), + TLMM_FUNC_SEL_MASK | TLMM_GPIO_ENABLE, + priv->data->get_function_mux(func_selector) << 2); + return 0; +} + +static int msm_pinconf_set(struct udevice *dev, unsigned int pin_selector, + unsigned int param, unsigned int argument) +{ + struct msm_pinctrl_priv *priv = dev_get_priv(dev); + + switch (param) { + case PIN_CONFIG_DRIVE_STRENGTH: + clrsetbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector), + TLMM_DRV_STRENGTH_MASK, argument << 6); + break; + case PIN_CONFIG_BIAS_DISABLE: + clrbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector), + TLMM_GPIO_PULL_MASK); + break; + default: + return 0; + } + + return 0; +} + +static struct pinctrl_ops msm_pinctrl_ops = { + .get_pins_count = msm_get_pins_count, + .get_pin_name = msm_get_pin_name, + .set_state = pinctrl_generic_set_state, + .pinmux_set = msm_pinmux_set, + .pinconf_num_params = ARRAY_SIZE(msm_conf_params), + .pinconf_params = msm_conf_params, + .pinconf_set = msm_pinconf_set, + .get_functions_count = msm_get_functions_count, + .get_function_name = msm_get_function_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,tlmm-msm8916", .data = (ulong)&apq8016_data }, + { .compatible = "qcom,tlmm-apq8016", .data = (ulong)&apq8016_data }, + { } +}; + +U_BOOT_DRIVER(pinctrl_snapdraon) = { + .name = "pinctrl_msm", + .id = UCLASS_PINCTRL, + .of_match = msm_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct msm_pinctrl_priv), + .ops = &msm_pinctrl_ops, + .probe = msm_pinctrl_probe, +}; diff --git a/arch/arm/mach-snapdragon/pinctrl-snapdragon.h b/arch/arm/mach-snapdragon/pinctrl-snapdragon.h new file mode 100644 index 00000000000..c47d988af4c --- /dev/null +++ b/arch/arm/mach-snapdragon/pinctrl-snapdragon.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Qualcomm Pin control + * + * (C) Copyright 2018 Ramon Fried <ramon.fried@gmail.com> + * + */ +#ifndef _PINCTRL_SNAPDRAGON_H +#define _PINCTRL_SNAPDRAGON_H + +#include <common.h> + +struct msm_pinctrl_data { + int pin_count; + int functions_count; + const char *(*get_function_name)(struct udevice *dev, + unsigned int selector); + unsigned int (*get_function_mux)(unsigned int selector); + const char *(*get_pin_name)(struct udevice *dev, + unsigned int selector); +}; + +struct pinctrl_function { + const char *name; + int val; +}; + +extern struct msm_pinctrl_data apq8016_data; + +#endif diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index ccbeb5c3881..abceeded24a 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -54,4 +54,19 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2 source "board/st/stm32mp1/Kconfig" +# currently activated for debug / should be deactivated for real product +if DEBUG_UART + +config DEBUG_UART_BOARD_INIT + default y + +# debug on UART4 by default +config DEBUG_UART_BASE + default 0x40010000 + +# clock source is HSI on reset +config DEBUG_UART_CLOCK + default 64000000 +endif + endif diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index 08ee642d908..f59ced5ee1b 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +# SPDX-License-Identifier: GPL-2.0+ # # Copyright (C) 2018, STMicroelectronics - All Rights Reserved # @@ -7,6 +7,10 @@ obj-y += cpu.o obj-y += dram_init.o obj-y += syscon.o -obj-$(CONFIG_SPL_BUILD) += spl.o +ifdef CONFIG_SPL_BUILD +obj-y += spl.o +else +obj-y += bsec.o +endif obj-$(CONFIG_ARMV7_PSCI) += psci.o obj-$(CONFIG_$(SPL_)DM_REGULATOR) += pwr_regulator.o diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c new file mode 100644 index 00000000000..0e152efc045 --- /dev/null +++ b/arch/arm/mach-stm32mp/bsec.c @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <dm.h> +#include <misc.h> +#include <asm/io.h> +#include <linux/iopoll.h> + +#define BSEC_OTP_MAX_VALUE 95 + +#define BSEC_TIMEOUT_US 10000 + +/* BSEC REGISTER OFFSET (base relative) */ +#define BSEC_OTP_CONF_OFF 0x000 +#define BSEC_OTP_CTRL_OFF 0x004 +#define BSEC_OTP_WRDATA_OFF 0x008 +#define BSEC_OTP_STATUS_OFF 0x00C +#define BSEC_OTP_LOCK_OFF 0x010 +#define BSEC_DISTURBED_OFF 0x01C +#define BSEC_ERROR_OFF 0x034 +#define BSEC_SPLOCK_OFF 0x064 /* Program safmem sticky lock */ +#define BSEC_SWLOCK_OFF 0x07C /* write in OTP sticky lock */ +#define BSEC_SRLOCK_OFF 0x094 /* shadowing sticky lock */ +#define BSEC_OTP_DATA_OFF 0x200 + +/* BSEC_CONFIGURATION Register MASK */ +#define BSEC_CONF_POWER_UP 0x001 + +/* BSEC_CONTROL Register */ +#define BSEC_READ 0x000 +#define BSEC_WRITE 0x100 + +/* LOCK Register */ +#define OTP_LOCK_MASK 0x1F +#define OTP_LOCK_BANK_SHIFT 0x05 +#define OTP_LOCK_BIT_MASK 0x01 + +/* STATUS Register */ +#define BSEC_MODE_BUSY_MASK 0x08 +#define BSEC_MODE_PROGFAIL_MASK 0x10 +#define BSEC_MODE_PWR_MASK 0x20 + +/* + * OTP Lock services definition + * Value must corresponding to the bit number in the register + */ +#define BSEC_LOCK_PROGRAM 0x04 + +/** + * bsec_check_error() - Check status of one otp + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: 0 if no error, -EAGAIN or -ENOTSUPP + */ +static u32 bsec_check_error(u32 base, u32 otp) +{ + u32 bit; + u32 bank; + + bit = 1 << (otp & OTP_LOCK_MASK); + bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32); + + if (readl(base + BSEC_DISTURBED_OFF + bank) & bit) + return -EAGAIN; + else if (readl(base + BSEC_ERROR_OFF + bank) & bit) + return -ENOTSUPP; + + return 0; +} + +/** + * bsec_lock() - manage lock for each type SR/SP/SW + * @address: address of bsec IP register + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: true if locked else false + */ +static bool bsec_read_lock(u32 address, u32 otp) +{ + u32 bit; + u32 bank; + + bit = 1 << (otp & OTP_LOCK_MASK); + bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32); + + return !!(readl(address + bank) & bit); +} + +/** + * bsec_read_SR_lock() - read SR lock (Shadowing) + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: true if locked else false + */ +static bool bsec_read_SR_lock(u32 base, u32 otp) +{ + return bsec_read_lock(base + BSEC_SRLOCK_OFF, otp); +} + +/** + * bsec_read_SP_lock() - read SP lock (program Lock) + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: true if locked else false + */ +static bool bsec_read_SP_lock(u32 base, u32 otp) +{ + return bsec_read_lock(base + BSEC_SPLOCK_OFF, otp); +} + +/** + * bsec_SW_lock() - manage SW lock (Write in Shadow) + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: true if locked else false + */ +static bool bsec_read_SW_lock(u32 base, u32 otp) +{ + return bsec_read_lock(base + BSEC_SWLOCK_OFF, otp); +} + +/** + * bsec_power_safmem() - Activate or deactivate safmem power + * @base: base address of bsec IP + * @power: true to power up , false to power down + * Return: 0 if succeed + */ +static int bsec_power_safmem(u32 base, bool power) +{ + u32 val; + u32 mask; + + if (power) { + setbits_le32(base + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP); + mask = BSEC_MODE_PWR_MASK; + } else { + clrbits_le32(base + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP); + mask = 0; + } + + /* waiting loop */ + return readl_poll_timeout(base + BSEC_OTP_STATUS_OFF, + val, (val & BSEC_MODE_PWR_MASK) == mask, + BSEC_TIMEOUT_US); +} + +/** + * bsec_shadow_register() - copy safmen otp to bsec data + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: 0 if no error + */ +static int bsec_shadow_register(u32 base, u32 otp) +{ + u32 val; + int ret; + bool power_up = false; + + /* check if shadowing of otp is locked */ + if (bsec_read_SR_lock(base, otp)) + pr_debug("bsec : OTP %d is locked and refreshed with 0\n", otp); + + /* check if safemem is power up */ + val = readl(base + BSEC_OTP_STATUS_OFF); + if (!(val & BSEC_MODE_PWR_MASK)) { + ret = bsec_power_safmem(base, true); + if (ret) + return ret; + power_up = 1; + } + /* set BSEC_OTP_CTRL_OFF with the otp value*/ + writel(otp | BSEC_READ, base + BSEC_OTP_CTRL_OFF); + + /* check otp status*/ + ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF, + val, (val & BSEC_MODE_BUSY_MASK) == 0, + BSEC_TIMEOUT_US); + if (ret) + return ret; + + ret = bsec_check_error(base, otp); + + if (power_up) + bsec_power_safmem(base, false); + + return ret; +} + +/** + * bsec_read_shadow() - read an otp data value from shadow + * @base: base address of bsec IP + * @val: read value + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: 0 if no error + */ +static int bsec_read_shadow(u32 base, u32 *val, u32 otp) +{ + *val = readl(base + BSEC_OTP_DATA_OFF + otp * sizeof(u32)); + + return bsec_check_error(base, otp); +} + +/** + * bsec_write_shadow() - write value in BSEC data register in shadow + * @base: base address of bsec IP + * @val: value to write + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: 0 if no error + */ +static int bsec_write_shadow(u32 base, u32 val, u32 otp) +{ + /* check if programming of otp is locked */ + if (bsec_read_SW_lock(base, otp)) + pr_debug("bsec : OTP %d is lock, write will be ignore\n", otp); + + writel(val, base + BSEC_OTP_DATA_OFF + otp * sizeof(u32)); + + return bsec_check_error(base, otp); +} + +/** + * bsec_program_otp() - program a bit in SAFMEM + * @base: base address of bsec IP + * @val: value to program + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * after the function the otp data is not refreshed in shadow + * Return: 0 if no error + */ +static int bsec_program_otp(long base, u32 val, u32 otp) +{ + u32 ret; + bool power_up = false; + + if (bsec_read_SP_lock(base, otp)) + pr_debug("bsec : OTP %d locked, prog will be ignore\n", otp); + + if (readl(base + BSEC_OTP_LOCK_OFF) & (1 << BSEC_LOCK_PROGRAM)) + pr_debug("bsec : Global lock, prog will be ignore\n"); + + /* check if safemem is power up */ + if (!(readl(base + BSEC_OTP_STATUS_OFF) & BSEC_MODE_PWR_MASK)) { + ret = bsec_power_safmem(base, true); + if (ret) + return ret; + + power_up = true; + } + /* set value in write register*/ + writel(val, base + BSEC_OTP_WRDATA_OFF); + + /* set BSEC_OTP_CTRL_OFF with the otp value */ + writel(otp | BSEC_WRITE, base + BSEC_OTP_CTRL_OFF); + + /* check otp status*/ + ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF, + val, (val & BSEC_MODE_BUSY_MASK) == 0, + BSEC_TIMEOUT_US); + if (ret) + return ret; + + if (val & BSEC_MODE_PROGFAIL_MASK) + ret = -EACCES; + else + ret = bsec_check_error(base, otp); + + if (power_up) + bsec_power_safmem(base, false); + + return ret; +} + +/* BSEC MISC driver *******************************************************/ +struct stm32mp_bsec_platdata { + u32 base; +}; + +static int stm32mp_bsec_read_otp(struct udevice *dev, u32 *val, u32 otp) +{ + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + u32 tmp_data = 0; + int ret; + + /* read current shadow value */ + ret = bsec_read_shadow(plat->base, &tmp_data, otp); + if (ret) + return ret; + + /* copy otp in shadow */ + ret = bsec_shadow_register(plat->base, otp); + if (ret) + return ret; + + ret = bsec_read_shadow(plat->base, val, otp); + if (ret) + return ret; + + /* restore shadow value */ + ret = bsec_write_shadow(plat->base, tmp_data, otp); + return ret; +} + +static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp) +{ + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + + return bsec_read_shadow(plat->base, val, otp); +} + +static int stm32mp_bsec_write_otp(struct udevice *dev, u32 val, u32 otp) +{ + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + + return bsec_program_otp(plat->base, val, otp); +} + +static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp) +{ + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + + return bsec_write_shadow(plat->base, val, otp); +} + +static int stm32mp_bsec_read(struct udevice *dev, int offset, + void *buf, int size) +{ + int ret; + int i; + bool shadow = true; + int nb_otp = size / sizeof(u32); + int otp; + + if (offset >= STM32_BSEC_OTP_OFFSET) { + offset -= STM32_BSEC_OTP_OFFSET; + shadow = false; + } + otp = offset / sizeof(u32); + + if (otp < 0 || (otp + nb_otp - 1) > BSEC_OTP_MAX_VALUE) { + dev_err(dev, "wrong value for otp, max value : %i\n", + BSEC_OTP_MAX_VALUE); + return -EINVAL; + } + + for (i = otp; i < (otp + nb_otp); i++) { + u32 *addr = &((u32 *)buf)[i - otp]; + + if (shadow) + ret = stm32mp_bsec_read_shadow(dev, addr, i); + else + ret = stm32mp_bsec_read_otp(dev, addr, i); + + if (ret) + break; + } + return ret; +} + +static int stm32mp_bsec_write(struct udevice *dev, int offset, + const void *buf, int size) +{ + int ret = 0; + int i; + bool shadow = true; + int nb_otp = size / sizeof(u32); + int otp; + + if (offset >= STM32_BSEC_OTP_OFFSET) { + offset -= STM32_BSEC_OTP_OFFSET; + shadow = false; + } + otp = offset / sizeof(u32); + + if (otp < 0 || (otp + nb_otp - 1) > BSEC_OTP_MAX_VALUE) { + dev_err(dev, "wrong value for otp, max value : %d\n", + BSEC_OTP_MAX_VALUE); + return -EINVAL; + } + + for (i = otp; i < otp + nb_otp; i++) { + u32 *val = &((u32 *)buf)[i - otp]; + + if (shadow) + ret = stm32mp_bsec_write_shadow(dev, *val, i); + else + ret = stm32mp_bsec_write_otp(dev, *val, i); + if (ret) + break; + } + return ret; +} + +static const struct misc_ops stm32mp_bsec_ops = { + .read = stm32mp_bsec_read, + .write = stm32mp_bsec_write, +}; + +static int stm32mp_bsec_ofdata_to_platdata(struct udevice *dev) +{ + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + + plat->base = (u32)dev_read_addr_ptr(dev); + + return 0; +} + +static const struct udevice_id stm32mp_bsec_ids[] = { + { .compatible = "st,stm32mp-bsec" }, + {} +}; + +U_BOOT_DRIVER(stm32mp_bsec) = { + .name = "stm32mp_bsec", + .id = UCLASS_MISC, + .of_match = stm32mp_bsec_ids, + .ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata), + .ops = &stm32mp_bsec_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +/* bsec IP is not present in device tee, manage IP address by platdata */ +static struct stm32mp_bsec_platdata stm32_bsec_platdata = { + .base = STM32_BSEC_BASE, +}; + +U_BOOT_DEVICE(stm32mp_bsec) = { + .name = "stm32mp_bsec", + .platdata = &stm32_bsec_platdata, +}; diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index dfcbbd23146..0e01f8e6138 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -4,9 +4,13 @@ */ #include <common.h> #include <clk.h> +#include <debug_uart.h> +#include <environment.h> +#include <misc.h> #include <asm/io.h> #include <asm/arch/stm32.h> #include <asm/arch/sys_proto.h> +#include <dm/device.h> #include <dm/uclass.h> /* RCC register */ @@ -50,6 +54,10 @@ #define BOOTROM_INSTANCE_MASK GENMASK(31, 16) #define BOOTROM_INSTANCE_SHIFT 16 +/* BSEC OTP index */ +#define BSEC_OTP_SERIAL 13 +#define BSEC_OTP_MAC 57 + #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) static void security_init(void) { @@ -152,6 +160,8 @@ static u32 get_bootmode(void) */ int arch_cpu_init(void) { + u32 boot_mode; + /* early armv7 timer init: needed for polling */ timer_init(); @@ -160,8 +170,17 @@ int arch_cpu_init(void) security_init(); #endif + /* get bootmode from BootRom context: saved in TAMP register */ - get_bootmode(); + boot_mode = get_bootmode(); + + if ((boot_mode & TAMP_BOOT_DEVICE_MASK) == BOOT_SERIAL_UART) + gd->flags |= GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE; +#if defined(CONFIG_DEBUG_UART) && \ + (!defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)) + else + debug_uart_init(); +#endif return 0; } @@ -262,9 +281,83 @@ static void setup_boot_mode(void) } } +/* + * If there is no MAC address in the environment, then it will be initialized + * (silently) from the value in the OTP. + */ +static int setup_mac_address(void) +{ +#if defined(CONFIG_NET) + int ret; + int i; + u32 otp[2]; + uchar enetaddr[6]; + struct udevice *dev; + + /* MAC already in environment */ + if (eth_env_get_enetaddr("ethaddr", enetaddr)) + return 0; + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + + ret = misc_read(dev, BSEC_OTP_MAC * 4 + STM32_BSEC_OTP_OFFSET, + otp, sizeof(otp)); + if (ret) + return ret; + + for (i = 0; i < 6; i++) + enetaddr[i] = ((uint8_t *)&otp)[i]; + + if (!is_valid_ethaddr(enetaddr)) { + pr_err("invalid MAC address in OTP %pM", enetaddr); + return -EINVAL; + } + pr_debug("OTP MAC address = %pM\n", enetaddr); + ret = !eth_env_set_enetaddr("ethaddr", enetaddr); + if (!ret) + pr_err("Failed to set mac address %pM from OTP: %d\n", + enetaddr, ret); +#endif + + return 0; +} + +static int setup_serial_number(void) +{ + char serial_string[25]; + u32 otp[3] = {0, 0, 0 }; + struct udevice *dev; + int ret; + + if (env_get("serial#")) + return 0; + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + + ret = misc_read(dev, BSEC_OTP_SERIAL * 4 + STM32_BSEC_OTP_OFFSET, + otp, sizeof(otp)); + if (ret) + return ret; + + sprintf(serial_string, "%08x%08x%08x", otp[0], otp[1], otp[2]); + env_set("serial#", serial_string); + + return 0; +} + int arch_misc_init(void) { setup_boot_mode(); + setup_mac_address(); + setup_serial_number(); return 0; } diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index a8142013b08..5d0bdca1787 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -13,10 +13,23 @@ #define STM32_RCC_BASE 0x50000000 #define STM32_PWR_BASE 0x50001000 #define STM32_DBGMCU_BASE 0x50081000 +#define STM32_BSEC_BASE 0x5C005000 #define STM32_TZC_BASE 0x5C006000 #define STM32_ETZPC_BASE 0x5C007000 #define STM32_TAMP_BASE 0x5C00A000 +#ifdef CONFIG_DEBUG_UART_BASE +/* hardcoded value can be only used for DEBUG UART */ +#define STM32_USART1_BASE 0x5C000000 +#define STM32_USART2_BASE 0x4000E000 +#define STM32_USART3_BASE 0x4000F000 +#define STM32_UART4_BASE 0x40010000 +#define STM32_UART5_BASE 0x40011000 +#define STM32_USART6_BASE 0x44003000 +#define STM32_UART7_BASE 0x40018000 +#define STM32_UART8_BASE 0x40019000 +#endif + #define STM32_SYSRAM_BASE 0x2FFC0000 #define STM32_SYSRAM_SIZE SZ_256K @@ -83,5 +96,9 @@ enum boot_device { #define TAMP_BOOT_DEVICE_MASK GENMASK(7, 4) #define TAMP_BOOT_INSTANCE_MASK GENMASK(3, 0) +/* offset used for BSEC driver: misc_read and misc_write */ +#define STM32_BSEC_SHADOW_OFFSET 0x0 +#define STM32_BSEC_OTP_OFFSET 0x80000000 + #endif /* __ASSEMBLY__*/ #endif /* _MACH_STM32_H_ */ diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index b56f0c5381c..790973e8b6e 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -14,9 +14,6 @@ u32 spl_boot_device(void) boot_mode = (readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_MODE_MASK) >> TAMP_BOOT_MODE_SHIFT; - clrsetbits_le32(TAMP_BOOT_CONTEXT, - TAMP_BOOT_MODE_MASK, - boot_mode << TAMP_BOOT_MODE_SHIFT); switch (boot_mode) { case BOOT_FLASH_SD_1: diff --git a/arch/arm/mach-uniphier/board_late_init.c b/arch/arm/mach-uniphier/board_late_init.c index 9dff3f16a06..6a995728d4b 100644 --- a/arch/arm/mach-uniphier/board_late_init.c +++ b/arch/arm/mach-uniphier/board_late_init.c @@ -38,7 +38,7 @@ static int uniphier_set_fdt_file(void) char dtb_name[256]; int buf_len = sizeof(dtb_name); - if (env_get("fdt_file")) + if (env_get("fdtfile")) return 0; /* do nothing if it is already set */ compat = fdt_stringlist_get(gd->fdt_blob, 0, "compatible", 0, NULL); @@ -56,7 +56,7 @@ static int uniphier_set_fdt_file(void) strncat(dtb_name, ".dtb", buf_len); - return env_set("fdt_file", dtb_name); + return env_set("fdtfile", dtb_name); } int board_late_init(void) diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 86680a6b11d..0ea2452742d 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -242,6 +242,10 @@ compatible = "google,sandbox-tpm"; }; + tpm2 { + compatible = "sandbox,tpm2"; + }; + triangle { compatible = "demo-shape"; colour = "cyan"; diff --git a/arch/sandbox/dts/sandbox64.dts b/arch/sandbox/dts/sandbox64.dts index 8f707b47dbe..48e420e721e 100644 --- a/arch/sandbox/dts/sandbox64.dts +++ b/arch/sandbox/dts/sandbox64.dts @@ -242,6 +242,10 @@ compatible = "google,sandbox-tpm"; }; + tpm2 { + compatible = "sandbox,tpm2"; + }; + triangle { compatible = "demo-shape"; colour = "cyan"; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 5a0f187d8b7..f2e5d65dad9 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -422,6 +422,10 @@ clock-frequency = <1000000>; }; + tpm2 { + compatible = "sandbox,tpm2"; + }; + uart0: serial { compatible = "sandbox,serial"; u-boot,dm-pre-reloc; diff --git a/board/emulation/qemu-arm/qemu-arm.c b/board/emulation/qemu-arm/qemu-arm.c index 6ec42001706..085cbbef994 100644 --- a/board/emulation/qemu-arm/qemu-arm.c +++ b/board/emulation/qemu-arm/qemu-arm.c @@ -28,7 +28,7 @@ static struct mm_region qemu_arm64_mem_map[] = { /* RAM */ .virt = 0x40000000UL, .phys = 0x40000000UL, - .size = 0xc0000000UL, + .size = 255UL * SZ_1G, .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE }, { diff --git a/board/gdsys/a38x/controlcenterdc.c b/board/gdsys/a38x/controlcenterdc.c index 320bc100c9d..824a08f12af 100644 --- a/board/gdsys/a38x/controlcenterdc.c +++ b/board/gdsys/a38x/controlcenterdc.c @@ -7,7 +7,7 @@ #include <common.h> #include <dm.h> #include <miiphy.h> -#include <tpm.h> +#include <tpm-v1.h> #include <asm/io.h> #include <asm/arch/cpu.h> #include <asm-generic/gpio.h> diff --git a/board/gdsys/a38x/hre.c b/board/gdsys/a38x/hre.c index 961316cab78..34c4df71b25 100644 --- a/board/gdsys/a38x/hre.c +++ b/board/gdsys/a38x/hre.c @@ -9,7 +9,7 @@ #include <fs.h> #include <i2c.h> #include <mmc.h> -#include <tpm.h> +#include <tpm-v1.h> #include <u-boot/sha1.h> #include <asm/byteorder.h> #include <asm/unaligned.h> diff --git a/board/gdsys/a38x/keyprogram.c b/board/gdsys/a38x/keyprogram.c index f6a2747fb25..1fb5306b50f 100644 --- a/board/gdsys/a38x/keyprogram.c +++ b/board/gdsys/a38x/keyprogram.c @@ -5,7 +5,7 @@ */ #include <common.h> -#include <tpm.h> +#include <tpm-v1.h> #include <malloc.h> #include <linux/ctype.h> #include <asm/unaligned.h> diff --git a/board/gdsys/p1022/controlcenterd-id.c b/board/gdsys/p1022/controlcenterd-id.c index 87edf92f43a..7e082dff052 100644 --- a/board/gdsys/p1022/controlcenterd-id.c +++ b/board/gdsys/p1022/controlcenterd-id.c @@ -15,7 +15,7 @@ #include <fs.h> #include <i2c.h> #include <mmc.h> -#include <tpm.h> +#include <tpm-v1.h> #include <u-boot/sha1.h> #include <asm/byteorder.h> #include <asm/unaligned.h> diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c index 956768f0447..5f31ea99f59 100644 --- a/board/st/stm32mp1/board.c +++ b/board/st/stm32mp1/board.c @@ -10,6 +10,33 @@ #include <power/pmic.h> #include <power/stpmu1.h> +#ifdef CONFIG_DEBUG_UART_BOARD_INIT +void board_debug_uart_init(void) +{ +#if (CONFIG_DEBUG_UART_BASE == STM32_UART4_BASE) + +#define RCC_MP_APB1ENSETR (STM32_RCC_BASE + 0x0A00) +#define RCC_MP_AHB4ENSETR (STM32_RCC_BASE + 0x0A28) + + /* UART4 clock enable */ + setbits_le32(RCC_MP_APB1ENSETR, BIT(16)); + +#define GPIOG_BASE 0x50008000 + /* GPIOG clock enable */ + writel(BIT(6), RCC_MP_AHB4ENSETR); + /* GPIO configuration for EVAL board + * => Uart4 TX = G11 + */ + writel(0xffbfffff, GPIOG_BASE + 0x00); + writel(0x00006000, GPIOG_BASE + 0x24); +#else + +#error("CONFIG_DEBUG_UART_BASE: not supported value") + +#endif +} +#endif + #ifdef CONFIG_PMIC_STPMU1 int board_ddr_power_init(void) { diff --git a/board/technexion/twister/twister.c b/board/technexion/twister/twister.c index 1166886e1d3..0590e5f8afe 100644 --- a/board/technexion/twister/twister.c +++ b/board/technexion/twister/twister.c @@ -18,10 +18,8 @@ #include <spl.h> #include <mmc.h> #include <asm/gpio.h> -#ifdef CONFIG_USB_EHCI_HCD #include <usb.h> #include <asm/ehci-omap.h> -#endif #include "twister.h" DECLARE_GLOBAL_DATA_PTR; @@ -45,7 +43,7 @@ static const u32 gpmc_XR16L2751[] = { XR16L2751_GPMC_CONFIG6, }; -#ifdef CONFIG_USB_EHCI_HCD +#ifdef CONFIG_USB_EHCI_OMAP static struct omap_usbhs_board_data usbhs_bdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, @@ -118,19 +116,20 @@ void set_muxconf_regs(void) int board_eth_init(bd_t *bis) { +#ifdef CONFIG_DRIVER_TI_EMAC davinci_emac_initialize(); - +#endif /* init cs for extern lan */ enable_gpmc_cs_config(gpmc_smc911, &gpmc_cfg->cs[5], CONFIG_SMC911X_BASE, GPMC_SIZE_16M); - if (smc911x_initialize(0, CONFIG_SMC911X_BASE) <= 0) - printf("\nError initializing SMC911x controlleri\n"); - +#ifdef CONFIG_SMC911X + return smc911x_initialize(0, CONFIG_SMC911X_BASE); +#else return 0; +#endif } -#if defined(CONFIG_MMC_OMAP_HS) && \ - !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_MMC_OMAP_HS) int board_mmc_init(bd_t *bis) { return omap_mmc_init(0, 0, 0, -1, -1); diff --git a/cmd/Kconfig b/cmd/Kconfig index 38406fcfdac..d532c9fc41c 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -816,6 +816,13 @@ config CMD_MMC help MMC memory mapped support. +config CMD_MMC_RPMB + bool "Enable support for RPMB in the mmc command" + depends on CMD_MMC + help + Enable the commands for reading, writing and programming the + key for the Replay Protection Memory Block partition in eMMC. + config CMD_NAND bool "nand" default y if NAND_SUNXI @@ -1222,6 +1229,13 @@ config CMD_BMP the image into RAM, then using this command to look at it or display it. +config CMD_BOOTCOUNT + bool "bootcount" + depends on BOOTCOUNT_LIMIT + help + Enable the bootcount command, which allows interrogation and + reset of the bootcounter. + config CMD_BSP bool "Enable board-specific commands" help @@ -1477,25 +1491,37 @@ config HASH_VERIFY help Add -v option to verify data against a hash. +config CMD_TPM_V1 + bool + +config CMD_TPM_V2 + bool + config CMD_TPM bool "Enable the 'tpm' command" - depends on TPM + depends on TPM_V1 || TPM_V2 + select CMD_TPM_V1 if TPM_V1 + select CMD_TPM_V2 if TPM_V2 help This provides a means to talk to a TPM from the command line. A wide range of commands if provided - see 'tpm help' for details. The command requires a suitable TPM on your board and the correct driver must be enabled. +if CMD_TPM + config CMD_TPM_TEST bool "Enable the 'tpm test' command" - depends on CMD_TPM + depends on TPM_V1 help - This provides a a series of tests to confirm that the TPM is working - correctly. The tests cover initialisation, non-volatile RAM, extend, - global lock and checking that timing is within expectations. The - tests pass correctly on Infineon TPMs but may need to be adjusted + This provides a a series of tests to confirm that the TPMv1.x is + working correctly. The tests cover initialisation, non-volatile RAM, + extend, global lock and checking that timing is within expectations. + The tests pass correctly on Infineon TPMs but may need to be adjusted for other devices. +endif + endmenu menu "Firmware commands" diff --git a/cmd/Makefile b/cmd/Makefile index 0d7322ee0a4..e0088df33bd 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_CMD_BEDBUG) += bedbug.o obj-$(CONFIG_CMD_BINOP) += binop.o obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o obj-$(CONFIG_CMD_BMP) += bmp.o +obj-$(CONFIG_CMD_BOOTCOUNT) += bootcount.o obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o obj-$(CONFIG_CMD_BOOTMENU) += bootmenu.o obj-$(CONFIG_CMD_BOOTSTAGE) += bootstage.o @@ -119,8 +120,10 @@ obj-$(CONFIG_CMD_TERMINAL) += terminal.o obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_TRACE) += trace.o obj-$(CONFIG_HUSH_PARSER) += test.o -obj-$(CONFIG_CMD_TPM) += tpm.o +obj-$(CONFIG_CMD_TPM) += tpm-common.o +obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o obj-$(CONFIG_CMD_TPM_TEST) += tpm_test.o +obj-$(CONFIG_CMD_TPM_V2) += tpm-v2.o obj-$(CONFIG_CMD_CROS_EC) += cros_ec.o obj-$(CONFIG_CMD_TSI148) += tsi148.o obj-$(CONFIG_CMD_UBI) += ubi.o diff --git a/cmd/bootcount.c b/cmd/bootcount.c new file mode 100644 index 00000000000..c358418ebe5 --- /dev/null +++ b/cmd/bootcount.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <common.h> +#include <command.h> +#include <bootcount.h> + +static int do_bootcount_print(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + printf("%lu\n", bootcount_load()); + return CMD_RET_SUCCESS; +} + +static int do_bootcount_reset(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + /* + * note that we're explicitly not resetting the environment + * variable, so you still have the old bootcounter available + */ + bootcount_store(0); + return CMD_RET_SUCCESS; +} + +static cmd_tbl_t bootcount_sub[] = { + U_BOOT_CMD_MKENT(print, 1, 1, do_bootcount_print, "", ""), + U_BOOT_CMD_MKENT(reset, 1, 1, do_bootcount_reset, "", ""), +}; + +static int do_bootcount(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + cmd_tbl_t *cp; + + if (argc < 2) + return CMD_RET_USAGE; + + /* drop initial "bootcount" arg */ + argc--; + argv++; + + cp = find_cmd_tbl(argv[0], bootcount_sub, ARRAY_SIZE(bootcount_sub)); + if (cp) + return cp->cmd(cmdtp, flag, argc, argv); + + return CMD_RET_USAGE; +} + +#if CONFIG_IS_ENABLED(SYS_LONGHELP) +static char bootcount_help_text[] = + "print - print current bootcounter\n" + "reset - reset the bootcounter" + ; +#endif + +U_BOOT_CMD(bootcount, 2, 1, do_bootcount, + "bootcount", +#if CONFIG_IS_ENABLED(SYS_LONGHELP) + bootcount_help_text +#endif +); diff --git a/cmd/mmc.c b/cmd/mmc.c index 68bbf1f5135..a3357eff8fa 100644 --- a/cmd/mmc.c +++ b/cmd/mmc.c @@ -128,7 +128,7 @@ static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_SUCCESS; } -#ifdef CONFIG_SUPPORT_EMMC_RPMB +#if CONFIG_IS_ENABLED(CMD_MMC_RPMB) static int confirm_key_prog(void) { puts("Warning: Programming authentication key can be done only once !\n" @@ -886,7 +886,7 @@ static cmd_tbl_t cmd_mmc[] = { U_BOOT_CMD_MKENT(partconf, 5, 0, do_mmc_partconf, "", ""), U_BOOT_CMD_MKENT(rst-function, 3, 0, do_mmc_rst_func, "", ""), #endif -#ifdef CONFIG_SUPPORT_EMMC_RPMB +#if CONFIG_IS_ENABLED(CMD_MMC_RPMB) U_BOOT_CMD_MKENT(rpmb, CONFIG_SYS_MAXARGS, 1, do_mmcrpmb, "", ""), #endif U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""), @@ -953,7 +953,7 @@ U_BOOT_CMD( " - Change the RST_n_FUNCTION field of the specified device\n" " WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.\n" #endif -#ifdef CONFIG_SUPPORT_EMMC_RPMB +#if CONFIG_IS_ENABLED(CMD_MMC_RPMB) "mmc rpmb read addr blk# cnt [address of auth-key] - block size is 256 bytes\n" "mmc rpmb write addr blk# cnt <address of auth-key> - block size is 256 bytes\n" "mmc rpmb key <address of auth-key> - program the RPMB authentication key.\n" diff --git a/cmd/tpm-common.c b/cmd/tpm-common.c new file mode 100644 index 00000000000..6cf9fcc9ac8 --- /dev/null +++ b/cmd/tpm-common.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2013 The Chromium OS Authors. + */ + +#include <common.h> +#include <command.h> +#include <dm.h> +#include <asm/unaligned.h> +#include <linux/string.h> +#include <tpm-common.h> +#include "tpm-user-utils.h" + +/** + * Print a byte string in hexdecimal format, 16-bytes per line. + * + * @param data byte string to be printed + * @param count number of bytes to be printed + */ +void print_byte_string(u8 *data, size_t count) +{ + int i, print_newline = 0; + + for (i = 0; i < count; i++) { + printf(" %02x", data[i]); + print_newline = (i % 16 == 15); + if (print_newline) + putc('\n'); + } + /* Avoid duplicated newline at the end */ + if (!print_newline) + putc('\n'); +} + +/** + * Convert a text string of hexdecimal values into a byte string. + * + * @param bytes text string of hexdecimal values with no space + * between them + * @param data output buffer for byte string. The caller has to make + * sure it is large enough for storing the output. If + * NULL is passed, a large enough buffer will be allocated, + * and the caller must free it. + * @param count_ptr output variable for the length of byte string + * @return pointer to output buffer + */ +void *parse_byte_string(char *bytes, u8 *data, size_t *count_ptr) +{ + char byte[3]; + size_t count, length; + int i; + + if (!bytes) + return NULL; + length = strlen(bytes); + count = length / 2; + + if (!data) + data = malloc(count); + if (!data) + return NULL; + + byte[2] = '\0'; + for (i = 0; i < length; i += 2) { + byte[0] = bytes[i]; + byte[1] = bytes[i + 1]; + data[i / 2] = (u8)simple_strtoul(byte, NULL, 16); + } + + if (count_ptr) + *count_ptr = count; + + return data; +} + +/** + * report_return_code() - Report any error and return failure or success + * + * @param return_code TPM command return code + * @return value of enum command_ret_t + */ +int report_return_code(int return_code) +{ + if (return_code) { + printf("Error: %d\n", return_code); + return CMD_RET_FAILURE; + } else { + return CMD_RET_SUCCESS; + } +} + +/** + * Return number of values defined by a type string. + * + * @param type_str type string + * @return number of values of type string + */ +int type_string_get_num_values(const char *type_str) +{ + return strlen(type_str); +} + +/** + * Return total size of values defined by a type string. + * + * @param type_str type string + * @return total size of values of type string, or 0 if type string + * contains illegal type character. + */ +size_t type_string_get_space_size(const char *type_str) +{ + size_t size; + + for (size = 0; *type_str; type_str++) { + switch (*type_str) { + case 'b': + size += 1; + break; + case 'w': + size += 2; + break; + case 'd': + size += 4; + break; + default: + return 0; + } + } + + return size; +} + +/** + * Allocate a buffer large enough to hold values defined by a type + * string. The caller has to free the buffer. + * + * @param type_str type string + * @param count pointer for storing size of buffer + * @return pointer to buffer or NULL on error + */ +void *type_string_alloc(const char *type_str, u32 *count) +{ + void *data; + size_t size; + + size = type_string_get_space_size(type_str); + if (!size) + return NULL; + data = malloc(size); + if (data) + *count = size; + + return data; +} + +/** + * Pack values defined by a type string into a buffer. The buffer must have + * large enough space. + * + * @param type_str type string + * @param values text strings of values to be packed + * @param data output buffer of values + * @return 0 on success, non-0 on error + */ +int type_string_pack(const char *type_str, char * const values[], + u8 *data) +{ + size_t offset; + u32 value; + + for (offset = 0; *type_str; type_str++, values++) { + value = simple_strtoul(values[0], NULL, 0); + switch (*type_str) { + case 'b': + data[offset] = value; + offset += 1; + break; + case 'w': + put_unaligned_be16(value, data + offset); + offset += 2; + break; + case 'd': + put_unaligned_be32(value, data + offset); + offset += 4; + break; + default: + return -1; + } + } + + return 0; +} + +/** + * Read values defined by a type string from a buffer, and write these values + * to environment variables. + * + * @param type_str type string + * @param data input buffer of values + * @param vars names of environment variables + * @return 0 on success, non-0 on error + */ +int type_string_write_vars(const char *type_str, u8 *data, + char * const vars[]) +{ + size_t offset; + u32 value; + + for (offset = 0; *type_str; type_str++, vars++) { + switch (*type_str) { + case 'b': + value = data[offset]; + offset += 1; + break; + case 'w': + value = get_unaligned_be16(data + offset); + offset += 2; + break; + case 'd': + value = get_unaligned_be32(data + offset); + offset += 4; + break; + default: + return -1; + } + if (env_set_ulong(*vars, value)) + return -1; + } + + return 0; +} + +int get_tpm(struct udevice **devp) +{ + int rc; + + rc = uclass_first_device_err(UCLASS_TPM, devp); + if (rc) { + printf("Could not find TPM (ret=%d)\n", rc); + return CMD_RET_FAILURE; + } + + return 0; +} + +int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + struct udevice *dev; + char buf[80]; + int rc; + + rc = get_tpm(&dev); + if (rc) + return rc; + rc = tpm_get_desc(dev, buf, sizeof(buf)); + if (rc < 0) { + printf("Couldn't get TPM info (%d)\n", rc); + return CMD_RET_FAILURE; + } + printf("%s\n", buf); + + return 0; +} + +int do_tpm_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (argc != 1) + return CMD_RET_USAGE; + + return report_return_code(tpm_init()); +} + +int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + cmd_tbl_t *tpm_commands, *cmd; + unsigned int size; + + if (argc < 2) + return CMD_RET_USAGE; + + tpm_commands = get_tpm_commands(&size); + + cmd = find_cmd_tbl(argv[1], tpm_commands, size); + if (!cmd) + return CMD_RET_USAGE; + + return cmd->cmd(cmdtp, flag, argc - 1, argv + 1); +} diff --git a/cmd/tpm-user-utils.h b/cmd/tpm-user-utils.h new file mode 100644 index 00000000000..8ce98617843 --- /dev/null +++ b/cmd/tpm-user-utils.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#ifndef __TPM_USER_UTILS_H +#define __TPM_USER_UTILS_H + +void print_byte_string(u8 *data, size_t count); +void *parse_byte_string(char *bytes, u8 *data, size_t *count_ptr); +int report_return_code(int return_code); +int type_string_get_num_values(const char *type_str); +size_t type_string_get_space_size(const char *type_str); +void *type_string_alloc(const char *type_str, u32 *count); +int type_string_pack(const char *type_str, char * const values[], u8 *data); +int type_string_write_vars(const char *type_str, u8 *data, char * const vars[]); +int get_tpm(struct udevice **devp); + +int do_tpm_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]); +int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]); +int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + +#endif /* __TPM_USER_UTILS_H */ diff --git a/cmd/tpm.c b/cmd/tpm-v1.c index c173bcfe42a..0874c4d7baf 100644 --- a/cmd/tpm.c +++ b/cmd/tpm-v1.c @@ -4,241 +4,14 @@ */ #include <common.h> -#include <command.h> -#include <dm.h> #include <malloc.h> -#include <tpm.h> #include <asm/unaligned.h> -#include <linux/string.h> +#include <tpm-common.h> +#include <tpm-v1.h> +#include "tpm-user-utils.h" -/* Useful constants */ -enum { - DIGEST_LENGTH = 20, - /* max lengths, valid for RSA keys <= 2048 bits */ - TPM_PUBKEY_MAX_LENGTH = 288, -}; - -/** - * Print a byte string in hexdecimal format, 16-bytes per line. - * - * @param data byte string to be printed - * @param count number of bytes to be printed - */ -static void print_byte_string(uint8_t *data, size_t count) -{ - int i, print_newline = 0; - - for (i = 0; i < count; i++) { - printf(" %02x", data[i]); - print_newline = (i % 16 == 15); - if (print_newline) - putc('\n'); - } - /* Avoid duplicated newline at the end */ - if (!print_newline) - putc('\n'); -} - -/** - * Convert a text string of hexdecimal values into a byte string. - * - * @param bytes text string of hexdecimal values with no space - * between them - * @param data output buffer for byte string. The caller has to make - * sure it is large enough for storing the output. If - * NULL is passed, a large enough buffer will be allocated, - * and the caller must free it. - * @param count_ptr output variable for the length of byte string - * @return pointer to output buffer - */ -static void *parse_byte_string(char *bytes, uint8_t *data, size_t *count_ptr) -{ - char byte[3]; - size_t count, length; - int i; - - if (!bytes) - return NULL; - length = strlen(bytes); - count = length / 2; - - if (!data) - data = malloc(count); - if (!data) - return NULL; - - byte[2] = '\0'; - for (i = 0; i < length; i += 2) { - byte[0] = bytes[i]; - byte[1] = bytes[i + 1]; - data[i / 2] = (uint8_t)simple_strtoul(byte, NULL, 16); - } - - if (count_ptr) - *count_ptr = count; - - return data; -} - -/** - * report_return_code() - Report any error and return failure or success - * - * @param return_code TPM command return code - * @return value of enum command_ret_t - */ -static int report_return_code(int return_code) -{ - if (return_code) { - printf("Error: %d\n", return_code); - return CMD_RET_FAILURE; - } else { - return CMD_RET_SUCCESS; - } -} - -/** - * Return number of values defined by a type string. - * - * @param type_str type string - * @return number of values of type string - */ -static int type_string_get_num_values(const char *type_str) -{ - return strlen(type_str); -} - -/** - * Return total size of values defined by a type string. - * - * @param type_str type string - * @return total size of values of type string, or 0 if type string - * contains illegal type character. - */ -static size_t type_string_get_space_size(const char *type_str) -{ - size_t size; - - for (size = 0; *type_str; type_str++) { - switch (*type_str) { - case 'b': - size += 1; - break; - case 'w': - size += 2; - break; - case 'd': - size += 4; - break; - default: - return 0; - } - } - - return size; -} - -/** - * Allocate a buffer large enough to hold values defined by a type - * string. The caller has to free the buffer. - * - * @param type_str type string - * @param count pointer for storing size of buffer - * @return pointer to buffer or NULL on error - */ -static void *type_string_alloc(const char *type_str, uint32_t *count) -{ - void *data; - size_t size; - - size = type_string_get_space_size(type_str); - if (!size) - return NULL; - data = malloc(size); - if (data) - *count = size; - - return data; -} - -/** - * Pack values defined by a type string into a buffer. The buffer must have - * large enough space. - * - * @param type_str type string - * @param values text strings of values to be packed - * @param data output buffer of values - * @return 0 on success, non-0 on error - */ -static int type_string_pack(const char *type_str, char * const values[], - uint8_t *data) -{ - size_t offset; - uint32_t value; - - for (offset = 0; *type_str; type_str++, values++) { - value = simple_strtoul(values[0], NULL, 0); - switch (*type_str) { - case 'b': - data[offset] = value; - offset += 1; - break; - case 'w': - put_unaligned_be16(value, data + offset); - offset += 2; - break; - case 'd': - put_unaligned_be32(value, data + offset); - offset += 4; - break; - default: - return -1; - } - } - - return 0; -} - -/** - * Read values defined by a type string from a buffer, and write these values - * to environment variables. - * - * @param type_str type string - * @param data input buffer of values - * @param vars names of environment variables - * @return 0 on success, non-0 on error - */ -static int type_string_write_vars(const char *type_str, uint8_t *data, - char * const vars[]) -{ - size_t offset; - uint32_t value; - - for (offset = 0; *type_str; type_str++, vars++) { - switch (*type_str) { - case 'b': - value = data[offset]; - offset += 1; - break; - case 'w': - value = get_unaligned_be16(data + offset); - offset += 2; - break; - case 'd': - value = get_unaligned_be32(data + offset); - offset += 4; - break; - default: - return -1; - } - if (env_set_ulong(*vars, value)) - return -1; - } - - return 0; -} - -static int do_tpm_startup(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_startup(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { enum tpm_startup_type mode; @@ -258,10 +31,10 @@ static int do_tpm_startup(cmd_tbl_t *cmdtp, int flag, return report_return_code(tpm_startup(mode)); } -static int do_tpm_nv_define_space(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_nv_define_space(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t index, perm, size; + u32 index, perm, size; if (argc != 4) return CMD_RET_USAGE; @@ -272,10 +45,10 @@ static int do_tpm_nv_define_space(cmd_tbl_t *cmdtp, int flag, return report_return_code(tpm_nv_define_space(index, perm, size)); } -static int do_tpm_nv_read_value(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_nv_read_value(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t index, count, rc; + u32 index, count, rc; void *data; if (argc != 4) @@ -293,10 +66,10 @@ static int do_tpm_nv_read_value(cmd_tbl_t *cmdtp, int flag, return report_return_code(rc); } -static int do_tpm_nv_write_value(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_nv_write_value(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t index, rc; + u32 index, rc; size_t count; void *data; @@ -315,11 +88,11 @@ static int do_tpm_nv_write_value(cmd_tbl_t *cmdtp, int flag, return report_return_code(rc); } -static int do_tpm_extend(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_extend(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t index, rc; - uint8_t in_digest[20], out_digest[20]; + u32 index, rc; + u8 in_digest[20], out_digest[20]; if (argc != 3) return CMD_RET_USAGE; @@ -338,10 +111,10 @@ static int do_tpm_extend(cmd_tbl_t *cmdtp, int flag, return report_return_code(rc); } -static int do_tpm_pcr_read(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_pcr_read(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t index, count, rc; + u32 index, count, rc; void *data; if (argc != 4) @@ -359,22 +132,22 @@ static int do_tpm_pcr_read(cmd_tbl_t *cmdtp, int flag, return report_return_code(rc); } -static int do_tpm_tsc_physical_presence(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_tsc_physical_presence(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint16_t presence; + u16 presence; if (argc != 2) return CMD_RET_USAGE; - presence = (uint16_t)simple_strtoul(argv[1], NULL, 0); + presence = (u16)simple_strtoul(argv[1], NULL, 0); return report_return_code(tpm_tsc_physical_presence(presence)); } -static int do_tpm_read_pubek(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_read_pubek(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t count, rc; + u32 count, rc; void *data; if (argc != 3) @@ -391,22 +164,22 @@ static int do_tpm_read_pubek(cmd_tbl_t *cmdtp, int flag, return report_return_code(rc); } -static int do_tpm_physical_set_deactivated(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_physical_set_deactivated(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint8_t state; + u8 state; if (argc != 2) return CMD_RET_USAGE; - state = (uint8_t)simple_strtoul(argv[1], NULL, 0); + state = (u8)simple_strtoul(argv[1], NULL, 0); return report_return_code(tpm_physical_set_deactivated(state)); } -static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t cap_area, sub_cap, rc; + u32 cap_area, sub_cap, rc; void *cap; size_t count; @@ -426,63 +199,14 @@ static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag, return report_return_code(rc); } -#define TPM_COMMAND_NO_ARG(cmd) \ -static int do_##cmd(cmd_tbl_t *cmdtp, int flag, \ - int argc, char * const argv[]) \ -{ \ - if (argc != 1) \ - return CMD_RET_USAGE; \ - return report_return_code(cmd()); \ -} - -TPM_COMMAND_NO_ARG(tpm_init) -TPM_COMMAND_NO_ARG(tpm_self_test_full) -TPM_COMMAND_NO_ARG(tpm_continue_self_test) -TPM_COMMAND_NO_ARG(tpm_force_clear) -TPM_COMMAND_NO_ARG(tpm_physical_enable) -TPM_COMMAND_NO_ARG(tpm_physical_disable) - -static int get_tpm(struct udevice **devp) -{ - int rc; - - rc = uclass_first_device_err(UCLASS_TPM, devp); - if (rc) { - printf("Could not find TPM (ret=%d)\n", rc); - return CMD_RET_FAILURE; - } - - return 0; -} - -static int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc, - char *const argv[]) -{ - struct udevice *dev; - char buf[80]; - int rc; - - rc = get_tpm(&dev); - if (rc) - return rc; - rc = tpm_get_desc(dev, buf, sizeof(buf)); - if (rc < 0) { - printf("Couldn't get TPM info (%d)\n", rc); - return CMD_RET_FAILURE; - } - printf("%s\n", buf); - - return 0; -} - -static int do_tpm_raw_transfer(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_raw_transfer(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { struct udevice *dev; void *command; - uint8_t response[1024]; + u8 response[1024]; size_t count, response_length = sizeof(response); - uint32_t rc; + u32 rc; command = parse_byte_string(argv[1], NULL, &count); if (!command) { @@ -504,10 +228,10 @@ static int do_tpm_raw_transfer(cmd_tbl_t *cmdtp, int flag, return report_return_code(rc); } -static int do_tpm_nv_define(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_nv_define(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t index, perm, size; + u32 index, perm, size; if (argc != 4) return CMD_RET_USAGE; @@ -522,10 +246,10 @@ static int do_tpm_nv_define(cmd_tbl_t *cmdtp, int flag, return report_return_code(tpm_nv_define_space(index, perm, size)); } -static int do_tpm_nv_read(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_nv_read(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t index, count, err; + u32 index, count, err; void *data; if (argc < 3) @@ -551,10 +275,10 @@ static int do_tpm_nv_read(cmd_tbl_t *cmdtp, int flag, return report_return_code(err); } -static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t index, count, err; + u32 index, count, err; void *data; if (argc < 3) @@ -581,10 +305,10 @@ static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag, #ifdef CONFIG_TPM_AUTH_SESSIONS -static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t auth_handle, err; + u32 auth_handle, err; err = tpm_oiap(&auth_handle); @@ -595,10 +319,10 @@ static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag, static int do_tpm_load_key_by_sha1(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - uint32_t parent_handle = 0; - uint32_t key_len, key_handle, err; - uint8_t usage_auth[DIGEST_LENGTH]; - uint8_t parent_hash[DIGEST_LENGTH]; + u32 parent_handle = 0; + u32 key_len, key_handle, err; + u8 usage_auth[DIGEST_LENGTH]; + u8 parent_hash[DIGEST_LENGTH]; void *key; if (argc < 5) @@ -630,11 +354,11 @@ static int do_tpm_load_key_by_sha1(cmd_tbl_t *cmdtp, int flag, int argc, char * } #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ -static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t parent_handle, key_len, key_handle, err; - uint8_t usage_auth[DIGEST_LENGTH]; + u32 parent_handle, key_len, key_handle, err; + u8 usage_auth[DIGEST_LENGTH]; void *key; if (argc < 5) @@ -648,19 +372,19 @@ static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag, parse_byte_string(argv[4], usage_auth, NULL); err = tpm_load_key2_oiap(parent_handle, key, key_len, usage_auth, - &key_handle); + &key_handle); if (!err) printf("Key handle is 0x%x\n", key_handle); return report_return_code(err); } -static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { - uint32_t key_handle, err; - uint8_t usage_auth[DIGEST_LENGTH]; - uint8_t pub_key_buffer[TPM_PUBKEY_MAX_LENGTH]; + u32 key_handle, err; + u8 usage_auth[DIGEST_LENGTH]; + u8 pub_key_buffer[TPM_PUBKEY_MAX_LENGTH]; size_t pub_key_len = sizeof(pub_key_buffer); if (argc < 3) @@ -671,8 +395,8 @@ static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag, return CMD_RET_FAILURE; parse_byte_string(argv[2], usage_auth, NULL); - err = tpm_get_pub_key_oiap(key_handle, usage_auth, - pub_key_buffer, &pub_key_len); + err = tpm_get_pub_key_oiap(key_handle, usage_auth, pub_key_buffer, + &pub_key_len); if (!err) { printf("dump of received pub key structure:\n"); print_byte_string(pub_key_buffer, pub_key_len); @@ -720,9 +444,9 @@ static int do_tpm_flush(cmd_tbl_t *cmdtp, int flag, int argc, } if (!strcasecmp(argv[2], "all")) { - uint16_t res_count; - uint8_t buf[288]; - uint8_t *ptr; + u16 res_count; + u8 buf[288]; + u8 *ptr; int err; uint i; @@ -738,7 +462,7 @@ static int do_tpm_flush(cmd_tbl_t *cmdtp, int flag, int argc, for (i = 0; i < res_count; ++i, ptr += 4) tpm_flush_specific(get_unaligned_be32(ptr), type); } else { - uint32_t handle = simple_strtoul(argv[2], NULL, 0); + u32 handle = simple_strtoul(argv[2], NULL, 0); if (!handle) { printf("Illegal resource handle %s\n", argv[2]); @@ -756,9 +480,9 @@ static int do_tpm_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int type = 0; - uint16_t res_count; - uint8_t buf[288]; - uint8_t *ptr; + u16 res_count; + u8 buf[288]; + u8 *ptr; int err; uint i; @@ -813,51 +537,53 @@ static int do_tpm_list(cmd_tbl_t *cmdtp, int flag, int argc, } #endif /* CONFIG_TPM_LIST_RESOURCES */ -#define MAKE_TPM_CMD_ENTRY(cmd) \ - U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "") +TPM_COMMAND_NO_ARG(tpm_self_test_full) +TPM_COMMAND_NO_ARG(tpm_continue_self_test) +TPM_COMMAND_NO_ARG(tpm_force_clear) +TPM_COMMAND_NO_ARG(tpm_physical_enable) +TPM_COMMAND_NO_ARG(tpm_physical_disable) -static cmd_tbl_t tpm_commands[] = { +static cmd_tbl_t tpm1_commands[] = { U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), - U_BOOT_CMD_MKENT(init, 0, 1, - do_tpm_init, "", ""), + U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""), U_BOOT_CMD_MKENT(startup, 0, 1, - do_tpm_startup, "", ""), + do_tpm_startup, "", ""), U_BOOT_CMD_MKENT(self_test_full, 0, 1, - do_tpm_self_test_full, "", ""), + do_tpm_self_test_full, "", ""), U_BOOT_CMD_MKENT(continue_self_test, 0, 1, - do_tpm_continue_self_test, "", ""), + do_tpm_continue_self_test, "", ""), U_BOOT_CMD_MKENT(force_clear, 0, 1, - do_tpm_force_clear, "", ""), + do_tpm_force_clear, "", ""), U_BOOT_CMD_MKENT(physical_enable, 0, 1, - do_tpm_physical_enable, "", ""), + do_tpm_physical_enable, "", ""), U_BOOT_CMD_MKENT(physical_disable, 0, 1, - do_tpm_physical_disable, "", ""), + do_tpm_physical_disable, "", ""), U_BOOT_CMD_MKENT(nv_define_space, 0, 1, - do_tpm_nv_define_space, "", ""), + do_tpm_nv_define_space, "", ""), U_BOOT_CMD_MKENT(nv_read_value, 0, 1, - do_tpm_nv_read_value, "", ""), + do_tpm_nv_read_value, "", ""), U_BOOT_CMD_MKENT(nv_write_value, 0, 1, - do_tpm_nv_write_value, "", ""), + do_tpm_nv_write_value, "", ""), U_BOOT_CMD_MKENT(extend, 0, 1, - do_tpm_extend, "", ""), + do_tpm_extend, "", ""), U_BOOT_CMD_MKENT(pcr_read, 0, 1, - do_tpm_pcr_read, "", ""), + do_tpm_pcr_read, "", ""), U_BOOT_CMD_MKENT(tsc_physical_presence, 0, 1, - do_tpm_tsc_physical_presence, "", ""), + do_tpm_tsc_physical_presence, "", ""), U_BOOT_CMD_MKENT(read_pubek, 0, 1, - do_tpm_read_pubek, "", ""), + do_tpm_read_pubek, "", ""), U_BOOT_CMD_MKENT(physical_set_deactivated, 0, 1, - do_tpm_physical_set_deactivated, "", ""), + do_tpm_physical_set_deactivated, "", ""), U_BOOT_CMD_MKENT(get_capability, 0, 1, - do_tpm_get_capability, "", ""), + do_tpm_get_capability, "", ""), U_BOOT_CMD_MKENT(raw_transfer, 0, 1, - do_tpm_raw_transfer, "", ""), + do_tpm_raw_transfer, "", ""), U_BOOT_CMD_MKENT(nv_define, 0, 1, - do_tpm_nv_define, "", ""), + do_tpm_nv_define, "", ""), U_BOOT_CMD_MKENT(nv_read, 0, 1, - do_tpm_nv_read, "", ""), + do_tpm_nv_read, "", ""), U_BOOT_CMD_MKENT(nv_write, 0, 1, - do_tpm_nv_write, "", ""), + do_tpm_nv_write, "", ""), #ifdef CONFIG_TPM_AUTH_SESSIONS U_BOOT_CMD_MKENT(oiap, 0, 1, do_tpm_oiap, "", ""), @@ -882,21 +608,15 @@ static cmd_tbl_t tpm_commands[] = { #endif /* CONFIG_TPM_LIST_RESOURCES */ }; -static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +cmd_tbl_t *get_tpm_commands(unsigned int *size) { - cmd_tbl_t *tpm_cmd; - - if (argc < 2) - return CMD_RET_USAGE; - tpm_cmd = find_cmd_tbl(argv[1], tpm_commands, ARRAY_SIZE(tpm_commands)); - if (!tpm_cmd) - return CMD_RET_USAGE; + *size = ARRAY_SIZE(tpm1_commands); - return tpm_cmd->cmd(cmdtp, flag, argc - 1, argv + 1); + return tpm1_commands; } U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm, -"Issue a TPM command", +"Issue a TPMv1.x command", "cmd args...\n" " - Issue TPM command <cmd> with arguments <args...>.\n" "Admin Startup and State Commands:\n" diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c new file mode 100644 index 00000000000..38add4f4622 --- /dev/null +++ b/cmd/tpm-v2.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2018 Bootlin + * Author: Miquel Raynal <miquel.raynal@bootlin.com> + */ + +#include <common.h> +#include <dm.h> +#include <log.h> +#include <mapmem.h> +#include <tpm-common.h> +#include <tpm-v2.h> +#include "tpm-user-utils.h" + +static int do_tpm2_startup(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + enum tpm2_startup_types mode; + + if (argc != 2) + return CMD_RET_USAGE; + + if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) { + mode = TPM2_SU_CLEAR; + } else if (!strcasecmp("TPM2_SU_STATE", argv[1])) { + mode = TPM2_SU_STATE; + } else { + printf("Couldn't recognize mode string: %s\n", argv[1]); + return CMD_RET_FAILURE; + } + + return report_return_code(tpm2_startup(mode)); +} + +static int do_tpm2_self_test(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + enum tpm2_yes_no full_test; + + if (argc != 2) + return CMD_RET_USAGE; + + if (!strcasecmp("full", argv[1])) { + full_test = TPMI_YES; + } else if (!strcasecmp("continue", argv[1])) { + full_test = TPMI_NO; + } else { + printf("Couldn't recognize test mode: %s\n", argv[1]); + return CMD_RET_FAILURE; + } + + return report_return_code(tpm2_self_test(full_test)); +} + +static int do_tpm2_clear(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 handle = 0; + const char *pw = (argc < 3) ? NULL : argv[2]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + + if (argc < 2 || argc > 3) + return CMD_RET_USAGE; + + if (pw_sz > TPM2_DIGEST_LEN) + return -EINVAL; + + if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) + handle = TPM2_RH_LOCKOUT; + else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) + handle = TPM2_RH_PLATFORM; + else + return CMD_RET_USAGE; + + return report_return_code(tpm2_clear(handle, pw, pw_sz)); +} + +static int do_tpm2_pcr_extend(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + struct udevice *dev; + struct tpm_chip_priv *priv; + u32 index = simple_strtoul(argv[1], NULL, 0); + void *digest = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0); + int ret; + u32 rc; + + if (argc != 3) + return CMD_RET_USAGE; + + ret = uclass_first_device_err(UCLASS_TPM, &dev); + if (ret) + return ret; + + priv = dev_get_uclass_priv(dev); + if (!priv) + return -EINVAL; + + if (index >= priv->pcr_count) + return -EINVAL; + + rc = tpm2_pcr_extend(index, digest); + + unmap_sysmem(digest); + + return report_return_code(rc); +} + +static int do_tpm_pcr_read(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + struct udevice *dev; + struct tpm_chip_priv *priv; + u32 index, rc; + unsigned int updates; + void *data; + int ret; + + if (argc != 3) + return CMD_RET_USAGE; + + ret = uclass_first_device_err(UCLASS_TPM, &dev); + if (ret) + return ret; + + priv = dev_get_uclass_priv(dev); + if (!priv) + return -EINVAL; + + index = simple_strtoul(argv[1], NULL, 0); + if (index >= priv->pcr_count) + return -EINVAL; + + data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0); + + rc = tpm2_pcr_read(index, priv->pcr_select_min, data, &updates); + if (!rc) { + printf("PCR #%u content (%d known updates):\n", index, updates); + print_byte_string(data, TPM2_DIGEST_LEN); + } + + unmap_sysmem(data); + + return report_return_code(rc); +} + +static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 capability, property, rc; + u8 *data; + size_t count; + int i, j; + + if (argc != 5) + return CMD_RET_USAGE; + + capability = simple_strtoul(argv[1], NULL, 0); + property = simple_strtoul(argv[2], NULL, 0); + data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0); + count = simple_strtoul(argv[4], NULL, 0); + + rc = tpm2_get_capability(capability, property, data, count); + if (rc) + goto unmap_data; + + printf("Capabilities read from TPM:\n"); + for (i = 0; i < count; i++) { + printf("Property 0x"); + for (j = 0; j < 4; j++) + printf("%02x", data[(i * 8) + j]); + printf(": 0x"); + for (j = 4; j < 8; j++) + printf("%02x", data[(i * 8) + j]); + printf("\n"); + } + +unmap_data: + unmap_sysmem(data); + + return report_return_code(rc); +} + +static int do_tpm_dam_reset(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *pw = (argc < 2) ? NULL : argv[1]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + + if (argc > 2) + return CMD_RET_USAGE; + + if (pw_sz > TPM2_DIGEST_LEN) + return -EINVAL; + + return report_return_code(tpm2_dam_reset(pw, pw_sz)); +} + +static int do_tpm_dam_parameters(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *pw = (argc < 5) ? NULL : argv[4]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + /* + * No Dictionary Attack Mitigation (DAM) means: + * maxtries = 0xFFFFFFFF, recovery_time = 1, lockout_recovery = 0 + */ + unsigned long int max_tries; + unsigned long int recovery_time; + unsigned long int lockout_recovery; + + if (argc < 4 || argc > 5) + return CMD_RET_USAGE; + + if (pw_sz > TPM2_DIGEST_LEN) + return -EINVAL; + + if (strict_strtoul(argv[1], 0, &max_tries)) + return CMD_RET_USAGE; + + if (strict_strtoul(argv[2], 0, &recovery_time)) + return CMD_RET_USAGE; + + if (strict_strtoul(argv[3], 0, &lockout_recovery)) + return CMD_RET_USAGE; + + log(LOGC_NONE, LOGL_INFO, "Changing dictionary attack parameters:\n"); + log(LOGC_NONE, LOGL_INFO, "- maxTries: %lu", max_tries); + log(LOGC_NONE, LOGL_INFO, "- recoveryTime: %lu\n", recovery_time); + log(LOGC_NONE, LOGL_INFO, "- lockoutRecovery: %lu\n", lockout_recovery); + + return report_return_code(tpm2_dam_parameters(pw, pw_sz, max_tries, + recovery_time, + lockout_recovery)); +} + +static int do_tpm_change_auth(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + u32 handle; + const char *newpw = argv[2]; + const char *oldpw = (argc == 3) ? NULL : argv[3]; + const ssize_t newpw_sz = strlen(newpw); + const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0; + + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + if (newpw_sz > TPM2_DIGEST_LEN || oldpw_sz > TPM2_DIGEST_LEN) + return -EINVAL; + + if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) + handle = TPM2_RH_LOCKOUT; + else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1])) + handle = TPM2_RH_ENDORSEMENT; + else if (!strcasecmp("TPM2_RH_OWNER", argv[1])) + handle = TPM2_RH_OWNER; + else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) + handle = TPM2_RH_PLATFORM; + else + return CMD_RET_USAGE; + + return report_return_code(tpm2_change_auth(handle, newpw, newpw_sz, + oldpw, oldpw_sz)); +} + +static int do_tpm_pcr_setauthpolicy(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 index = simple_strtoul(argv[1], NULL, 0); + char *key = argv[2]; + const char *pw = (argc < 4) ? NULL : argv[3]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + + if (strlen(key) != TPM2_DIGEST_LEN) + return -EINVAL; + + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + return report_return_code(tpm2_pcr_setauthpolicy(pw, pw_sz, index, + key)); +} + +static int do_tpm_pcr_setauthvalue(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + u32 index = simple_strtoul(argv[1], NULL, 0); + char *key = argv[2]; + const ssize_t key_sz = strlen(key); + const char *pw = (argc < 4) ? NULL : argv[3]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + + if (strlen(key) != TPM2_DIGEST_LEN) + return -EINVAL; + + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + return report_return_code(tpm2_pcr_setauthvalue(pw, pw_sz, index, + key, key_sz)); +} + +static cmd_tbl_t tpm2_commands[] = { + U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), + U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""), + U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""), + U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""), + U_BOOT_CMD_MKENT(clear, 0, 1, do_tpm2_clear, "", ""), + U_BOOT_CMD_MKENT(pcr_extend, 0, 1, do_tpm2_pcr_extend, "", ""), + U_BOOT_CMD_MKENT(pcr_read, 0, 1, do_tpm_pcr_read, "", ""), + U_BOOT_CMD_MKENT(get_capability, 0, 1, do_tpm_get_capability, "", ""), + U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm_dam_reset, "", ""), + U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm_dam_parameters, "", ""), + U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm_change_auth, "", ""), + U_BOOT_CMD_MKENT(pcr_setauthpolicy, 0, 1, + do_tpm_pcr_setauthpolicy, "", ""), + U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1, + do_tpm_pcr_setauthvalue, "", ""), +}; + +cmd_tbl_t *get_tpm_commands(unsigned int *size) +{ + *size = ARRAY_SIZE(tpm2_commands); + + return tpm2_commands; +} + +U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", +"<command> [<arguments>]\n" +"\n" +"info\n" +" Show information about the TPM.\n" +"init\n" +" Initialize the software stack. Always the first command to issue.\n" +"startup <mode>\n" +" Issue a TPM2_Startup command.\n" +" <mode> is one of:\n" +" * TPM2_SU_CLEAR (reset state)\n" +" * TPM2_SU_STATE (preserved state)\n" +"self_test <type>\n" +" Test the TPM capabilities.\n" +" <type> is one of:\n" +" * full (perform all tests)\n" +" * continue (only check untested tests)\n" +"clear <hierarchy>\n" +" Issue a TPM2_Clear command.\n" +" <hierarchy> is one of:\n" +" * TPM2_RH_LOCKOUT\n" +" * TPM2_RH_PLATFORM\n" +"pcr_extend <pcr> <digest_addr>\n" +" Extend PCR #<pcr> with digest at <digest_addr>.\n" +" <pcr>: index of the PCR\n" +" <digest_addr>: address of a 32-byte SHA256 digest\n" +"pcr_read <pcr> <digest_addr>\n" +" Read PCR #<pcr> to memory address <digest_addr>.\n" +" <pcr>: index of the PCR\n" +" <digest_addr>: address to store the a 32-byte SHA256 digest\n" +"get_capability <capability> <property> <addr> <count>\n" +" Read and display <count> entries indexed by <capability>/<property>.\n" +" Values are 4 bytes long and are written at <addr>.\n" +" <capability>: capability\n" +" <property>: property\n" +" <addr>: address to store <count> entries of 4 bytes\n" +" <count>: number of entries to retrieve\n" +"dam_reset [<password>]\n" +" If the TPM is not in a LOCKOUT state, reset the internal error counter.\n" +" <password>: optional password\n" +"dam_parameters <max_tries> <recovery_time> <lockout_recovery> [<password>]\n" +" If the TPM is not in a LOCKOUT state, set the DAM parameters\n" +" <maxTries>: maximum number of failures before lockout,\n" +" 0 means always locking\n" +" <recoveryTime>: time before decrement of the error counter,\n" +" 0 means no lockout\n" +" <lockoutRecovery>: time of a lockout (before the next try),\n" +" 0 means a reboot is needed\n" +" <password>: optional password of the LOCKOUT hierarchy\n" +"change_auth <hierarchy> <new_pw> [<old_pw>]\n" +" <hierarchy>: the hierarchy\n" +" <new_pw>: new password for <hierarchy>\n" +" <old_pw>: optional previous password of <hierarchy>\n" +"pcr_setauthpolicy|pcr_setauthvalue <pcr> <key> [<password>]\n" +" Change the <key> to access PCR #<pcr>.\n" +" hierarchy and may be empty.\n" +" /!\\WARNING: untested function, use at your own risks !\n" +" <pcr>: index of the PCR\n" +" <key>: secret to protect the access of PCR #<pcr>\n" +" <password>: optional password of the PLATFORM hierarchy\n" +); diff --git a/cmd/tpm_test.c b/cmd/tpm_test.c index 2e7d133a47e..35f3c96e3de 100644 --- a/cmd/tpm_test.c +++ b/cmd/tpm_test.c @@ -6,7 +6,7 @@ #include <common.h> #include <command.h> #include <environment.h> -#include <tpm.h> +#include <tpm-v1.h> /* Prints error and returns on failure */ #define TPM_CHECK(tpm_command) do { \ diff --git a/common/dlmalloc.c b/common/dlmalloc.c index b395eefbf86..edaad299bbb 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -1891,6 +1891,13 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes; if ((long)bytes < 0) return NULL; +#if CONFIG_VAL(SYS_MALLOC_F_LEN) + if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) { + nb = roundup(bytes, alignment); + return malloc_simple(nb); + } +#endif + /* If need less alignment than we give anyway, just relay to malloc */ if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes); diff --git a/common/image-fit.c b/common/image-fit.c index 5b93dceae15..728187ac883 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -142,7 +142,186 @@ int fit_get_subimage_count(const void *fit, int images_noffset) return count; } -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_FIT_SPL_PRINT) +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FIT_PRINT) +/** + * fit_image_print_data() - prints out the hash node details + * @fit: pointer to the FIT format image header + * @noffset: offset of the hash node + * @p: pointer to prefix string + * @type: Type of information to print ("hash" or "sign") + * + * fit_image_print_data() lists properties for the processed hash node + * + * This function avoid using puts() since it prints a newline on the host + * but does not in U-Boot. + * + * returns: + * no returned results + */ +static void fit_image_print_data(const void *fit, int noffset, const char *p, + const char *type) +{ + const char *keyname; + uint8_t *value; + int value_len; + char *algo; + int required; + int ret, i; + + debug("%s %s node: '%s'\n", p, type, + fit_get_name(fit, noffset, NULL)); + printf("%s %s algo: ", p, type); + if (fit_image_hash_get_algo(fit, noffset, &algo)) { + printf("invalid/unsupported\n"); + return; + } + printf("%s", algo); + keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + required = fdt_getprop(fit, noffset, "required", NULL) != NULL; + if (keyname) + printf(":%s", keyname); + if (required) + printf(" (required)"); + printf("\n"); + + ret = fit_image_hash_get_value(fit, noffset, &value, + &value_len); + printf("%s %s value: ", p, type); + if (ret) { + printf("unavailable\n"); + } else { + for (i = 0; i < value_len; i++) + printf("%02x", value[i]); + printf("\n"); + } + + debug("%s %s len: %d\n", p, type, value_len); + + /* Signatures have a time stamp */ + if (IMAGE_ENABLE_TIMESTAMP && keyname) { + time_t timestamp; + + printf("%s Timestamp: ", p); + if (fit_get_timestamp(fit, noffset, ×tamp)) + printf("unavailable\n"); + else + genimg_print_time(timestamp); + } +} + +/** + * fit_image_print_verification_data() - prints out the hash/signature details + * @fit: pointer to the FIT format image header + * @noffset: offset of the hash or signature node + * @p: pointer to prefix string + * + * This lists properties for the processed hash node + * + * returns: + * no returned results + */ +static void fit_image_print_verification_data(const void *fit, int noffset, + const char *p) +{ + const char *name; + + /* + * Check subnode name, must be equal to "hash" or "signature". + * Multiple hash/signature nodes require unique unit node + * names, e.g. hash-1, hash-2, signature-1, signature-2, etc. + */ + name = fit_get_name(fit, noffset, NULL); + if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) { + fit_image_print_data(fit, noffset, p, "Hash"); + } else if (!strncmp(name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + fit_image_print_data(fit, noffset, p, "Sign"); + } +} + +/** + * fit_conf_print - prints out the FIT configuration details + * @fit: pointer to the FIT format image header + * @noffset: offset of the configuration node + * @p: pointer to prefix string + * + * fit_conf_print() lists all mandatory properties for the processed + * configuration node. + * + * returns: + * no returned results + */ +static void fit_conf_print(const void *fit, int noffset, const char *p) +{ + char *desc; + const char *uname; + int ret; + int fdt_index, loadables_index; + int ndepth; + + /* Mandatory properties */ + ret = fit_get_desc(fit, noffset, &desc); + printf("%s Description: ", p); + if (ret) + printf("unavailable\n"); + else + printf("%s\n", desc); + + uname = fdt_getprop(fit, noffset, FIT_KERNEL_PROP, NULL); + printf("%s Kernel: ", p); + if (!uname) + printf("unavailable\n"); + else + printf("%s\n", uname); + + /* Optional properties */ + uname = fdt_getprop(fit, noffset, FIT_RAMDISK_PROP, NULL); + if (uname) + printf("%s Init Ramdisk: %s\n", p, uname); + + uname = fdt_getprop(fit, noffset, FIT_FIRMWARE_PROP, NULL); + if (uname) + printf("%s Firmware: %s\n", p, uname); + + for (fdt_index = 0; + uname = fdt_stringlist_get(fit, noffset, FIT_FDT_PROP, + fdt_index, NULL), uname; + fdt_index++) { + if (fdt_index == 0) + printf("%s FDT: ", p); + else + printf("%s ", p); + printf("%s\n", uname); + } + + uname = fdt_getprop(fit, noffset, FIT_FPGA_PROP, NULL); + if (uname) + printf("%s FPGA: %s\n", p, uname); + + /* Print out all of the specified loadables */ + for (loadables_index = 0; + uname = fdt_stringlist_get(fit, noffset, FIT_LOADABLE_PROP, + loadables_index, NULL), uname; + loadables_index++) { + if (loadables_index == 0) { + printf("%s Loadables: ", p); + } else { + printf("%s ", p); + } + printf("%s\n", uname); + } + + /* Process all hash subnodes of the component configuration node */ + for (ndepth = 0, noffset = fdt_next_node(fit, noffset, &ndepth); + (noffset >= 0) && (ndepth > 0); + noffset = fdt_next_node(fit, noffset, &ndepth)) { + if (ndepth == 1) { + /* Direct child node of the component configuration node */ + fit_image_print_verification_data(fit, noffset, p); + } + } +} + /** * fit_print_contents - prints out the contents of the FIT format image * @fit: pointer to the FIT format image header @@ -245,102 +424,6 @@ void fit_print_contents(const void *fit) } /** - * fit_image_print_data() - prints out the hash node details - * @fit: pointer to the FIT format image header - * @noffset: offset of the hash node - * @p: pointer to prefix string - * @type: Type of information to print ("hash" or "sign") - * - * fit_image_print_data() lists properties for the processed hash node - * - * This function avoid using puts() since it prints a newline on the host - * but does not in U-Boot. - * - * returns: - * no returned results - */ -static void fit_image_print_data(const void *fit, int noffset, const char *p, - const char *type) -{ - const char *keyname; - uint8_t *value; - int value_len; - char *algo; - int required; - int ret, i; - - debug("%s %s node: '%s'\n", p, type, - fit_get_name(fit, noffset, NULL)); - printf("%s %s algo: ", p, type); - if (fit_image_hash_get_algo(fit, noffset, &algo)) { - printf("invalid/unsupported\n"); - return; - } - printf("%s", algo); - keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); - required = fdt_getprop(fit, noffset, "required", NULL) != NULL; - if (keyname) - printf(":%s", keyname); - if (required) - printf(" (required)"); - printf("\n"); - - ret = fit_image_hash_get_value(fit, noffset, &value, - &value_len); - printf("%s %s value: ", p, type); - if (ret) { - printf("unavailable\n"); - } else { - for (i = 0; i < value_len; i++) - printf("%02x", value[i]); - printf("\n"); - } - - debug("%s %s len: %d\n", p, type, value_len); - - /* Signatures have a time stamp */ - if (IMAGE_ENABLE_TIMESTAMP && keyname) { - time_t timestamp; - - printf("%s Timestamp: ", p); - if (fit_get_timestamp(fit, noffset, ×tamp)) - printf("unavailable\n"); - else - genimg_print_time(timestamp); - } -} - -/** - * fit_image_print_verification_data() - prints out the hash/signature details - * @fit: pointer to the FIT format image header - * @noffset: offset of the hash or signature node - * @p: pointer to prefix string - * - * This lists properties for the processed hash node - * - * returns: - * no returned results - */ -static void fit_image_print_verification_data(const void *fit, int noffset, - const char *p) -{ - const char *name; - - /* - * Check subnode name, must be equal to "hash" or "signature". - * Multiple hash/signature nodes require unique unit node - * names, e.g. hash-1, hash-2, signature-1, signature-2, etc. - */ - name = fit_get_name(fit, noffset, NULL); - if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) { - fit_image_print_data(fit, noffset, p, "Hash"); - } else if (!strncmp(name, FIT_SIG_NODENAME, - strlen(FIT_SIG_NODENAME))) { - fit_image_print_data(fit, noffset, p, "Sign"); - } -} - -/** * fit_image_print - prints out the FIT component image details * @fit: pointer to the FIT format image header * @image_noffset: offset of the component image node @@ -391,7 +474,7 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) fit_image_get_comp(fit, image_noffset, &comp); printf("%s Compression: %s\n", p, genimg_get_comp_name(comp)); - ret = fit_image_get_data(fit, image_noffset, &data, &size); + ret = fit_image_get_data_and_size(fit, image_noffset, &data, &size); #ifndef USE_HOSTCC printf("%s Data Start: ", p); @@ -459,8 +542,10 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) } } } - -#endif /* !defined(CONFIG_SPL_BUILD) || defined(CONFIG_FIT_SPL_PRINT) */ +#else +void fit_print_contents(const void *fit) { } +void fit_image_print(const void *fit, int image_noffset, const char *p) { } +#endif /* !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FIT_PRINT) */ /** * fit_get_desc - get node description property @@ -856,6 +941,54 @@ int fit_image_get_data_size(const void *fit, int noffset, int *data_size) } /** + * fit_image_get_data_and_size - get data and its size including + * both embedded and external data + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @data: double pointer to void, will hold data property's data address + * @size: pointer to size_t, will hold data property's data size + * + * fit_image_get_data_and_size() finds data and its size including + * both embedded and external data. If the property is found + * its data start address and size are returned to the caller. + * + * returns: + * 0, on success + * otherwise, on failure + */ +int fit_image_get_data_and_size(const void *fit, int noffset, + const void **data, size_t *size) +{ + bool external_data = false; + int offset; + int len; + int ret; + + if (!fit_image_get_data_position(fit, noffset, &offset)) { + external_data = true; + } else if (!fit_image_get_data_offset(fit, noffset, &offset)) { + external_data = true; + /* + * For FIT with external data, figure out where + * the external images start. This is the base + * for the data-offset properties in each image. + */ + offset += ((fdt_totalsize(fit) + 3) & ~3); + } + + if (external_data) { + debug("External Data\n"); + ret = fit_image_get_data_size(fit, noffset, &len); + *data = fit + offset; + *size = len; + } else { + ret = fit_image_get_data(fit, noffset, data, size); + } + + return ret; +} + +/** * fit_image_hash_get_algo - get hash algorithm name * @fit: pointer to the FIT format image header * @noffset: hash node offset @@ -1153,7 +1286,7 @@ int fit_image_verify(const void *fit, int image_noffset) char *err_msg = ""; /* Get image data and data length */ - if (fit_image_get_data(fit, image_noffset, &data, &size)) { + if (fit_image_get_data_and_size(fit, image_noffset, &data, &size)) { err_msg = "Can't get image data/size"; printf("error!\n%s for '%s' hash node in '%s' image node\n", err_msg, fit_get_name(fit, noffset, NULL), @@ -1571,92 +1704,6 @@ int fit_conf_get_prop_node(const void *fit, int noffset, return fit_conf_get_prop_node_index(fit, noffset, prop_name, 0); } -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_FIT_SPL_PRINT) -/** - * fit_conf_print - prints out the FIT configuration details - * @fit: pointer to the FIT format image header - * @noffset: offset of the configuration node - * @p: pointer to prefix string - * - * fit_conf_print() lists all mandatory properties for the processed - * configuration node. - * - * returns: - * no returned results - */ -void fit_conf_print(const void *fit, int noffset, const char *p) -{ - char *desc; - const char *uname; - int ret; - int fdt_index, loadables_index; - int ndepth; - - /* Mandatory properties */ - ret = fit_get_desc(fit, noffset, &desc); - printf("%s Description: ", p); - if (ret) - printf("unavailable\n"); - else - printf("%s\n", desc); - - uname = fdt_getprop(fit, noffset, FIT_KERNEL_PROP, NULL); - printf("%s Kernel: ", p); - if (uname == NULL) - printf("unavailable\n"); - else - printf("%s\n", uname); - - /* Optional properties */ - uname = fdt_getprop(fit, noffset, FIT_RAMDISK_PROP, NULL); - if (uname) - printf("%s Init Ramdisk: %s\n", p, uname); - - uname = fdt_getprop(fit, noffset, FIT_FIRMWARE_PROP, NULL); - if (uname) - printf("%s Firmware: %s\n", p, uname); - - for (fdt_index = 0; - uname = fdt_stringlist_get(fit, noffset, FIT_FDT_PROP, - fdt_index, NULL), uname; - fdt_index++) { - - if (fdt_index == 0) - printf("%s FDT: ", p); - else - printf("%s ", p); - printf("%s\n", uname); - } - - uname = fdt_getprop(fit, noffset, FIT_FPGA_PROP, NULL); - if (uname) - printf("%s FPGA: %s\n", p, uname); - - /* Print out all of the specified loadables */ - for (loadables_index = 0; - uname = fdt_stringlist_get(fit, noffset, FIT_LOADABLE_PROP, - loadables_index, NULL), uname; - loadables_index++) { - if (loadables_index == 0) { - printf("%s Loadables: ", p); - } else { - printf("%s ", p); - } - printf("%s\n", uname); - } - - /* Process all hash subnodes of the component configuration node */ - for (ndepth = 0, noffset = fdt_next_node(fit, noffset, &ndepth); - (noffset >= 0) && (ndepth > 0); - noffset = fdt_next_node(fit, noffset, &ndepth)) { - if (ndepth == 1) { - /* Direct child node of the component configuration node */ - fit_image_print_verification_data(fit, noffset, p); - } - } -} -#endif /* !defined(CONFIG_SPL_BUILD) || defined(CONFIG_FIT_SPL_PRINT) */ - static int fit_image_select(const void *fit, int rd_noffset, int verify) { fit_image_print(fit, rd_noffset, " "); @@ -1726,6 +1773,8 @@ static const char *fit_get_image_type_property(int type) return FIT_LOADABLE_PROP; case IH_TYPE_FPGA: return FIT_FPGA_PROP; + case IH_TYPE_STANDALONE: + return FIT_STANDALONE_PROP; } return "unknown"; @@ -1875,7 +1924,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr, bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK); /* get image data address and length */ - if (fit_image_get_data(fit, noffset, &buf, &size)) { + if (fit_image_get_data_and_size(fit, noffset, &buf, &size)) { printf("Could not find %s subimage data!\n", prop_name); bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA); return -ENOENT; diff --git a/common/spl/spl.c b/common/spl/spl.c index 6606417ff74..a09ada37d72 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -145,9 +145,84 @@ void spl_set_header_raw_uboot(struct spl_image_info *spl_image) spl_image->name = "U-Boot"; } +#ifdef CONFIG_SPL_LOAD_FIT_FULL +/* Parse and load full fitImage in SPL */ +static int spl_load_fit_image(struct spl_image_info *spl_image, + const struct image_header *header) +{ + bootm_headers_t images; + const char *fit_uname_config = NULL; + const char *fit_uname_fdt = FIT_FDT_PROP; + const char *uname; + ulong fw_data = 0, dt_data = 0, img_data = 0; + ulong fw_len = 0, dt_len = 0, img_len = 0; + int idx, conf_noffset; + int ret; + +#ifdef CONFIG_SPL_FIT_SIGNATURE + images.verify = 1; +#endif + ret = fit_image_load(&images, (ulong)header, + NULL, &fit_uname_config, + IH_ARCH_DEFAULT, IH_TYPE_STANDALONE, -1, + FIT_LOAD_REQUIRED, &fw_data, &fw_len); + if (ret < 0) + return ret; + + spl_image->size = fw_len; + spl_image->entry_point = fw_data; + spl_image->load_addr = fw_data; + spl_image->os = IH_OS_U_BOOT; + spl_image->name = "U-Boot"; + + debug("spl: payload image: %.*s load addr: 0x%lx size: %d\n", + (int)sizeof(spl_image->name), spl_image->name, + spl_image->load_addr, spl_image->size); + +#ifdef CONFIG_SPL_FIT_SIGNATURE + images.verify = 1; +#endif + fit_image_load(&images, (ulong)header, + &fit_uname_fdt, &fit_uname_config, + IH_ARCH_DEFAULT, IH_TYPE_FLATDT, -1, + FIT_LOAD_OPTIONAL, &dt_data, &dt_len); + + conf_noffset = fit_conf_get_node((const void *)header, + fit_uname_config); + if (conf_noffset <= 0) + return 0; + + for (idx = 0; + uname = fdt_stringlist_get((const void *)header, conf_noffset, + FIT_LOADABLE_PROP, idx, + NULL), uname; + idx++) + { +#ifdef CONFIG_SPL_FIT_SIGNATURE + images.verify = 1; +#endif + ret = fit_image_load(&images, (ulong)header, + &uname, &fit_uname_config, + IH_ARCH_DEFAULT, IH_TYPE_LOADABLE, -1, + FIT_LOAD_OPTIONAL_NON_ZERO, + &img_data, &img_len); + if (ret < 0) + return ret; + } + + return 0; +} +#endif + int spl_parse_image_header(struct spl_image_info *spl_image, const struct image_header *header) { +#ifdef CONFIG_SPL_LOAD_FIT_FULL + int ret = spl_load_fit_image(spl_image, header); + + if (!ret) + return ret; +#endif if (image_get_magic(header) == IH_MAGIC) { #ifdef CONFIG_SPL_LEGACY_IMAGE_SUPPORT u32 header_size = sizeof(struct image_header); diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 8b5befcec2b..2321ebb0dde 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -140,6 +140,14 @@ static int get_aligned_image_size(struct spl_load_info *info, int data_size, return (data_size + info->bl_len - 1) / info->bl_len; } +#ifdef CONFIG_SPL_FPGA_SUPPORT +__weak int spl_load_fpga_image(struct spl_load_info *info, size_t length, + int nr_sectors, int sector_offset) +{ + return 0; +} +#endif + /** * spl_load_fit_image(): load the image described in a certain FIT node * @info: points to information about the device to load data from @@ -161,7 +169,7 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector, void *fit, ulong base_offset, int node, struct spl_image_info *image_info) { - int offset; + int offset, sector_offset; size_t length; int len; ulong size; @@ -209,9 +217,16 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector, overhead = get_aligned_image_overhead(info, offset); nr_sectors = get_aligned_image_size(info, length, offset); + sector_offset = sector + get_aligned_image_offset(info, offset); - if (info->read(info, - sector + get_aligned_image_offset(info, offset), +#ifdef CONFIG_SPL_FPGA_SUPPORT + if (type == IH_TYPE_FPGA) { + return spl_load_fpga_image(info, length, nr_sectors, + sector_offset); + } +#endif + + if (info->read(info, sector_offset, nr_sectors, (void *)load_ptr) != nr_sectors) return -EIO; @@ -387,6 +402,20 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, return -1; } +#ifdef CONFIG_SPL_FPGA_SUPPORT + node = spl_fit_get_image_node(fit, images, "fpga", 0); + if (node >= 0) { + /* Load the image and set up the spl_image structure */ + ret = spl_load_fit_image(info, sector, fit, base_offset, node, + spl_image); + if (ret) { + printf("%s: Cannot load the FPGA: %i\n", __func__, ret); + return ret; + } + node = -1; + } +#endif + /* * Find the U-Boot image using the following search order: * - start at 'firmware' (e.g. an ARM Trusted Firmware) diff --git a/configs/at91sam9x5ek_dataflash_defconfig b/configs/at91sam9x5ek_dataflash_defconfig index ffed17904ab..a888e9d39a8 100644 --- a/configs/at91sam9x5ek_dataflash_defconfig +++ b/configs/at91sam9x5ek_dataflash_defconfig @@ -8,7 +8,7 @@ CONFIG_DEBUG_UART=y CONFIG_SYS_EXTRA_OPTIONS="SYS_USE_DATAFLASH" CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256k(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs rw" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256k(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs rw" # CONFIG_CONSOLE_MUX is not set CONFIG_SYS_CONSOLE_IS_IN_ENV=y # CONFIG_DISPLAY_BOARDINFO is not set diff --git a/configs/at91sam9x5ek_nandflash_defconfig b/configs/at91sam9x5ek_nandflash_defconfig index 4d16eb5a8b7..e3c863e3526 100644 --- a/configs/at91sam9x5ek_nandflash_defconfig +++ b/configs/at91sam9x5ek_nandflash_defconfig @@ -8,7 +8,7 @@ CONFIG_DEBUG_UART=y CONFIG_NAND_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256k(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs rw" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256k(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs rw" # CONFIG_CONSOLE_MUX is not set CONFIG_SYS_CONSOLE_IS_IN_ENV=y # CONFIG_DISPLAY_BOARDINFO is not set diff --git a/configs/at91sam9x5ek_spiflash_defconfig b/configs/at91sam9x5ek_spiflash_defconfig index 52c419d0504..16d7de54b67 100644 --- a/configs/at91sam9x5ek_spiflash_defconfig +++ b/configs/at91sam9x5ek_spiflash_defconfig @@ -8,7 +8,7 @@ CONFIG_DEBUG_UART=y CONFIG_SPI_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256k(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs rw" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256k(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs rw" # CONFIG_CONSOLE_MUX is not set CONFIG_SYS_CONSOLE_IS_IN_ENV=y # CONFIG_DISPLAY_BOARDINFO is not set diff --git a/configs/axs101_defconfig b/configs/axs101_defconfig index 25b10888ced..559ed4734c1 100644 --- a/configs/axs101_defconfig +++ b/configs/axs101_defconfig @@ -3,6 +3,7 @@ CONFIG_TARGET_AXS101=y CONFIG_SYS_TEXT_BASE=0x81000000 CONFIG_SYS_CLK_FREQ=750000000 CONFIG_DEFAULT_DEVICE_TREE="axs101" +CONFIG_DEBUG_UART=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS3,115200n8" @@ -33,6 +34,10 @@ CONFIG_DM_ETH=y CONFIG_PHY_GIGE=y CONFIG_ETH_DESIGNWARE=y CONFIG_DM_SERIAL=y +CONFIG_DEBUG_UART_BASE=0xe0022000 +CONFIG_DEBUG_UART_CLOCK=33333333 +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_DEBUG_UART_ANNOUNCE=y CONFIG_SYS_NS16550=y CONFIG_USB=y CONFIG_DM_USB=y diff --git a/configs/axs103_defconfig b/configs/axs103_defconfig index b9d387b88a8..8b66451307d 100644 --- a/configs/axs103_defconfig +++ b/configs/axs103_defconfig @@ -3,6 +3,7 @@ CONFIG_ISA_ARCV2=y CONFIG_SYS_TEXT_BASE=0x81000000 CONFIG_SYS_CLK_FREQ=100000000 CONFIG_DEFAULT_DEVICE_TREE="axs103" +CONFIG_DEBUG_UART=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS3,115200n8" @@ -33,6 +34,10 @@ CONFIG_DM_ETH=y CONFIG_PHY_GIGE=y CONFIG_ETH_DESIGNWARE=y CONFIG_DM_SERIAL=y +CONFIG_DEBUG_UART_BASE=0xe0022000 +CONFIG_DEBUG_UART_CLOCK=33333333 +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_DEBUG_UART_ANNOUNCE=y CONFIG_SYS_NS16550=y CONFIG_USB=y CONFIG_DM_USB=y diff --git a/configs/dragonboard410c_defconfig b/configs/dragonboard410c_defconfig index e6114db2ce2..4b3de64dd50 100644 --- a/configs/dragonboard410c_defconfig +++ b/configs/dragonboard410c_defconfig @@ -45,3 +45,8 @@ CONFIG_USB_ETHER_ASIX88179=y CONFIG_USB_ETHER_MCS7830=y CONFIG_USB_ETHER_SMSC95XX=y CONFIG_OF_LIBFDT_OVERLAY=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_FULL=y +CONFIG_PINCTRL_GENERIC=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y diff --git a/configs/gwventana_emmc_defconfig b/configs/gwventana_emmc_defconfig index c77de886da6..d4de3b408e9 100644 --- a/configs/gwventana_emmc_defconfig +++ b/configs/gwventana_emmc_defconfig @@ -56,6 +56,7 @@ CONFIG_CMD_UBI=y CONFIG_ENV_IS_IN_MMC=y CONFIG_DM=y CONFIG_DWC_AHSATA=y +CONFIG_SUPPORT_EMMC_RPMB=y CONFIG_FSL_ESDHC=y CONFIG_PHYLIB=y CONFIG_NETDEVICES=y diff --git a/configs/gwventana_gw5904_defconfig b/configs/gwventana_gw5904_defconfig index 007b49abc80..fdad5ee4ee5 100644 --- a/configs/gwventana_gw5904_defconfig +++ b/configs/gwventana_gw5904_defconfig @@ -56,6 +56,7 @@ CONFIG_CMD_UBI=y CONFIG_ENV_IS_IN_MMC=y CONFIG_DM=y CONFIG_DWC_AHSATA=y +CONFIG_SUPPORT_EMMC_RPMB=y CONFIG_FSL_ESDHC=y CONFIG_PHYLIB=y CONFIG_MV88E61XX_SWITCH=y diff --git a/configs/gwventana_nand_defconfig b/configs/gwventana_nand_defconfig index 1de70818eff..e6ccfef7aac 100644 --- a/configs/gwventana_nand_defconfig +++ b/configs/gwventana_nand_defconfig @@ -58,6 +58,7 @@ CONFIG_CMD_UBI=y CONFIG_ENV_IS_IN_NAND=y CONFIG_DM=y CONFIG_DWC_AHSATA=y +CONFIG_SUPPORT_EMMC_RPMB=y CONFIG_FSL_ESDHC=y CONFIG_NAND=y CONFIG_NAND_MXS=y diff --git a/configs/hsdk_defconfig b/configs/hsdk_defconfig index d23acfeb878..28cd1dd70c4 100644 --- a/configs/hsdk_defconfig +++ b/configs/hsdk_defconfig @@ -4,6 +4,7 @@ CONFIG_TARGET_HSDK=y CONFIG_SYS_TEXT_BASE=0x81000000 CONFIG_SYS_CLK_FREQ=500000000 CONFIG_DEFAULT_DEVICE_TREE="hsdk" +CONFIG_DEBUG_UART=y CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS0,115200n8" CONFIG_BOARD_EARLY_INIT_F=y @@ -42,6 +43,10 @@ CONFIG_SPI_FLASH_SST=y CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_DM_SERIAL=y +CONFIG_DEBUG_UART_BASE=0xf0005000 +CONFIG_DEBUG_UART_CLOCK=33333333 +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_DEBUG_UART_ANNOUNCE=y CONFIG_SYS_NS16550=y CONFIG_SPI=y CONFIG_DM_SPI=y diff --git a/configs/nsim_700_defconfig b/configs/nsim_700_defconfig index 12fe5f77c64..b10044986fa 100644 --- a/configs/nsim_700_defconfig +++ b/configs/nsim_700_defconfig @@ -3,6 +3,7 @@ CONFIG_TARGET_NSIM=y CONFIG_SYS_TEXT_BASE=0x81000000 CONFIG_SYS_CLK_FREQ=70000000 CONFIG_DEFAULT_DEVICE_TREE="nsim" +CONFIG_DEBUG_UART=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyARC0,115200n8" @@ -13,4 +14,8 @@ CONFIG_OF_CONTROL=y CONFIG_OF_EMBED=y CONFIG_DM=y CONFIG_DM_SERIAL=y +CONFIG_DEBUG_ARC_SERIAL=y +CONFIG_DEBUG_UART_BASE=0xc0fc1000 +CONFIG_DEBUG_UART_CLOCK=70000000 +CONFIG_ARC_SERIAL=y CONFIG_USE_PRIVATE_LIBGCC=y diff --git a/configs/nsim_700be_defconfig b/configs/nsim_700be_defconfig index 6c0dba7c6d0..6f03145517d 100644 --- a/configs/nsim_700be_defconfig +++ b/configs/nsim_700be_defconfig @@ -4,6 +4,7 @@ CONFIG_TARGET_NSIM=y CONFIG_SYS_TEXT_BASE=0x81000000 CONFIG_SYS_CLK_FREQ=70000000 CONFIG_DEFAULT_DEVICE_TREE="nsim" +CONFIG_DEBUG_UART=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyARC0,115200n8" @@ -14,4 +15,8 @@ CONFIG_OF_CONTROL=y CONFIG_OF_EMBED=y CONFIG_DM=y CONFIG_DM_SERIAL=y +CONFIG_DEBUG_ARC_SERIAL=y +CONFIG_DEBUG_UART_BASE=0xc0fc1000 +CONFIG_DEBUG_UART_CLOCK=70000000 +CONFIG_ARC_SERIAL=y CONFIG_USE_PRIVATE_LIBGCC=y diff --git a/configs/nsim_hs38_defconfig b/configs/nsim_hs38_defconfig index bb31adb381d..526dd3e5e24 100644 --- a/configs/nsim_hs38_defconfig +++ b/configs/nsim_hs38_defconfig @@ -4,6 +4,7 @@ CONFIG_TARGET_NSIM=y CONFIG_SYS_TEXT_BASE=0x81000000 CONFIG_SYS_CLK_FREQ=70000000 CONFIG_DEFAULT_DEVICE_TREE="nsim" +CONFIG_DEBUG_UART=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyARC0,115200n8" @@ -14,4 +15,8 @@ CONFIG_OF_CONTROL=y CONFIG_OF_EMBED=y CONFIG_DM=y CONFIG_DM_SERIAL=y +CONFIG_DEBUG_ARC_SERIAL=y +CONFIG_DEBUG_UART_BASE=0xc0fc1000 +CONFIG_DEBUG_UART_CLOCK=70000000 +CONFIG_ARC_SERIAL=y CONFIG_USE_PRIVATE_LIBGCC=y diff --git a/configs/nsim_hs38be_defconfig b/configs/nsim_hs38be_defconfig index a2cc238433f..141051ded1f 100644 --- a/configs/nsim_hs38be_defconfig +++ b/configs/nsim_hs38be_defconfig @@ -5,6 +5,7 @@ CONFIG_TARGET_NSIM=y CONFIG_SYS_TEXT_BASE=0x81000000 CONFIG_SYS_CLK_FREQ=70000000 CONFIG_DEFAULT_DEVICE_TREE="nsim" +CONFIG_DEBUG_UART=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyARC0,115200n8" @@ -15,4 +16,8 @@ CONFIG_OF_CONTROL=y CONFIG_OF_EMBED=y CONFIG_DM=y CONFIG_DM_SERIAL=y +CONFIG_DEBUG_ARC_SERIAL=y +CONFIG_DEBUG_UART_BASE=0xc0fc1000 +CONFIG_DEBUG_UART_CLOCK=70000000 +CONFIG_ARC_SERIAL=y CONFIG_USE_PRIVATE_LIBGCC=y diff --git a/configs/sama5d2_xplained_mmc_defconfig b/configs/sama5d2_xplained_mmc_defconfig index 066fdb36c58..6363b485ff2 100644 --- a/configs/sama5d2_xplained_mmc_defconfig +++ b/configs/sama5d2_xplained_mmc_defconfig @@ -34,11 +34,13 @@ CONFIG_CMD_SF=y CONFIG_CMD_USB=y CONFIG_CMD_DHCP=y CONFIG_CMD_PING=y +CONFIG_CMD_EXT4=y CONFIG_CMD_FAT=y CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y CONFIG_OF_SPL_REMOVE_PROPS="interrupts interrupt-parent dmas dma-names" CONFIG_ENV_IS_IN_FAT=y +CONFIG_ENV_FAT_DEVICE_AND_PART="1:1" CONFIG_DM=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y diff --git a/configs/sama5d2_xplained_spiflash_defconfig b/configs/sama5d2_xplained_spiflash_defconfig index 87bca1f6fbf..92da1200f85 100644 --- a/configs/sama5d2_xplained_spiflash_defconfig +++ b/configs/sama5d2_xplained_spiflash_defconfig @@ -18,7 +18,7 @@ CONFIG_FIT=y CONFIG_SPI_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256K(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p1 rw rootwait" # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_SPI_LOAD=y CONFIG_HUSH_PARSER=y @@ -32,6 +32,7 @@ CONFIG_CMD_SF=y CONFIG_CMD_USB=y CONFIG_CMD_DHCP=y CONFIG_CMD_PING=y +CONFIG_CMD_EXT4=y CONFIG_CMD_FAT=y CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 20a2ab3ffb7..228820dfc84 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -175,6 +175,7 @@ CONFIG_TIMER=y CONFIG_TIMER_EARLY=y CONFIG_SANDBOX_TIMER=y CONFIG_TPM_TIS_SANDBOX=y +CONFIG_TPM2_TIS_SANDBOX=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EMUL=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 2fc84a16c91..dc82ca08d99 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -176,6 +176,7 @@ CONFIG_TIMER=y CONFIG_TIMER_EARLY=y CONFIG_SANDBOX_TIMER=y CONFIG_TPM_TIS_SANDBOX=y +CONFIG_TPM2_TIS_SANDBOX=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EMUL=y diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index e922c4b38ff..08072e8f031 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -157,6 +157,7 @@ CONFIG_TIMER=y CONFIG_TIMER_EARLY=y CONFIG_SANDBOX_TIMER=y CONFIG_TPM_TIS_SANDBOX=y +CONFIG_TPM2_TIS_SANDBOX=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EMUL=y diff --git a/configs/sandbox_noblk_defconfig b/configs/sandbox_noblk_defconfig index 8bdd4edcda6..306945b8975 100644 --- a/configs/sandbox_noblk_defconfig +++ b/configs/sandbox_noblk_defconfig @@ -156,6 +156,7 @@ CONFIG_TIMER=y CONFIG_TIMER_EARLY=y CONFIG_SANDBOX_TIMER=y CONFIG_TPM_TIS_SANDBOX=y +CONFIG_TPM2_TIS_SANDBOX=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EMUL=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index fb6bb4baa2b..36727554658 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -175,6 +175,7 @@ CONFIG_TIMER=y CONFIG_TIMER_EARLY=y CONFIG_SANDBOX_TIMER=y CONFIG_TPM_TIS_SANDBOX=y +CONFIG_TPM2_TIS_SANDBOX=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EMUL=y diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index b1c3690c009..9e43cc96985 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -18,6 +18,7 @@ CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_EXPORTENV is not set # CONFIG_CMD_IMPORTENV is not set CONFIG_CMD_MEMINFO=y +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/configs/vining_2000_defconfig b/configs/vining_2000_defconfig index 1d28b2f1dbd..8cc030bd3c3 100644 --- a/configs/vining_2000_defconfig +++ b/configs/vining_2000_defconfig @@ -30,6 +30,7 @@ CONFIG_CMD_FAT=y CONFIG_CMD_FS_GENERIC=y CONFIG_EFI_PARTITION=y CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y +CONFIG_SUPPORT_EMMC_RPMB=y CONFIG_FSL_ESDHC=y CONFIG_PHYLIB=y CONFIG_PCI=y diff --git a/doc/README.commands b/doc/README.commands index afd5577b0a9..1d29c4d91dd 100644 --- a/doc/README.commands +++ b/doc/README.commands @@ -1,19 +1,83 @@ +Command definition +------------------ Commands are added to U-Boot by creating a new command structure. -This is done by first including command.h, then using the U_BOOT_CMD() macro -to fill in a cmd_tbl_t struct. +This is done by first including command.h, then using the U_BOOT_CMD() or the +U_BOOT_CMD_COMPLETE macro to fill in a cmd_tbl_t struct. -U_BOOT_CMD(name,maxargs,repeatable,command,"usage","help") +U_BOOT_CMD(name, maxargs, repeatable, command, "usage", "help") +U_BOOT_CMD_COMPLETE(name, maxargs, repeatable, command, "usage, "help", comp) -name: is the name of the commad. THIS IS NOT a string. -maxargs: the maximum number of arguments this function takes -repeatable: either 0 or 1 to indicate if autorepeat is allowed -command: Function pointer (*cmd)(struct cmd_tbl_s *, int, int, char *[]); -usage: Short description. This is a string -help: Long description. This is a string +name: The name of the command. THIS IS NOT a string. +maxargs: The maximum number of arguments this function takes including + the command itself. -**** Behind the scene ****** +repeatable: Either 0 or 1 to indicate if autorepeat is allowed. + +command: Pointer to the command function. This is the function that is + called when the command is issued. + +usage: Short description. This is a string. + +help: Long description. This is a string. The long description is + only available if CONFIG_SYS_LONGHELP is defined. + +comp: Pointer to the completion function. May be NULL. + This function is called if the user hits the TAB key while + entering the command arguments to complete the entry. Command + completion is only available if CONFIG_AUTO_COMPLETE is defined. + +Command function +---------------- + +The commmand function pointer has to be of type +int (*cmd)(struct cmd_tbl_s *cmdtp, int flag, int argc, const char *argv[]); + +cmdtp: Table entry describing the command (see above). + +flag: A bitmap which may contain the following bit: + CMD_FLAG_REPEAT - The last command is repeated. + CMD_FLAG_BOOTD - The command is called by the bootd command. + CMD_FLAG_ENV - The command is called by the run command. + +argc: Number of arguments including the command. + +argv: Arguments. + +Allowable return value are: + +CMD_SUCCESS The command was successfully executed. + +CMD_FAILURE The command failed. + +CMD_RET_USAGE The command was called with invalid parameters. This value + leads to the display of the usage string. + +Completion function +------------------- + +The completion function pointer has to be of type +int (*complete)(int argc, char *const argv[], char last_char, + int maxv, char *cmdv[]); + +argc: Number of arguments including the command. + +argv: Arguments. + +last_char: The last character in the command line buffer. + +maxv: Maximum number of possible completions that may be returned by + the function. + +cmdv: Used to return possible values for the last argument. The last + possible completion must be followed by NULL. + +The function returns the number of possible completions (without the terminating +NULL value). + +Behind the scene +---------------- The structure created is named with a special prefix and placed by the linker in a special section using the linker lists mechanism diff --git a/doc/README.qemu-arm b/doc/README.qemu-arm index 6f6f07d8bb5..260165638aa 100644 --- a/doc/README.qemu-arm +++ b/doc/README.qemu-arm @@ -39,13 +39,12 @@ Running U-Boot The minimal QEMU command line to get U-Boot up and running is: - For ARM: - qemu-system-arm -machine virt,highmem=off -bios u-boot.bin + qemu-system-arm -machine virt -bios u-boot.bin - For AArch64: - qemu-system-aarch64 -machine virt,highmem=off -cpu cortex-a57 -bios u-boot.bin + qemu-system-aarch64 -machine virt -cpu cortex-a57 -bios u-boot.bin -The 'highmem=off' parameter to the 'virt' machine is required for PCI to work -in U-Boot. Also, for some odd reason qemu-system-aarch64 needs to be explicitly +Note that for some odd reason qemu-system-aarch64 needs to be explicitly told to use a 64-bit CPU or it will boot in 32-bit mode. Additional peripherals that have been tested to work in both U-Boot and Linux diff --git a/doc/device-tree-bindings/tpm2/sandbox.txt b/doc/device-tree-bindings/tpm2/sandbox.txt new file mode 100644 index 00000000000..3d0f727cc41 --- /dev/null +++ b/doc/device-tree-bindings/tpm2/sandbox.txt @@ -0,0 +1,11 @@ +Sandbox TPMv2.0 bindings +------------------------ + +Required properties: +- compatible : Should be "sandbox,tpm2" + +Example: + + tpm { + compatible = "sandbox,tpm2"; + }; diff --git a/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt b/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt new file mode 100644 index 00000000000..b48a15112d3 --- /dev/null +++ b/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt @@ -0,0 +1,18 @@ +ST33TPHF20 SPI TPMv2.0 bindings +------------------------------- + +Required properties: +- compatible : Should be "tis,tpm2-spi" +- reg : SPI Chip select + +Optional properties: +- gpio-reset : Reset GPIO (if not connected to the SoC reset line) +- spi-max-frequency : See spi-bus.txt + +Example: + + tpm@1 { + compatible = "tis,tpm2-spi"; + reg = <1>; + spi-max-frequency = <10000000>; + }; diff --git a/doc/driver-model/i2c-howto.txt b/doc/driver-model/i2c-howto.txt index 605d3ef7adc..8ba2f6e2679 100644 --- a/doc/driver-model/i2c-howto.txt +++ b/doc/driver-model/i2c-howto.txt @@ -14,9 +14,7 @@ ones remain: ppc4xx_i2c rcar_i2c sh_i2c - sh_sh7734_i2c soft_i2c - tsi108_i2c zynq_i2c The deadline for this work is the end of June 2017. If no one steps diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c index 485a023bfd3..8f02d73d8da 100644 --- a/drivers/clk/at91/clk-h32mx.c +++ b/drivers/clk/at91/clk-h32mx.c @@ -26,7 +26,7 @@ static ulong sama5d4_h32mx_clk_get_rate(struct clk *clk) rate /= 2; if (rate > H32MX_MAX_FREQ) - dm_warn("H32MX clock is too fast\n"); + dev_dbg(clk->dev, "H32MX clock is too fast\n"); return rate; } diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 8bb3c18b572..da368cc02a0 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -9,8 +9,6 @@ obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o obj-$(CONFIG_I2C_MV) += mv_i2c.o -obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o -obj-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o diff --git a/drivers/i2c/sh_sh7734_i2c.c b/drivers/i2c/sh_sh7734_i2c.c deleted file mode 100644 index 6fe356baca8..00000000000 --- a/drivers/i2c/sh_sh7734_i2c.c +++ /dev/null @@ -1,376 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> - * Copyright (C) 2012 Renesas Solutions Corp. - * - * NOTE: This driver should be converted to driver model before June 2017. - * Please see doc/driver-model/i2c-howto.txt for instructions. - */ - -#include <common.h> -#include <i2c.h> -#include <asm/io.h> - -struct sh_i2c { - u8 iccr1; - u8 iccr2; - u8 icmr; - u8 icier; - u8 icsr; - u8 sar; - u8 icdrt; - u8 icdrr; - u8 nf2cyc; - u8 __pad0; - u8 __pad1; -}; - -static struct sh_i2c *base; -static u8 iccr1_cks, nf2cyc; - -/* ICCR1 */ -#define SH_I2C_ICCR1_ICE (1 << 7) -#define SH_I2C_ICCR1_RCVD (1 << 6) -#define SH_I2C_ICCR1_MST (1 << 5) -#define SH_I2C_ICCR1_TRS (1 << 4) -#define SH_I2C_ICCR1_MTRS \ - (SH_I2C_ICCR1_MST | SH_I2C_ICCR1_TRS) - -/* ICCR1 */ -#define SH_I2C_ICCR2_BBSY (1 << 7) -#define SH_I2C_ICCR2_SCP (1 << 6) -#define SH_I2C_ICCR2_SDAO (1 << 5) -#define SH_I2C_ICCR2_SDAOP (1 << 4) -#define SH_I2C_ICCR2_SCLO (1 << 3) -#define SH_I2C_ICCR2_IICRST (1 << 1) - -#define SH_I2C_ICIER_TIE (1 << 7) -#define SH_I2C_ICIER_TEIE (1 << 6) -#define SH_I2C_ICIER_RIE (1 << 5) -#define SH_I2C_ICIER_NAKIE (1 << 4) -#define SH_I2C_ICIER_STIE (1 << 3) -#define SH_I2C_ICIER_ACKE (1 << 2) -#define SH_I2C_ICIER_ACKBR (1 << 1) -#define SH_I2C_ICIER_ACKBT (1 << 0) - -#define SH_I2C_ICSR_TDRE (1 << 7) -#define SH_I2C_ICSR_TEND (1 << 6) -#define SH_I2C_ICSR_RDRF (1 << 5) -#define SH_I2C_ICSR_NACKF (1 << 4) -#define SH_I2C_ICSR_STOP (1 << 3) -#define SH_I2C_ICSR_ALOVE (1 << 2) -#define SH_I2C_ICSR_AAS (1 << 1) -#define SH_I2C_ICSR_ADZ (1 << 0) - -#define IRQ_WAIT 1000 - -static void sh_i2c_send_stop(struct sh_i2c *base) -{ - clrbits_8(&base->iccr2, SH_I2C_ICCR2_BBSY | SH_I2C_ICCR2_SCP); -} - -static int check_icsr_bits(struct sh_i2c *base, u8 bits) -{ - int i; - - for (i = 0; i < IRQ_WAIT; i++) { - if (bits & readb(&base->icsr)) - return 0; - udelay(10); - } - - return 1; -} - -static int check_stop(struct sh_i2c *base) -{ - int ret = check_icsr_bits(base, SH_I2C_ICSR_STOP); - clrbits_8(&base->icsr, SH_I2C_ICSR_STOP); - - return ret; -} - -static int check_tend(struct sh_i2c *base, int stop) -{ - int ret = check_icsr_bits(base, SH_I2C_ICSR_TEND); - - if (stop) { - clrbits_8(&base->icsr, SH_I2C_ICSR_STOP); - sh_i2c_send_stop(base); - } - - clrbits_8(&base->icsr, SH_I2C_ICSR_TEND); - return ret; -} - -static int check_tdre(struct sh_i2c *base) -{ - return check_icsr_bits(base, SH_I2C_ICSR_TDRE); -} - -static int check_rdrf(struct sh_i2c *base) -{ - return check_icsr_bits(base, SH_I2C_ICSR_RDRF); -} - -static int check_bbsy(struct sh_i2c *base) -{ - int i; - - for (i = 0 ; i < IRQ_WAIT ; i++) { - if (!(SH_I2C_ICCR2_BBSY & readb(&base->iccr2))) - return 0; - udelay(10); - } - return 1; -} - -static int check_ackbr(struct sh_i2c *base) -{ - int i; - - for (i = 0 ; i < IRQ_WAIT ; i++) { - if (!(SH_I2C_ICIER_ACKBR & readb(&base->icier))) - return 0; - udelay(10); - } - - return 1; -} - -static void sh_i2c_reset(struct sh_i2c *base) -{ - setbits_8(&base->iccr2, SH_I2C_ICCR2_IICRST); - - udelay(100); - - clrbits_8(&base->iccr2, SH_I2C_ICCR2_IICRST); -} - -static int i2c_set_addr(struct sh_i2c *base, u8 id, u8 reg) -{ - if (check_bbsy(base)) { - puts("i2c bus busy\n"); - goto fail; - } - - setbits_8(&base->iccr1, SH_I2C_ICCR1_MTRS); - clrsetbits_8(&base->iccr2, SH_I2C_ICCR2_SCP, SH_I2C_ICCR2_BBSY); - - writeb((id << 1), &base->icdrt); - - if (check_tend(base, 0)) { - puts("TEND check fail...\n"); - goto fail; - } - - if (check_ackbr(base)) { - check_tend(base, 0); - sh_i2c_send_stop(base); - goto fail; - } - - writeb(reg, &base->icdrt); - - if (check_tdre(base)) { - puts("TDRE check fail...\n"); - goto fail; - } - - if (check_tend(base, 0)) { - puts("TEND check fail...\n"); - goto fail; - } - - return 0; -fail: - - return 1; -} - -static int -i2c_raw_write(struct sh_i2c *base, u8 id, u8 reg, u8 *val, int size) -{ - int i; - - if (i2c_set_addr(base, id, reg)) { - puts("Fail set slave address\n"); - return 1; - } - - for (i = 0; i < size; i++) { - writeb(val[i], &base->icdrt); - check_tdre(base); - } - - check_tend(base, 1); - check_stop(base); - - udelay(100); - - clrbits_8(&base->iccr1, SH_I2C_ICCR1_MTRS); - clrbits_8(&base->icsr, SH_I2C_ICSR_TDRE); - sh_i2c_reset(base); - - return 0; -} - -static u8 i2c_raw_read(struct sh_i2c *base, u8 id, u8 reg) -{ - u8 ret = 0; - - if (i2c_set_addr(base, id, reg)) { - puts("Fail set slave address\n"); - goto fail; - } - - clrsetbits_8(&base->iccr2, SH_I2C_ICCR2_SCP, SH_I2C_ICCR2_BBSY); - writeb((id << 1) | 1, &base->icdrt); - - if (check_tend(base, 0)) - puts("TDRE check fail...\n"); - - clrsetbits_8(&base->iccr1, SH_I2C_ICCR1_TRS, SH_I2C_ICCR1_MST); - clrbits_8(&base->icsr, SH_I2C_ICSR_TDRE); - setbits_8(&base->icier, SH_I2C_ICIER_ACKBT); - setbits_8(&base->iccr1, SH_I2C_ICCR1_RCVD); - - /* read data (dummy) */ - ret = readb(&base->icdrr); - - if (check_rdrf(base)) { - puts("check RDRF error\n"); - goto fail; - } - - clrbits_8(&base->icsr, SH_I2C_ICSR_STOP); - udelay(1000); - - sh_i2c_send_stop(base); - - if (check_stop(base)) { - puts("check STOP error\n"); - goto fail; - } - - clrbits_8(&base->iccr1, SH_I2C_ICCR1_MTRS); - clrbits_8(&base->icsr, SH_I2C_ICSR_TDRE); - - /* data read */ - ret = readb(&base->icdrr); - -fail: - clrbits_8(&base->iccr1, SH_I2C_ICCR1_RCVD); - - return ret; -} - -#ifdef CONFIG_I2C_MULTI_BUS -static unsigned int current_bus; - -/** - * i2c_set_bus_num - change active I2C bus - * @bus: bus index, zero based - * @returns: 0 on success, non-0 on failure - */ -int i2c_set_bus_num(unsigned int bus) -{ - switch (bus) { - case 0: - base = (void *)CONFIG_SH_I2C_BASE0; - break; - case 1: - base = (void *)CONFIG_SH_I2C_BASE1; - break; - default: - printf("Bad bus: %d\n", bus); - return -1; - } - - current_bus = bus; - - return 0; -} - -/** - * i2c_get_bus_num - returns index of active I2C bus - */ -unsigned int i2c_get_bus_num(void) -{ - return current_bus; -} -#endif - -void i2c_init(int speed, int slaveaddr) -{ -#ifdef CONFIG_I2C_MULTI_BUS - current_bus = 0; -#endif - base = (struct sh_i2c *)CONFIG_SH_I2C_BASE0; - - if (speed == 400000) - iccr1_cks = 0x07; - else - iccr1_cks = 0x0F; - - nf2cyc = 1; - - /* Reset */ - sh_i2c_reset(base); - - /* ICE enable and set clock */ - writeb(SH_I2C_ICCR1_ICE | iccr1_cks, &base->iccr1); - writeb(nf2cyc, &base->nf2cyc); -} - -/* - * i2c_read: - Read multiple bytes from an i2c device - * - * The higher level routines take into account that this function is only - * called with len < page length of the device (see configuration file) - * - * @chip: address of the chip which is to be read - * @addr: i2c data address within the chip - * @alen: length of the i2c data address (1..2 bytes) - * @buffer: where to write the data - * @len: how much byte do we want to read - * @return: 0 in case of success - */ -int i2c_read(u8 chip, u32 addr, int alen, u8 *buffer, int len) -{ - int i = 0; - for (i = 0; i < len; i++) - buffer[i] = i2c_raw_read(base, chip, addr + i); - - return 0; -} - -/* - * i2c_write: - Write multiple bytes to an i2c device - * - * The higher level routines take into account that this function is only - * called with len < page length of the device (see configuration file) - * - * @chip: address of the chip which is to be written - * @addr: i2c data address within the chip - * @alen: length of the i2c data address (1..2 bytes) - * @buffer: where to find the data to be written - * @len: how much byte do we want to read - * @return: 0 in case of success - */ -int i2c_write(u8 chip, u32 addr, int alen, u8 *buffer, int len) -{ - return i2c_raw_write(base, chip, addr, buffer, len); -} - -/* - * i2c_probe: - Test if a chip answers for a given i2c address - * - * @chip: address of the chip which is searched for - * @return: 0 if a chip was found, -1 otherwhise - */ -int i2c_probe(u8 chip) -{ - u8 byte; - return i2c_read(chip, 0, 0, &byte, 1); -} diff --git a/drivers/i2c/tsi108_i2c.c b/drivers/i2c/tsi108_i2c.c deleted file mode 100644 index 208c0900ef8..00000000000 --- a/drivers/i2c/tsi108_i2c.c +++ /dev/null @@ -1,275 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2004 Tundra Semiconductor Corp. - * Author: Alex Bounine - * - * NOTE: This driver should be converted to driver model before June 2017. - * Please see doc/driver-model/i2c-howto.txt for instructions. - */ - -#include <config.h> -#include <common.h> - -#include <tsi108.h> - -#if defined(CONFIG_CMD_I2C) - -#define I2C_DELAY 100000 -#undef DEBUG_I2C - -#ifdef DEBUG_I2C -#define DPRINT(x) printf (x) -#else -#define DPRINT(x) -#endif - -/* All functions assume that Tsi108 I2C block is the only master on the bus */ -/* I2C read helper function */ - -void i2c_init(int speed, int slaveaddr) -{ - /* - * The TSI108 has a fixed I2C clock rate and doesn't support slave - * operation. This function only exists as a stub to fit into the - * U-Boot I2C API. - */ -} - -static int i2c_read_byte ( - uint i2c_chan, /* I2C channel number: 0 - main, 1 - SDC SPD */ - uchar chip_addr,/* I2C device address on the bus */ - uint byte_addr, /* Byte address within I2C device */ - uchar * buffer /* pointer to data buffer */ - ) -{ - u32 temp; - u32 to_count = I2C_DELAY; - u32 op_status = TSI108_I2C_TIMEOUT_ERR; - u32 chan_offset = TSI108_I2C_OFFSET; - - DPRINT (("I2C read_byte() %d 0x%02x 0x%02x\n", - i2c_chan, chip_addr, byte_addr)); - - if (0 != i2c_chan) - chan_offset = TSI108_I2C_SDRAM_OFFSET; - - /* Check if I2C operation is in progress */ - temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2); - - if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | - I2C_CNTRL2_START))) { - /* Set device address and operation (read = 0) */ - temp = (byte_addr << 16) | ((chip_addr & 0x07) << 8) | - ((chip_addr >> 3) & 0x0F); - *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL1) = - temp; - - /* Issue the read command - * (at this moment all other parameters are 0 - * (size = 1 byte, lane = 0) - */ - - *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2) = - (I2C_CNTRL2_START); - - /* Wait until operation completed */ - do { - /* Read I2C operation status */ - temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2); - - if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_START))) { - if (0 == (temp & - (I2C_CNTRL2_I2C_CFGERR | - I2C_CNTRL2_I2C_TO_ERR)) - ) { - op_status = TSI108_I2C_SUCCESS; - - temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + - chan_offset + - I2C_RD_DATA); - - *buffer = (u8) (temp & 0xFF); - } else { - /* report HW error */ - op_status = TSI108_I2C_IF_ERROR; - - DPRINT (("I2C HW error reported: 0x%02x\n", temp)); - } - - break; - } - } while (to_count--); - } else { - op_status = TSI108_I2C_IF_BUSY; - - DPRINT (("I2C Transaction start failed: 0x%02x\n", temp)); - } - - DPRINT (("I2C read_byte() status: 0x%02x\n", op_status)); - return op_status; -} - -/* - * I2C Read interface as defined in "include/i2c.h" : - * chip_addr: I2C chip address, range 0..127 - * (to read from SPD channel EEPROM use (0xD0 ... 0xD7) - * NOTE: The bit 7 in the chip_addr serves as a channel select. - * This hack is for enabling "i2c sdram" command on Tsi108 boards - * without changes to common code. Used for I2C reads only. - * byte_addr: Memory or register address within the chip - * alen: Number of bytes to use for addr (typically 1, 2 for larger - * memories, 0 for register type devices with only one - * register) - * buffer: Pointer to destination buffer for data to be read - * len: How many bytes to read - * - * Returns: 0 on success, not 0 on failure - */ - -int i2c_read (uchar chip_addr, uint byte_addr, int alen, - uchar * buffer, int len) -{ - u32 op_status = TSI108_I2C_PARAM_ERR; - u32 i2c_if = 0; - - /* Hack to support second (SPD) I2C controller (SPD EEPROM read only).*/ - if (0xD0 == (chip_addr & ~0x07)) { - i2c_if = 1; - chip_addr &= 0x7F; - } - /* Check for valid I2C address */ - if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) { - while (len--) { - op_status = i2c_read_byte(i2c_if, chip_addr, byte_addr++, buffer++); - - if (TSI108_I2C_SUCCESS != op_status) { - DPRINT (("I2C read_byte() failed: 0x%02x (%d left)\n", op_status, len)); - - break; - } - } - } - - DPRINT (("I2C read() status: 0x%02x\n", op_status)); - return op_status; -} - -/* I2C write helper function */ - -static int i2c_write_byte (uchar chip_addr,/* I2C device address on the bus */ - uint byte_addr, /* Byte address within I2C device */ - uchar * buffer /* pointer to data buffer */ - ) -{ - u32 temp; - u32 to_count = I2C_DELAY; - u32 op_status = TSI108_I2C_TIMEOUT_ERR; - - /* Check if I2C operation is in progress */ - temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2); - - if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) { - /* Place data into the I2C Tx Register */ - *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + - I2C_TX_DATA) = (u32) * buffer; - - /* Set device address and operation */ - temp = - I2C_CNTRL1_I2CWRITE | (byte_addr << 16) | - ((chip_addr & 0x07) << 8) | ((chip_addr >> 3) & 0x0F); - *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + - I2C_CNTRL1) = temp; - - /* Issue the write command (at this moment all other parameters - * are 0 (size = 1 byte, lane = 0) - */ - - *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + - I2C_CNTRL2) = (I2C_CNTRL2_START); - - op_status = TSI108_I2C_TIMEOUT_ERR; - - /* Wait until operation completed */ - do { - /* Read I2C operation status */ - temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2); - - if (0 == (temp & (I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) { - if (0 == (temp & - (I2C_CNTRL2_I2C_CFGERR | - I2C_CNTRL2_I2C_TO_ERR))) { - op_status = TSI108_I2C_SUCCESS; - } else { - /* report detected HW error */ - op_status = TSI108_I2C_IF_ERROR; - - DPRINT (("I2C HW error reported: 0x%02x\n", temp)); - } - - break; - } - - } while (to_count--); - } else { - op_status = TSI108_I2C_IF_BUSY; - - DPRINT (("I2C Transaction start failed: 0x%02x\n", temp)); - } - - return op_status; -} - -/* - * I2C Write interface as defined in "include/i2c.h" : - * chip_addr: I2C chip address, range 0..127 - * byte_addr: Memory or register address within the chip - * alen: Number of bytes to use for addr (typically 1, 2 for larger - * memories, 0 for register type devices with only one - * register) - * buffer: Pointer to data to be written - * len: How many bytes to write - * - * Returns: 0 on success, not 0 on failure - */ - -int i2c_write (uchar chip_addr, uint byte_addr, int alen, uchar * buffer, - int len) -{ - u32 op_status = TSI108_I2C_PARAM_ERR; - - /* Check for valid I2C address */ - if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) { - while (len--) { - op_status = - i2c_write_byte (chip_addr, byte_addr++, buffer++); - - if (TSI108_I2C_SUCCESS != op_status) { - DPRINT (("I2C write_byte() failed: 0x%02x (%d left)\n", op_status, len)); - - break; - } - } - } - - return op_status; -} - -/* - * I2C interface function as defined in "include/i2c.h". - * Probe the given I2C chip address by reading single byte from offset 0. - * Returns 0 if a chip responded, not 0 on failure. - */ - -int i2c_probe (uchar chip) -{ - u32 tmp; - - /* - * Try to read the first location of the chip. - * The Tsi108 HW doesn't support sending just the chip address - * and checkong for an <ACK> back. - */ - return i2c_read (chip, 0, 1, (uchar *)&tmp, 1); -} - -#endif diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index be900cf4d6e..17b3a805a2d 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -158,6 +158,15 @@ config PCA9551_I2C_ADDR help The I2C address of the PCA9551 LED controller. +config STM32MP_FUSE + bool "Enable STM32MP fuse wrapper providing the fuse API" + depends on ARCH_STM32MP && MISC + default y if CMD_FUSE + help + If you say Y here, you will get support for the fuse API (OTP) + for STM32MP architecture. + This API is needed for CMD_FUSE. + config STM32_RCC bool "Enable RCC driver for the STM32 SoC's family" depends on STM32 && MISC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e362609d62a..4ce9d213f06 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -51,5 +51,6 @@ obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o obj-$(CONFIG_QFW) += qfw.o obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_STM32_RCC) += stm32_rcc.o +obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o diff --git a/drivers/misc/stm32mp_fuse.c b/drivers/misc/stm32mp_fuse.c new file mode 100644 index 00000000000..2d661351a17 --- /dev/null +++ b/drivers/misc/stm32mp_fuse.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <command.h> +#include <misc.h> +#include <errno.h> +#include <dm/device.h> +#include <dm/uclass.h> + +#define STM32MP_OTP_BANK 0 + +/* + * The 'fuse' command API + */ +int fuse_read(u32 bank, u32 word, u32 *val) +{ + int ret = 0; + struct udevice *dev; + + switch (bank) { + case STM32MP_OTP_BANK: + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + ret = misc_read(dev, word * 4 + STM32_BSEC_SHADOW_OFFSET, + val, 4); + break; + + default: + printf("stm32mp %s: wrong value for bank %i\n", __func__, bank); + ret = -EINVAL; + break; + } + + return ret; +} + +int fuse_prog(u32 bank, u32 word, u32 val) +{ + struct udevice *dev; + int ret; + + switch (bank) { + case STM32MP_OTP_BANK: + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + ret = misc_write(dev, word * 4 + STM32_BSEC_OTP_OFFSET, + &val, 4); + break; + + default: + printf("stm32mp %s: wrong value for bank %i\n", __func__, bank); + ret = -EINVAL; + break; + } + + return ret; +} + +int fuse_sense(u32 bank, u32 word, u32 *val) +{ + struct udevice *dev; + int ret; + + switch (bank) { + case STM32MP_OTP_BANK: + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + ret = misc_read(dev, word * 4 + STM32_BSEC_OTP_OFFSET, val, 4); + break; + + default: + printf("stm32mp %s: wrong value for bank %i\n", __func__, bank); + ret = -EINVAL; + break; + } + + return ret; +} + +int fuse_override(u32 bank, u32 word, u32 val) +{ + struct udevice *dev; + int ret; + + switch (bank) { + case STM32MP_OTP_BANK: + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + ret = misc_write(dev, word * 4 + STM32_BSEC_SHADOW_OFFSET, + &val, 4); + break; + + default: + printf("stm32mp %s: wrong value for bank %i\n", + __func__, bank); + ret = -EINVAL; + break; + } + + return ret; +} diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 3f15f85efda..693b3ceaf00 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -71,6 +71,13 @@ config MMC_HW_PARTITIONING This adds a command and an API to do hardware partitioning on eMMC devices. +config SUPPORT_EMMC_RPMB + bool "Support eMMC replay protected memory block (RPMB)" + imply CMD_MMC_RPMB + help + Enable support for reading, writing and programming the + key for the Replay Protection Memory Block partition in eMMC. + config MMC_IO_VOLTAGE bool "Support IO voltage configuration" help diff --git a/drivers/mmc/bcm2835_sdhost.c b/drivers/mmc/bcm2835_sdhost.c index 96428333b0a..1ce019af579 100644 --- a/drivers/mmc/bcm2835_sdhost.c +++ b/drivers/mmc/bcm2835_sdhost.c @@ -163,7 +163,6 @@ struct bcm2835_host { int clock; /* Current clock speed */ unsigned int max_clk; /* Max possible freq */ unsigned int blocks; /* remaining PIO blocks */ - int irq; /* Device IRQ */ u32 ns_per_fifo_word; @@ -173,14 +172,7 @@ struct bcm2835_host { struct mmc_cmd *cmd; /* Current command */ struct mmc_data *data; /* Current data request */ - bool data_complete:1;/* Data finished before cmd */ bool use_busy:1; /* Wait for busy interrupt */ - bool wait_data_complete:1; /* Wait for data */ - - /* for threaded irq handler */ - bool irq_block; - bool irq_busy; - bool irq_data; struct udevice *dev; struct mmc *mmc; @@ -240,17 +232,9 @@ static void bcm2835_reset_internal(struct bcm2835_host *host) writel(host->cdiv, host->ioaddr + SDCDIV); } -static int bcm2835_finish_command(struct bcm2835_host *host); - -static void bcm2835_wait_transfer_complete(struct bcm2835_host *host) +static int bcm2835_wait_transfer_complete(struct bcm2835_host *host) { - int timediff; - u32 alternate_idle; - - alternate_idle = (host->data->flags & MMC_DATA_READ) ? - SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1; - - timediff = 0; + int timediff = 0; while (1) { u32 edm, fsm; @@ -261,7 +245,10 @@ static void bcm2835_wait_transfer_complete(struct bcm2835_host *host) if ((fsm == SDEDM_FSM_IDENTMODE) || (fsm == SDEDM_FSM_DATAMODE)) break; - if (fsm == alternate_idle) { + + if ((fsm == SDEDM_FSM_READWAIT) || + (fsm == SDEDM_FSM_WRITESTART1) || + (fsm == SDEDM_FSM_READDATA)) { writel(edm | SDEDM_FORCE_DATA_MODE, host->ioaddr + SDEDM); break; @@ -273,9 +260,11 @@ static void bcm2835_wait_transfer_complete(struct bcm2835_host *host) "wait_transfer_complete - still waiting after %d retries\n", timediff); bcm2835_dumpregs(host); - return; + return -ETIMEDOUT; } } + + return 0; } static int bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read) @@ -322,6 +311,9 @@ static int bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read) fsm_state != SDEDM_FSM_READCRC)) || (!is_read && (fsm_state != SDEDM_FSM_WRITEDATA && + fsm_state != SDEDM_FSM_WRITEWAIT1 && + fsm_state != SDEDM_FSM_WRITEWAIT2 && + fsm_state != SDEDM_FSM_WRITECRC && fsm_state != SDEDM_FSM_WRITESTART1 && fsm_state != SDEDM_FSM_WRITESTART2))) { hsts = readl(host->ioaddr + SDHSTS); @@ -358,9 +350,8 @@ static int bcm2835_transfer_pio(struct bcm2835_host *host) is_read = (host->data->flags & MMC_DATA_READ) != 0; ret = bcm2835_transfer_block_pio(host, is_read); - - if (host->wait_data_complete) - bcm2835_wait_transfer_complete(host); + if (ret) + return ret; sdhsts = readl(host->ioaddr + SDHSTS); if (sdhsts & (SDHSTS_CRC16_ERROR | @@ -379,21 +370,8 @@ static int bcm2835_transfer_pio(struct bcm2835_host *host) return ret; } -static void bcm2835_set_transfer_irqs(struct bcm2835_host *host) -{ - u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN | - SDHCFG_BUSY_IRPT_EN; - - host->hcfg = (host->hcfg & ~all_irqs) | - SDHCFG_DATA_IRPT_EN | - SDHCFG_BUSY_IRPT_EN; - - writel(host->hcfg, host->ioaddr + SDHCFG); -} - -static -void bcm2835_prepare_data(struct bcm2835_host *host, struct mmc_cmd *cmd, - struct mmc_data *data) +static void bcm2835_prepare_data(struct bcm2835_host *host, struct mmc_cmd *cmd, + struct mmc_data *data) { WARN_ON(host->data); @@ -401,14 +379,9 @@ void bcm2835_prepare_data(struct bcm2835_host *host, struct mmc_cmd *cmd, if (!data) return; - host->wait_data_complete = cmd->cmdidx != MMC_CMD_READ_MULTIPLE_BLOCK; - host->data_complete = false; - /* Use PIO */ host->blocks = data->blocks; - bcm2835_set_transfer_irqs(host); - writel(data->blocksize, host->ioaddr + SDHBCT); writel(data->blocks, host->ioaddr + SDHBLC); } @@ -483,36 +456,6 @@ static int bcm2835_send_command(struct bcm2835_host *host, struct mmc_cmd *cmd, return 0; } -static int bcm2835_transfer_complete(struct bcm2835_host *host) -{ - int ret = 0; - - WARN_ON(!host->data_complete); - - host->data = NULL; - - return ret; -} - -static void bcm2835_finish_data(struct bcm2835_host *host) -{ - host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN); - writel(host->hcfg, host->ioaddr + SDHCFG); - - host->data_complete = true; - - if (host->cmd) { - /* Data managed to finish before the - * command completed. Make sure we do - * things in the proper order. - */ - dev_dbg(dev, "Finished early - HSTS %08x\n", - readl(host->ioaddr + SDHSTS)); - } else { - bcm2835_transfer_complete(host); - } -} - static int bcm2835_finish_command(struct bcm2835_host *host) { struct mmc_cmd *cmd = host->cmd; @@ -562,8 +505,6 @@ static int bcm2835_finish_command(struct bcm2835_host *host) /* Processed actual command. */ host->cmd = NULL; - if (host->data && host->data_complete) - ret = bcm2835_transfer_complete(host); return ret; } @@ -608,159 +549,44 @@ static int bcm2835_check_data_error(struct bcm2835_host *host, u32 intmask) return ret; } -static void bcm2835_busy_irq(struct bcm2835_host *host) -{ - if (WARN_ON(!host->cmd)) { - bcm2835_dumpregs(host); - return; - } - - if (WARN_ON(!host->use_busy)) { - bcm2835_dumpregs(host); - return; - } - host->use_busy = false; - - bcm2835_finish_command(host); -} - -static void bcm2835_data_irq(struct bcm2835_host *host, u32 intmask) +static int bcm2835_transmit(struct bcm2835_host *host) { + u32 intmask = readl(host->ioaddr + SDHSTS); int ret; - /* - * There are no dedicated data/space available interrupt - * status bits, so it is necessary to use the single shared - * data/space available FIFO status bits. It is therefore not - * an error to get here when there is no data transfer in - * progress. - */ - if (!host->data) - return; - + /* Check for errors */ ret = bcm2835_check_data_error(host, intmask); if (ret) - goto finished; - - if (host->data->flags & MMC_DATA_WRITE) { - /* Use the block interrupt for writes after the first block */ - host->hcfg &= ~(SDHCFG_DATA_IRPT_EN); - host->hcfg |= SDHCFG_BLOCK_IRPT_EN; - writel(host->hcfg, host->ioaddr + SDHCFG); - bcm2835_transfer_pio(host); - } else { - bcm2835_transfer_pio(host); - host->blocks--; - if ((host->blocks == 0)) - goto finished; - } - return; + return ret; -finished: - host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN); - writel(host->hcfg, host->ioaddr + SDHCFG); -} - -static void bcm2835_data_threaded_irq(struct bcm2835_host *host) -{ - if (!host->data) - return; - if ((host->blocks == 0)) - bcm2835_finish_data(host); -} - -static void bcm2835_block_irq(struct bcm2835_host *host) -{ - if (WARN_ON(!host->data)) { - bcm2835_dumpregs(host); - return; - } - - WARN_ON(!host->blocks); - if ((--host->blocks == 0)) - bcm2835_finish_data(host); - else - bcm2835_transfer_pio(host); -} + ret = bcm2835_check_cmd_error(host, intmask); + if (ret) + return ret; -static irqreturn_t bcm2835_irq(int irq, void *dev_id) -{ - irqreturn_t result = IRQ_NONE; - struct bcm2835_host *host = dev_id; - u32 intmask; - - intmask = readl(host->ioaddr + SDHSTS); - - writel(SDHSTS_BUSY_IRPT | - SDHSTS_BLOCK_IRPT | - SDHSTS_SDIO_IRPT | - SDHSTS_DATA_FLAG, - host->ioaddr + SDHSTS); - - if (intmask & SDHSTS_BLOCK_IRPT) { - bcm2835_check_data_error(host, intmask); - host->irq_block = true; - result = IRQ_WAKE_THREAD; + /* Handle wait for busy end */ + if (host->use_busy && (intmask & SDHSTS_BUSY_IRPT)) { + writel(SDHSTS_BUSY_IRPT, host->ioaddr + SDHSTS); + host->use_busy = false; + bcm2835_finish_command(host); } - if (intmask & SDHSTS_BUSY_IRPT) { - if (!bcm2835_check_cmd_error(host, intmask)) { - host->irq_busy = true; - result = IRQ_WAKE_THREAD; - } else { - result = IRQ_HANDLED; + /* Handle PIO data transfer */ + if (host->data) { + ret = bcm2835_transfer_pio(host); + if (ret) + return ret; + host->blocks--; + if (host->blocks == 0) { + /* Wait for command to complete for real */ + ret = bcm2835_wait_transfer_complete(host); + if (ret) + return ret; + /* Transfer complete */ + host->data = NULL; } } - /* There is no true data interrupt status bit, so it is - * necessary to qualify the data flag with the interrupt - * enable bit. - */ - if ((intmask & SDHSTS_DATA_FLAG) && - (host->hcfg & SDHCFG_DATA_IRPT_EN)) { - bcm2835_data_irq(host, intmask); - host->irq_data = true; - result = IRQ_WAKE_THREAD; - } - - return result; -} - -static irqreturn_t bcm2835_threaded_irq(int irq, void *dev_id) -{ - struct bcm2835_host *host = dev_id; - - if (host->irq_block) { - host->irq_block = false; - bcm2835_block_irq(host); - } - - if (host->irq_busy) { - host->irq_busy = false; - bcm2835_busy_irq(host); - } - - if (host->irq_data) { - host->irq_data = false; - bcm2835_data_threaded_irq(host); - } - - return IRQ_HANDLED; -} - -static void bcm2835_irq_poll(struct bcm2835_host *host) -{ - u32 intmask; - - while (1) { - intmask = readl(host->ioaddr + SDHSTS); - if (intmask & (SDHSTS_BUSY_IRPT | SDHSTS_BLOCK_IRPT | - SDHSTS_SDIO_IRPT | SDHSTS_DATA_FLAG)) { - bcm2835_irq(0, host); - bcm2835_threaded_irq(0, host); - return; - } - } + return 0; } static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock) @@ -864,8 +690,11 @@ static int bcm2835_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, } /* Wait for completion of busy signal or data transfer */ - while (host->use_busy || host->data) - bcm2835_irq_poll(host); + while (host->use_busy || host->data) { + ret = bcm2835_transmit(host); + if (ret) + break; + } return ret; } diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index 11cc438ce6a..e8292c438d9 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -235,8 +235,8 @@ static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, static void stm32_sdmmc2_start_cmd(struct stm32_sdmmc2_priv *priv, struct mmc_cmd *cmd, u32 cmd_param) { - if (readl(priv->base + SDMMC_ARG) & SDMMC_CMD_CPSMEN) - writel(0, priv->base + SDMMC_ARG); + if (readl(priv->base + SDMMC_CMD) & SDMMC_CMD_CPSMEN) + writel(0, priv->base + SDMMC_CMD); cmd_param |= cmd->cmdidx | SDMMC_CMD_CPSMEN; if (cmd->resp_type & MMC_RSP_PRESENT) { diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 851f82fb014..584bfdf2f9f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -58,7 +58,6 @@ obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o -obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o obj-$(CONFIG_ULI526X) += uli526x.o obj-$(CONFIG_VSC7385_ENET) += vsc7385.o obj-$(CONFIG_XILINX_AXIEMAC) += xilinx_axi_emac.o diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c deleted file mode 100644 index 108cf61647f..00000000000 --- a/drivers/net/tsi108_eth.c +++ /dev/null @@ -1,1015 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/*********************************************************************** - * - * Copyright (c) 2005 Freescale Semiconductor, Inc. - * - * Description: - * Ethernet interface for Tundra TSI108 bridge chip - * - ***********************************************************************/ - -#include <config.h> - -#if !defined(CONFIG_TSI108_ETH_NUM_PORTS) || (CONFIG_TSI108_ETH_NUM_PORTS > 2) -#error "CONFIG_TSI108_ETH_NUM_PORTS must be defined as 1 or 2" -#endif - -#include <common.h> -#include <malloc.h> -#include <net.h> -#include <netdev.h> -#include <asm/cache.h> - -#ifdef DEBUG -#define TSI108_ETH_DEBUG 7 -#else -#define TSI108_ETH_DEBUG 0 -#endif - -#if TSI108_ETH_DEBUG > 0 -#define debug_lev(lev, fmt, args...) \ -if (lev <= TSI108_ETH_DEBUG) \ -printf ("%s %d: " fmt, __FUNCTION__, __LINE__, ##args) -#else -#define debug_lev(lev, fmt, args...) do{}while(0) -#endif - -#define RX_PRINT_ERRORS -#define TX_PRINT_ERRORS - -#define ETH_BASE (CONFIG_SYS_TSI108_CSR_BASE + 0x6000) - -#define ETH_PORT_OFFSET 0x400 - -#define __REG32(base, offset) (*((volatile u32 *)((char *)(base) + (offset)))) - -#define reg_MAC_CONFIG_1(base) __REG32(base, 0x00000000) -#define MAC_CONFIG_1_TX_ENABLE (0x00000001) -#define MAC_CONFIG_1_SYNC_TX_ENABLE (0x00000002) -#define MAC_CONFIG_1_RX_ENABLE (0x00000004) -#define MAC_CONFIG_1_SYNC_RX_ENABLE (0x00000008) -#define MAC_CONFIG_1_TX_FLOW_CONTROL (0x00000010) -#define MAC_CONFIG_1_RX_FLOW_CONTROL (0x00000020) -#define MAC_CONFIG_1_LOOP_BACK (0x00000100) -#define MAC_CONFIG_1_RESET_TX_FUNCTION (0x00010000) -#define MAC_CONFIG_1_RESET_RX_FUNCTION (0x00020000) -#define MAC_CONFIG_1_RESET_TX_MAC (0x00040000) -#define MAC_CONFIG_1_RESET_RX_MAC (0x00080000) -#define MAC_CONFIG_1_SIM_RESET (0x40000000) -#define MAC_CONFIG_1_SOFT_RESET (0x80000000) - -#define reg_MAC_CONFIG_2(base) __REG32(base, 0x00000004) -#define MAC_CONFIG_2_FULL_DUPLEX (0x00000001) -#define MAC_CONFIG_2_CRC_ENABLE (0x00000002) -#define MAC_CONFIG_2_PAD_CRC (0x00000004) -#define MAC_CONFIG_2_LENGTH_CHECK (0x00000010) -#define MAC_CONFIG_2_HUGE_FRAME (0x00000020) -#define MAC_CONFIG_2_INTERFACE_MODE(val) (((val) & 0x3) << 8) -#define MAC_CONFIG_2_PREAMBLE_LENGTH(val) (((val) & 0xf) << 12) -#define INTERFACE_MODE_NIBBLE 1 /* 10/100 Mb/s MII) */ -#define INTERFACE_MODE_BYTE 2 /* 1000 Mb/s GMII/TBI */ - -#define reg_MAXIMUM_FRAME_LENGTH(base) __REG32(base, 0x00000010) - -#define reg_MII_MGMT_CONFIG(base) __REG32(base, 0x00000020) -#define MII_MGMT_CONFIG_MGMT_CLOCK_SELECT(val) ((val) & 0x7) -#define MII_MGMT_CONFIG_NO_PREAMBLE (0x00000010) -#define MII_MGMT_CONFIG_SCAN_INCREMENT (0x00000020) -#define MII_MGMT_CONFIG_RESET_MGMT (0x80000000) - -#define reg_MII_MGMT_COMMAND(base) __REG32(base, 0x00000024) -#define MII_MGMT_COMMAND_READ_CYCLE (0x00000001) -#define MII_MGMT_COMMAND_SCAN_CYCLE (0x00000002) - -#define reg_MII_MGMT_ADDRESS(base) __REG32(base, 0x00000028) -#define reg_MII_MGMT_CONTROL(base) __REG32(base, 0x0000002c) -#define reg_MII_MGMT_STATUS(base) __REG32(base, 0x00000030) - -#define reg_MII_MGMT_INDICATORS(base) __REG32(base, 0x00000034) -#define MII_MGMT_INDICATORS_BUSY (0x00000001) -#define MII_MGMT_INDICATORS_SCAN (0x00000002) -#define MII_MGMT_INDICATORS_NOT_VALID (0x00000004) - -#define reg_INTERFACE_STATUS(base) __REG32(base, 0x0000003c) -#define INTERFACE_STATUS_LINK_FAIL (0x00000008) -#define INTERFACE_STATUS_EXCESS_DEFER (0x00000200) - -#define reg_STATION_ADDRESS_1(base) __REG32(base, 0x00000040) -#define reg_STATION_ADDRESS_2(base) __REG32(base, 0x00000044) - -#define reg_PORT_CONTROL(base) __REG32(base, 0x00000200) -#define PORT_CONTROL_PRI (0x00000001) -#define PORT_CONTROL_BPT (0x00010000) -#define PORT_CONTROL_SPD (0x00040000) -#define PORT_CONTROL_RBC (0x00080000) -#define PORT_CONTROL_PRB (0x00200000) -#define PORT_CONTROL_DIS (0x00400000) -#define PORT_CONTROL_TBI (0x00800000) -#define PORT_CONTROL_STE (0x10000000) -#define PORT_CONTROL_ZOR (0x20000000) -#define PORT_CONTROL_CLR (0x40000000) -#define PORT_CONTROL_SRT (0x80000000) - -#define reg_TX_CONFIG(base) __REG32(base, 0x00000220) -#define TX_CONFIG_START_Q (0x00000003) -#define TX_CONFIG_EHP (0x00400000) -#define TX_CONFIG_CHP (0x00800000) -#define TX_CONFIG_RST (0x80000000) - -#define reg_TX_CONTROL(base) __REG32(base, 0x00000224) -#define TX_CONTROL_GO (0x00008000) -#define TX_CONTROL_MP (0x01000000) -#define TX_CONTROL_EAI (0x20000000) -#define TX_CONTROL_ABT (0x40000000) -#define TX_CONTROL_EII (0x80000000) - -#define reg_TX_STATUS(base) __REG32(base, 0x00000228) -#define TX_STATUS_QUEUE_USABLE (0x0000000f) -#define TX_STATUS_CURR_Q (0x00000300) -#define TX_STATUS_ACT (0x00008000) -#define TX_STATUS_QUEUE_IDLE (0x000f0000) -#define TX_STATUS_EOQ_PENDING (0x0f000000) - -#define reg_TX_EXTENDED_STATUS(base) __REG32(base, 0x0000022c) -#define TX_EXTENDED_STATUS_END_OF_QUEUE_CONDITION (0x0000000f) -#define TX_EXTENDED_STATUS_END_OF_FRAME_CONDITION (0x00000f00) -#define TX_EXTENDED_STATUS_DESCRIPTOR_INTERRUPT_CONDITION (0x000f0000) -#define TX_EXTENDED_STATUS_ERROR_FLAG (0x0f000000) - -#define reg_TX_THRESHOLDS(base) __REG32(base, 0x00000230) - -#define reg_TX_DIAGNOSTIC_ADDR(base) __REG32(base, 0x00000270) -#define TX_DIAGNOSTIC_ADDR_INDEX (0x0000007f) -#define TX_DIAGNOSTIC_ADDR_DFR (0x40000000) -#define TX_DIAGNOSTIC_ADDR_AI (0x80000000) - -#define reg_TX_DIAGNOSTIC_DATA(base) __REG32(base, 0x00000274) - -#define reg_TX_ERROR_STATUS(base) __REG32(base, 0x00000278) -#define TX_ERROR_STATUS (0x00000278) -#define TX_ERROR_STATUS_QUEUE_0_ERROR_RESPONSE (0x0000000f) -#define TX_ERROR_STATUS_TEA_ON_QUEUE_0 (0x00000010) -#define TX_ERROR_STATUS_RER_ON_QUEUE_0 (0x00000020) -#define TX_ERROR_STATUS_TER_ON_QUEUE_0 (0x00000040) -#define TX_ERROR_STATUS_DER_ON_QUEUE_0 (0x00000080) -#define TX_ERROR_STATUS_QUEUE_1_ERROR_RESPONSE (0x00000f00) -#define TX_ERROR_STATUS_TEA_ON_QUEUE_1 (0x00001000) -#define TX_ERROR_STATUS_RER_ON_QUEUE_1 (0x00002000) -#define TX_ERROR_STATUS_TER_ON_QUEUE_1 (0x00004000) -#define TX_ERROR_STATUS_DER_ON_QUEUE_1 (0x00008000) -#define TX_ERROR_STATUS_QUEUE_2_ERROR_RESPONSE (0x000f0000) -#define TX_ERROR_STATUS_TEA_ON_QUEUE_2 (0x00100000) -#define TX_ERROR_STATUS_RER_ON_QUEUE_2 (0x00200000) -#define TX_ERROR_STATUS_TER_ON_QUEUE_2 (0x00400000) -#define TX_ERROR_STATUS_DER_ON_QUEUE_2 (0x00800000) -#define TX_ERROR_STATUS_QUEUE_3_ERROR_RESPONSE (0x0f000000) -#define TX_ERROR_STATUS_TEA_ON_QUEUE_3 (0x10000000) -#define TX_ERROR_STATUS_RER_ON_QUEUE_3 (0x20000000) -#define TX_ERROR_STATUS_TER_ON_QUEUE_3 (0x40000000) -#define TX_ERROR_STATUS_DER_ON_QUEUE_3 (0x80000000) - -#define reg_TX_QUEUE_0_CONFIG(base) __REG32(base, 0x00000280) -#define TX_QUEUE_0_CONFIG_OCN_PORT (0x0000003f) -#define TX_QUEUE_0_CONFIG_BSWP (0x00000400) -#define TX_QUEUE_0_CONFIG_WSWP (0x00000800) -#define TX_QUEUE_0_CONFIG_AM (0x00004000) -#define TX_QUEUE_0_CONFIG_GVI (0x00008000) -#define TX_QUEUE_0_CONFIG_EEI (0x00010000) -#define TX_QUEUE_0_CONFIG_ELI (0x00020000) -#define TX_QUEUE_0_CONFIG_ENI (0x00040000) -#define TX_QUEUE_0_CONFIG_ESI (0x00080000) -#define TX_QUEUE_0_CONFIG_EDI (0x00100000) - -#define reg_TX_QUEUE_0_BUF_CONFIG(base) __REG32(base, 0x00000284) -#define TX_QUEUE_0_BUF_CONFIG_OCN_PORT (0x0000003f) -#define TX_QUEUE_0_BUF_CONFIG_BURST (0x00000300) -#define TX_QUEUE_0_BUF_CONFIG_BSWP (0x00000400) -#define TX_QUEUE_0_BUF_CONFIG_WSWP (0x00000800) - -#define OCN_PORT_HLP 0 /* HLP Interface */ -#define OCN_PORT_PCI_X 1 /* PCI-X Interface */ -#define OCN_PORT_PROCESSOR_MASTER 2 /* Processor Interface (master) */ -#define OCN_PORT_PROCESSOR_SLAVE 3 /* Processor Interface (slave) */ -#define OCN_PORT_MEMORY 4 /* Memory Controller */ -#define OCN_PORT_DMA 5 /* DMA Controller */ -#define OCN_PORT_ETHERNET 6 /* Ethernet Controller */ -#define OCN_PORT_PRINT 7 /* Print Engine Interface */ - -#define reg_TX_QUEUE_0_PTR_LOW(base) __REG32(base, 0x00000288) - -#define reg_TX_QUEUE_0_PTR_HIGH(base) __REG32(base, 0x0000028c) -#define TX_QUEUE_0_PTR_HIGH_VALID (0x80000000) - -#define reg_RX_CONFIG(base) __REG32(base, 0x00000320) -#define RX_CONFIG_DEF_Q (0x00000003) -#define RX_CONFIG_EMF (0x00000100) -#define RX_CONFIG_EUF (0x00000200) -#define RX_CONFIG_BFE (0x00000400) -#define RX_CONFIG_MFE (0x00000800) -#define RX_CONFIG_UFE (0x00001000) -#define RX_CONFIG_SE (0x00002000) -#define RX_CONFIG_ABF (0x00200000) -#define RX_CONFIG_APE (0x00400000) -#define RX_CONFIG_CHP (0x00800000) -#define RX_CONFIG_RST (0x80000000) - -#define reg_RX_CONTROL(base) __REG32(base, 0x00000324) -#define GE_E0_RX_CONTROL_QUEUE_ENABLES (0x0000000f) -#define GE_E0_RX_CONTROL_GO (0x00008000) -#define GE_E0_RX_CONTROL_EAI (0x20000000) -#define GE_E0_RX_CONTROL_ABT (0x40000000) -#define GE_E0_RX_CONTROL_EII (0x80000000) - -#define reg_RX_EXTENDED_STATUS(base) __REG32(base, 0x0000032c) -#define RX_EXTENDED_STATUS (0x0000032c) -#define RX_EXTENDED_STATUS_EOQ (0x0000000f) -#define RX_EXTENDED_STATUS_EOQ_0 (0x00000001) -#define RX_EXTENDED_STATUS_EOF (0x00000f00) -#define RX_EXTENDED_STATUS_DESCRIPTOR_INTERRUPT_CONDITION (0x000f0000) -#define RX_EXTENDED_STATUS_ERROR_FLAG (0x0f000000) - -#define reg_RX_THRESHOLDS(base) __REG32(base, 0x00000330) - -#define reg_RX_DIAGNOSTIC_ADDR(base) __REG32(base, 0x00000370) -#define RX_DIAGNOSTIC_ADDR_INDEX (0x0000007f) -#define RX_DIAGNOSTIC_ADDR_DFR (0x40000000) -#define RX_DIAGNOSTIC_ADDR_AI (0x80000000) - -#define reg_RX_DIAGNOSTIC_DATA(base) __REG32(base, 0x00000374) - -#define reg_RX_QUEUE_0_CONFIG(base) __REG32(base, 0x00000380) -#define RX_QUEUE_0_CONFIG_OCN_PORT (0x0000003f) -#define RX_QUEUE_0_CONFIG_BSWP (0x00000400) -#define RX_QUEUE_0_CONFIG_WSWP (0x00000800) -#define RX_QUEUE_0_CONFIG_AM (0x00004000) -#define RX_QUEUE_0_CONFIG_EEI (0x00010000) -#define RX_QUEUE_0_CONFIG_ELI (0x00020000) -#define RX_QUEUE_0_CONFIG_ENI (0x00040000) -#define RX_QUEUE_0_CONFIG_ESI (0x00080000) -#define RX_QUEUE_0_CONFIG_EDI (0x00100000) - -#define reg_RX_QUEUE_0_BUF_CONFIG(base) __REG32(base, 0x00000384) -#define RX_QUEUE_0_BUF_CONFIG_OCN_PORT (0x0000003f) -#define RX_QUEUE_0_BUF_CONFIG_BURST (0x00000300) -#define RX_QUEUE_0_BUF_CONFIG_BSWP (0x00000400) -#define RX_QUEUE_0_BUF_CONFIG_WSWP (0x00000800) - -#define reg_RX_QUEUE_0_PTR_LOW(base) __REG32(base, 0x00000388) - -#define reg_RX_QUEUE_0_PTR_HIGH(base) __REG32(base, 0x0000038c) -#define RX_QUEUE_0_PTR_HIGH_VALID (0x80000000) - -/* - * PHY register definitions - */ -/* the first 15 PHY registers are standard. */ -#define PHY_CTRL_REG 0 /* Control Register */ -#define PHY_STATUS_REG 1 /* Status Regiser */ -#define PHY_ID1_REG 2 /* Phy Id Reg (word 1) */ -#define PHY_ID2_REG 3 /* Phy Id Reg (word 2) */ -#define PHY_AN_ADV_REG 4 /* Autoneg Advertisement */ -#define PHY_LP_ABILITY_REG 5 /* Link Partner Ability (Base Page) */ -#define PHY_AUTONEG_EXP_REG 6 /* Autoneg Expansion Reg */ -#define PHY_NEXT_PAGE_TX_REG 7 /* Next Page TX */ -#define PHY_LP_NEXT_PAGE_REG 8 /* Link Partner Next Page */ -#define PHY_1000T_CTRL_REG 9 /* 1000Base-T Control Reg */ -#define PHY_1000T_STATUS_REG 10 /* 1000Base-T Status Reg */ -#define PHY_EXT_STATUS_REG 11 /* Extended Status Reg */ - -/* - * PHY Register bit masks. - */ -#define PHY_CTRL_RESET (1 << 15) -#define PHY_CTRL_LOOPBACK (1 << 14) -#define PHY_CTRL_SPEED0 (1 << 13) -#define PHY_CTRL_AN_EN (1 << 12) -#define PHY_CTRL_PWR_DN (1 << 11) -#define PHY_CTRL_ISOLATE (1 << 10) -#define PHY_CTRL_RESTART_AN (1 << 9) -#define PHY_CTRL_FULL_DUPLEX (1 << 8) -#define PHY_CTRL_CT_EN (1 << 7) -#define PHY_CTRL_SPEED1 (1 << 6) - -#define PHY_STAT_100BASE_T4 (1 << 15) -#define PHY_STAT_100BASE_X_FD (1 << 14) -#define PHY_STAT_100BASE_X_HD (1 << 13) -#define PHY_STAT_10BASE_T_FD (1 << 12) -#define PHY_STAT_10BASE_T_HD (1 << 11) -#define PHY_STAT_100BASE_T2_FD (1 << 10) -#define PHY_STAT_100BASE_T2_HD (1 << 9) -#define PHY_STAT_EXT_STAT (1 << 8) -#define PHY_STAT_RESERVED (1 << 7) -#define PHY_STAT_MFPS (1 << 6) /* Management Frames Preamble Suppression */ -#define PHY_STAT_AN_COMPLETE (1 << 5) -#define PHY_STAT_REM_FAULT (1 << 4) -#define PHY_STAT_AN_CAP (1 << 3) -#define PHY_STAT_LINK_UP (1 << 2) -#define PHY_STAT_JABBER (1 << 1) -#define PHY_STAT_EXT_CAP (1 << 0) - -#define TBI_CONTROL_2 0x11 -#define TBI_CONTROL_2_ENABLE_COMMA_DETECT 0x0001 -#define TBI_CONTROL_2_ENABLE_WRAP 0x0002 -#define TBI_CONTROL_2_G_MII_MODE 0x0010 -#define TBI_CONTROL_2_RECEIVE_CLOCK_SELECT 0x0020 -#define TBI_CONTROL_2_AUTO_NEGOTIATION_SENSE 0x0100 -#define TBI_CONTROL_2_DISABLE_TRANSMIT_RUNNING_DISPARITY 0x1000 -#define TBI_CONTROL_2_DISABLE_RECEIVE_RUNNING_DISPARITY 0x2000 -#define TBI_CONTROL_2_SHORTCUT_LINK_TIMER 0x4000 -#define TBI_CONTROL_2_SOFT_RESET 0x8000 - -/* marvel specific */ -#define MV1111_EXT_CTRL1_REG 16 /* PHY Specific Control Reg */ -#define MV1111_SPEC_STAT_REG 17 /* PHY Specific Status Reg */ -#define MV1111_EXT_CTRL2_REG 20 /* Extended PHY Specific Control Reg */ - -/* - * MARVELL 88E1111 PHY register bit masks - */ -/* PHY Specific Status Register (MV1111_EXT_CTRL1_REG) */ - -#define SPEC_STAT_SPEED_MASK (3 << 14) -#define SPEC_STAT_FULL_DUP (1 << 13) -#define SPEC_STAT_PAGE_RCVD (1 << 12) -#define SPEC_STAT_RESOLVED (1 << 11) /* Speed and Duplex Resolved */ -#define SPEC_STAT_LINK_UP (1 << 10) -#define SPEC_STAT_CABLE_LEN_MASK (7 << 7)/* Cable Length (100/1000 modes only) */ -#define SPEC_STAT_MDIX (1 << 6) -#define SPEC_STAT_POLARITY (1 << 1) -#define SPEC_STAT_JABBER (1 << 0) - -#define SPEED_1000 (2 << 14) -#define SPEED_100 (1 << 14) -#define SPEED_10 (0 << 14) - -#define TBI_ADDR 0x1E /* Ten Bit Interface address */ - -/* negotiated link parameters */ -#define LINK_SPEED_UNKNOWN 0 -#define LINK_SPEED_10 1 -#define LINK_SPEED_100 2 -#define LINK_SPEED_1000 3 - -#define LINK_DUPLEX_UNKNOWN 0 -#define LINK_DUPLEX_HALF 1 -#define LINK_DUPLEX_FULL 2 - -static unsigned int phy_address[] = { 8, 9 }; - -#define vuint32 volatile u32 - -/* TX/RX buffer descriptors. MUST be cache line aligned in memory. (32 byte) - * This structure is accessed by the ethernet DMA engine which means it - * MUST be in LITTLE ENDIAN format */ -struct dma_descriptor { - vuint32 start_addr0; /* buffer address, least significant bytes. */ - vuint32 start_addr1; /* buffer address, most significant bytes. */ - vuint32 next_descr_addr0;/* next descriptor address, least significant bytes. Must be 64-bit aligned. */ - vuint32 next_descr_addr1;/* next descriptor address, most significant bytes. */ - vuint32 vlan_byte_count;/* VLAN tag(top 2 bytes) and byte countt (bottom 2 bytes). */ - vuint32 config_status; /* Configuration/Status. */ - vuint32 reserved1; /* reserved to make the descriptor cache line aligned. */ - vuint32 reserved2; /* reserved to make the descriptor cache line aligned. */ -}; - -/* last next descriptor address flag */ -#define DMA_DESCR_LAST (1 << 31) - -/* TX DMA descriptor config status bits */ -#define DMA_DESCR_TX_EOF (1 << 0) /* end of frame */ -#define DMA_DESCR_TX_SOF (1 << 1) /* start of frame */ -#define DMA_DESCR_TX_PFVLAN (1 << 2) -#define DMA_DESCR_TX_HUGE (1 << 3) -#define DMA_DESCR_TX_PAD (1 << 4) -#define DMA_DESCR_TX_CRC (1 << 5) -#define DMA_DESCR_TX_DESCR_INT (1 << 14) -#define DMA_DESCR_TX_RETRY_COUNT 0x000F0000 -#define DMA_DESCR_TX_ONE_COLLISION (1 << 20) -#define DMA_DESCR_TX_LATE_COLLISION (1 << 24) -#define DMA_DESCR_TX_UNDERRUN (1 << 25) -#define DMA_DESCR_TX_RETRY_LIMIT (1 << 26) -#define DMA_DESCR_TX_OK (1 << 30) -#define DMA_DESCR_TX_OWNER (1 << 31) - -/* RX DMA descriptor status bits */ -#define DMA_DESCR_RX_EOF (1 << 0) -#define DMA_DESCR_RX_SOF (1 << 1) -#define DMA_DESCR_RX_VTF (1 << 2) -#define DMA_DESCR_RX_FRAME_IS_TYPE (1 << 3) -#define DMA_DESCR_RX_SHORT_FRAME (1 << 4) -#define DMA_DESCR_RX_HASH_MATCH (1 << 7) -#define DMA_DESCR_RX_BAD_FRAME (1 << 8) -#define DMA_DESCR_RX_OVERRUN (1 << 9) -#define DMA_DESCR_RX_MAX_FRAME_LEN (1 << 11) -#define DMA_DESCR_RX_CRC_ERROR (1 << 12) -#define DMA_DESCR_RX_DESCR_INT (1 << 13) -#define DMA_DESCR_RX_OWNER (1 << 15) - -#define RX_BUFFER_SIZE PKTSIZE -#define NUM_RX_DESC PKTBUFSRX - -static struct dma_descriptor tx_descriptor __attribute__ ((aligned(32))); - -static struct dma_descriptor rx_descr_array[NUM_RX_DESC] - __attribute__ ((aligned(32))); - -static struct dma_descriptor *rx_descr_current; - -static int tsi108_eth_probe (struct eth_device *dev, bd_t * bis); -static int tsi108_eth_send(struct eth_device *dev, void *packet, int length); -static int tsi108_eth_recv (struct eth_device *dev); -static void tsi108_eth_halt (struct eth_device *dev); -static unsigned int read_phy (unsigned int base, - unsigned int phy_addr, unsigned int phy_reg); -static void write_phy (unsigned int base, - unsigned int phy_addr, - unsigned int phy_reg, unsigned int phy_data); - -#if TSI108_ETH_DEBUG > 100 -/* - * print phy debug infomation - */ -static void dump_phy_regs (unsigned int phy_addr) -{ - int i; - - printf ("PHY %d registers\n", phy_addr); - for (i = 0; i <= 30; i++) { - printf ("%2d 0x%04x\n", i, read_phy (ETH_BASE, phy_addr, i)); - } - printf ("\n"); - -} -#else -#define dump_phy_regs(base) do{}while(0) -#endif - -#if TSI108_ETH_DEBUG > 100 -/* - * print debug infomation - */ -static void tx_diag_regs (unsigned int base) -{ - int i; - unsigned long dummy; - - printf ("TX diagnostics registers\n"); - reg_TX_DIAGNOSTIC_ADDR(base) = 0x00 | TX_DIAGNOSTIC_ADDR_AI; - udelay (1000); - dummy = reg_TX_DIAGNOSTIC_DATA(base); - for (i = 0x00; i <= 0x05; i++) { - udelay (1000); - printf ("0x%02x 0x%08x\n", i, reg_TX_DIAGNOSTIC_DATA(base)); - } - reg_TX_DIAGNOSTIC_ADDR(base) = 0x40 | TX_DIAGNOSTIC_ADDR_AI; - udelay (1000); - dummy = reg_TX_DIAGNOSTIC_DATA(base); - for (i = 0x40; i <= 0x47; i++) { - udelay (1000); - printf ("0x%02x 0x%08x\n", i, reg_TX_DIAGNOSTIC_DATA(base)); - } - printf ("\n"); - -} -#else -#define tx_diag_regs(base) do{}while(0) -#endif - -#if TSI108_ETH_DEBUG > 100 -/* - * print debug infomation - */ -static void rx_diag_regs (unsigned int base) -{ - int i; - unsigned long dummy; - - printf ("RX diagnostics registers\n"); - reg_RX_DIAGNOSTIC_ADDR(base) = 0x00 | RX_DIAGNOSTIC_ADDR_AI; - udelay (1000); - dummy = reg_RX_DIAGNOSTIC_DATA(base); - for (i = 0x00; i <= 0x05; i++) { - udelay (1000); - printf ("0x%02x 0x%08x\n", i, reg_RX_DIAGNOSTIC_DATA(base)); - } - reg_RX_DIAGNOSTIC_ADDR(base) = 0x40 | RX_DIAGNOSTIC_ADDR_AI; - udelay (1000); - dummy = reg_RX_DIAGNOSTIC_DATA(base); - for (i = 0x08; i <= 0x0a; i++) { - udelay (1000); - printf ("0x%02x 0x%08x\n", i, reg_RX_DIAGNOSTIC_DATA(base)); - } - printf ("\n"); - -} -#else -#define rx_diag_regs(base) do{}while(0) -#endif - -#if TSI108_ETH_DEBUG > 100 -/* - * print debug infomation - */ -static void debug_mii_regs (unsigned int base) -{ - printf ("MII_MGMT_CONFIG 0x%08x\n", reg_MII_MGMT_CONFIG(base)); - printf ("MII_MGMT_COMMAND 0x%08x\n", reg_MII_MGMT_COMMAND(base)); - printf ("MII_MGMT_ADDRESS 0x%08x\n", reg_MII_MGMT_ADDRESS(base)); - printf ("MII_MGMT_CONTROL 0x%08x\n", reg_MII_MGMT_CONTROL(base)); - printf ("MII_MGMT_STATUS 0x%08x\n", reg_MII_MGMT_STATUS(base)); - printf ("MII_MGMT_INDICATORS 0x%08x\n", reg_MII_MGMT_INDICATORS(base)); - printf ("\n"); - -} -#else -#define debug_mii_regs(base) do{}while(0) -#endif - -/* - * Wait until the phy bus is non-busy - */ -static void phy_wait (unsigned int base, unsigned int condition) -{ - int timeout; - - timeout = 0; - while (reg_MII_MGMT_INDICATORS(base) & condition) { - udelay (10); - if (++timeout > 10000) { - printf ("ERROR: timeout waiting for phy bus (%d)\n", - condition); - break; - } - } -} - -/* - * read phy register - */ -static unsigned int read_phy (unsigned int base, - unsigned int phy_addr, unsigned int phy_reg) -{ - unsigned int value; - - phy_wait (base, MII_MGMT_INDICATORS_BUSY); - - reg_MII_MGMT_ADDRESS(base) = (phy_addr << 8) | phy_reg; - - /* Ensure that the Read Cycle bit is cleared prior to next read cycle */ - reg_MII_MGMT_COMMAND(base) = 0; - - /* start the read */ - reg_MII_MGMT_COMMAND(base) = MII_MGMT_COMMAND_READ_CYCLE; - - /* wait for the read to complete */ - phy_wait (base, - MII_MGMT_INDICATORS_NOT_VALID | MII_MGMT_INDICATORS_BUSY); - - value = reg_MII_MGMT_STATUS(base); - - reg_MII_MGMT_COMMAND(base) = 0; - - return value; -} - -/* - * write phy register - */ -static void write_phy (unsigned int base, - unsigned int phy_addr, - unsigned int phy_reg, unsigned int phy_data) -{ - phy_wait (base, MII_MGMT_INDICATORS_BUSY); - - reg_MII_MGMT_ADDRESS(base) = (phy_addr << 8) | phy_reg; - - /* Ensure that the Read Cycle bit is cleared prior to next cycle */ - reg_MII_MGMT_COMMAND(base) = 0; - - /* start the write */ - reg_MII_MGMT_CONTROL(base) = phy_data; -} - -/* - * configure the marvell 88e1111 phy - */ -static int marvell_88e_phy_config (struct eth_device *dev, int *speed, - int *duplex) -{ - unsigned long base; - unsigned long phy_addr; - unsigned int phy_status; - unsigned int phy_spec_status; - int timeout; - int phy_speed; - int phy_duplex; - unsigned int value; - - phy_speed = LINK_SPEED_UNKNOWN; - phy_duplex = LINK_DUPLEX_UNKNOWN; - - base = dev->iobase; - phy_addr = (unsigned long)dev->priv; - - /* Take the PHY out of reset. */ - write_phy (ETH_BASE, phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET); - - /* Wait for the reset process to complete. */ - udelay (10); - timeout = 0; - while ((phy_status = - read_phy (ETH_BASE, phy_addr, PHY_CTRL_REG)) & PHY_CTRL_RESET) { - udelay (10); - if (++timeout > 10000) { - printf ("ERROR: timeout waiting for phy reset\n"); - break; - } - } - - /* TBI Configuration. */ - write_phy (base, TBI_ADDR, TBI_CONTROL_2, TBI_CONTROL_2_G_MII_MODE | - TBI_CONTROL_2_RECEIVE_CLOCK_SELECT); - /* Wait for the link to be established. */ - timeout = 0; - do { - udelay (20000); - phy_status = read_phy (ETH_BASE, phy_addr, PHY_STATUS_REG); - if (++timeout > 100) { - debug_lev(1, "ERROR: unable to establish link!!!\n"); - break; - } - } while ((phy_status & PHY_STAT_LINK_UP) == 0); - - if ((phy_status & PHY_STAT_LINK_UP) == 0) - return 0; - - value = 0; - phy_spec_status = read_phy (ETH_BASE, phy_addr, MV1111_SPEC_STAT_REG); - if (phy_spec_status & SPEC_STAT_RESOLVED) { - switch (phy_spec_status & SPEC_STAT_SPEED_MASK) { - case SPEED_1000: - phy_speed = LINK_SPEED_1000; - value |= PHY_CTRL_SPEED1; - break; - case SPEED_100: - phy_speed = LINK_SPEED_100; - value |= PHY_CTRL_SPEED0; - break; - case SPEED_10: - phy_speed = LINK_SPEED_10; - break; - } - if (phy_spec_status & SPEC_STAT_FULL_DUP) { - phy_duplex = LINK_DUPLEX_FULL; - value |= PHY_CTRL_FULL_DUPLEX; - } else - phy_duplex = LINK_DUPLEX_HALF; - } - /* set TBI speed */ - write_phy (base, TBI_ADDR, PHY_CTRL_REG, value); - write_phy (base, TBI_ADDR, PHY_AN_ADV_REG, 0x0060); - -#if TSI108_ETH_DEBUG > 0 - printf ("%s link is up", dev->name); - phy_spec_status = read_phy (ETH_BASE, phy_addr, MV1111_SPEC_STAT_REG); - if (phy_spec_status & SPEC_STAT_RESOLVED) { - switch (phy_speed) { - case LINK_SPEED_1000: - printf (", 1000 Mbps"); - break; - case LINK_SPEED_100: - printf (", 100 Mbps"); - break; - case LINK_SPEED_10: - printf (", 10 Mbps"); - break; - } - if (phy_duplex == LINK_DUPLEX_FULL) - printf (", Full duplex"); - else - printf (", Half duplex"); - } - printf ("\n"); -#endif - - dump_phy_regs (TBI_ADDR); - if (speed) - *speed = phy_speed; - if (duplex) - *duplex = phy_duplex; - - return 1; -} - -/* - * External interface - * - * register the tsi108 ethernet controllers with the multi-ethernet system - */ -int tsi108_eth_initialize (bd_t * bis) -{ - struct eth_device *dev; - int index; - - for (index = 0; index < CONFIG_TSI108_ETH_NUM_PORTS; index++) { - dev = (struct eth_device *)malloc(sizeof(struct eth_device)); - if (!dev) { - printf("tsi108: Can not allocate memory\n"); - break; - } - memset(dev, 0, sizeof(*dev)); - sprintf (dev->name, "TSI108_eth%d", index); - - dev->iobase = ETH_BASE + (index * ETH_PORT_OFFSET); - dev->priv = (void *)(phy_address[index]); - dev->init = tsi108_eth_probe; - dev->halt = tsi108_eth_halt; - dev->send = tsi108_eth_send; - dev->recv = tsi108_eth_recv; - - eth_register(dev); - } - return index; -} - -/* - * probe for and initialize a single ethernet interface - */ -static int tsi108_eth_probe (struct eth_device *dev, bd_t * bis) -{ - unsigned long base; - unsigned long value; - int index; - struct dma_descriptor *tx_descr; - struct dma_descriptor *rx_descr; - int speed; - int duplex; - - base = dev->iobase; - - reg_PORT_CONTROL(base) = PORT_CONTROL_STE | PORT_CONTROL_BPT; - - /* Bring DMA/FIFO out of reset. */ - reg_TX_CONFIG(base) = 0x00000000; - reg_RX_CONFIG(base) = 0x00000000; - - reg_TX_THRESHOLDS(base) = (192 << 16) | 192; - reg_RX_THRESHOLDS(base) = (192 << 16) | 112; - - /* Bring MAC out of reset. */ - reg_MAC_CONFIG_1(base) = 0x00000000; - - /* DMA MAC configuration. */ - reg_MAC_CONFIG_1(base) = - MAC_CONFIG_1_RX_ENABLE | MAC_CONFIG_1_TX_ENABLE; - - reg_MII_MGMT_CONFIG(base) = MII_MGMT_CONFIG_NO_PREAMBLE; - reg_MAXIMUM_FRAME_LENGTH(base) = RX_BUFFER_SIZE; - - /* Note: Early tsi108 manual did not have correct byte order - * for the station address.*/ - reg_STATION_ADDRESS_1(base) = (dev->enetaddr[5] << 24) | - (dev->enetaddr[4] << 16) | - (dev->enetaddr[3] << 8) | (dev->enetaddr[2] << 0); - - reg_STATION_ADDRESS_2(base) = (dev->enetaddr[1] << 24) | - (dev->enetaddr[0] << 16); - - if (marvell_88e_phy_config(dev, &speed, &duplex) == 0) - return -1; - - value = - MAC_CONFIG_2_PREAMBLE_LENGTH(7) | MAC_CONFIG_2_PAD_CRC | - MAC_CONFIG_2_CRC_ENABLE; - if (speed == LINK_SPEED_1000) - value |= MAC_CONFIG_2_INTERFACE_MODE(INTERFACE_MODE_BYTE); - else { - value |= MAC_CONFIG_2_INTERFACE_MODE(INTERFACE_MODE_NIBBLE); - reg_PORT_CONTROL(base) |= PORT_CONTROL_SPD; - } - if (duplex == LINK_DUPLEX_FULL) { - value |= MAC_CONFIG_2_FULL_DUPLEX; - reg_PORT_CONTROL(base) &= ~PORT_CONTROL_BPT; - } else - reg_PORT_CONTROL(base) |= PORT_CONTROL_BPT; - reg_MAC_CONFIG_2(base) = value; - - reg_RX_CONFIG(base) = RX_CONFIG_SE; - reg_RX_QUEUE_0_CONFIG(base) = OCN_PORT_MEMORY; - reg_RX_QUEUE_0_BUF_CONFIG(base) = OCN_PORT_MEMORY; - - /* initialize the RX DMA descriptors */ - rx_descr = &rx_descr_array[0]; - rx_descr_current = rx_descr; - for (index = 0; index < NUM_RX_DESC; index++) { - /* make sure the receive buffers are not in cache */ - invalidate_dcache_range((unsigned long)net_rx_packets[index], - (unsigned long)net_rx_packets[index] + - RX_BUFFER_SIZE); - rx_descr->start_addr0 = - cpu_to_le32((vuint32) net_rx_packets[index]); - rx_descr->start_addr1 = 0; - rx_descr->next_descr_addr0 = - cpu_to_le32((vuint32) (rx_descr + 1)); - rx_descr->next_descr_addr1 = 0; - rx_descr->vlan_byte_count = 0; - rx_descr->config_status = cpu_to_le32((RX_BUFFER_SIZE << 16) | - DMA_DESCR_RX_OWNER); - rx_descr++; - } - rx_descr--; - rx_descr->next_descr_addr0 = 0; - rx_descr->next_descr_addr1 = cpu_to_le32(DMA_DESCR_LAST); - /* Push the descriptors to RAM so the ethernet DMA can see them */ - invalidate_dcache_range((unsigned long)rx_descr_array, - (unsigned long)rx_descr_array + - sizeof(rx_descr_array)); - - /* enable RX queue */ - reg_RX_CONTROL(base) = TX_CONTROL_GO | 0x01; - reg_RX_QUEUE_0_PTR_LOW(base) = (u32) rx_descr_current; - /* enable receive DMA */ - reg_RX_QUEUE_0_PTR_HIGH(base) = RX_QUEUE_0_PTR_HIGH_VALID; - - reg_TX_QUEUE_0_CONFIG(base) = OCN_PORT_MEMORY; - reg_TX_QUEUE_0_BUF_CONFIG(base) = OCN_PORT_MEMORY; - - /* initialize the TX DMA descriptor */ - tx_descr = &tx_descriptor; - - tx_descr->start_addr0 = 0; - tx_descr->start_addr1 = 0; - tx_descr->next_descr_addr0 = 0; - tx_descr->next_descr_addr1 = cpu_to_le32(DMA_DESCR_LAST); - tx_descr->vlan_byte_count = 0; - tx_descr->config_status = cpu_to_le32(DMA_DESCR_TX_OK | - DMA_DESCR_TX_SOF | - DMA_DESCR_TX_EOF); - /* enable TX queue */ - reg_TX_CONTROL(base) = TX_CONTROL_GO | 0x01; - - return 0; -} - -/* - * send a packet - */ -static int tsi108_eth_send(struct eth_device *dev, void *packet, int length) -{ - unsigned long base; - int timeout; - struct dma_descriptor *tx_descr; - unsigned long status; - - base = dev->iobase; - tx_descr = &tx_descriptor; - - /* Wait until the last packet has been transmitted. */ - timeout = 0; - do { - /* make sure we see the changes made by the DMA engine */ - invalidate_dcache_range((unsigned long)tx_descr, - (unsigned long)tx_descr + - sizeof(struct dma_descriptor)); - - if (timeout != 0) - udelay (15); - if (++timeout > 10000) { - tx_diag_regs(base); - debug_lev(1, - "ERROR: timeout waiting for last transmit packet to be sent\n"); - return 0; - } - } while (tx_descr->config_status & cpu_to_le32(DMA_DESCR_TX_OWNER)); - - status = le32_to_cpu(tx_descr->config_status); - if ((status & DMA_DESCR_TX_OK) == 0) { -#ifdef TX_PRINT_ERRORS - printf ("TX packet error: 0x%08lx\n %s%s%s%s\n", status, - status & DMA_DESCR_TX_OK ? "tx error, " : "", - status & DMA_DESCR_TX_RETRY_LIMIT ? - "retry limit reached, " : "", - status & DMA_DESCR_TX_UNDERRUN ? "underrun, " : "", - status & DMA_DESCR_TX_LATE_COLLISION ? "late collision, " - : ""); -#endif - } - - debug_lev (9, "sending packet %d\n", length); - tx_descr->start_addr0 = cpu_to_le32((vuint32) packet); - tx_descr->start_addr1 = 0; - tx_descr->next_descr_addr0 = 0; - tx_descr->next_descr_addr1 = cpu_to_le32(DMA_DESCR_LAST); - tx_descr->vlan_byte_count = cpu_to_le32(length); - tx_descr->config_status = cpu_to_le32(DMA_DESCR_TX_OWNER | - DMA_DESCR_TX_CRC | - DMA_DESCR_TX_PAD | - DMA_DESCR_TX_SOF | - DMA_DESCR_TX_EOF); - - invalidate_dcache_range((unsigned long)tx_descr, - (unsigned long)tx_descr + - sizeof(struct dma_descriptor)); - - invalidate_dcache_range((unsigned long)packet, - (unsigned long)packet + length); - - reg_TX_QUEUE_0_PTR_LOW(base) = (u32) tx_descr; - reg_TX_QUEUE_0_PTR_HIGH(base) = TX_QUEUE_0_PTR_HIGH_VALID; - - return length; -} - -/* - * Check for received packets and send them up the protocal stack - */ -static int tsi108_eth_recv (struct eth_device *dev) -{ - struct dma_descriptor *rx_descr; - unsigned long base; - int length = 0; - unsigned long status; - uchar *buffer; - - base = dev->iobase; - - /* make sure we see the changes made by the DMA engine */ - invalidate_dcache_range ((unsigned long)rx_descr_array, - (unsigned long)rx_descr_array + - sizeof(rx_descr_array)); - - /* process all of the received packets */ - rx_descr = rx_descr_current; - while ((rx_descr->config_status & cpu_to_le32(DMA_DESCR_RX_OWNER)) == 0) { - /* check for error */ - status = le32_to_cpu(rx_descr->config_status); - if (status & DMA_DESCR_RX_BAD_FRAME) { -#ifdef RX_PRINT_ERRORS - printf ("RX packet error: 0x%08lx\n %s%s%s%s%s%s\n", - status, - status & DMA_DESCR_RX_FRAME_IS_TYPE ? "too big, " - : "", - status & DMA_DESCR_RX_SHORT_FRAME ? "too short, " - : "", - status & DMA_DESCR_RX_BAD_FRAME ? "bad frame, " : - "", - status & DMA_DESCR_RX_OVERRUN ? "overrun, " : "", - status & DMA_DESCR_RX_MAX_FRAME_LEN ? - "max length, " : "", - status & DMA_DESCR_RX_CRC_ERROR ? "CRC error, " : - ""); -#endif - } else { - length = - le32_to_cpu(rx_descr->vlan_byte_count) & 0xFFFF; - - /*** process packet ***/ - buffer = (uchar *)(le32_to_cpu(rx_descr->start_addr0)); - net_process_received_packet(buffer, length); - - invalidate_dcache_range ((unsigned long)buffer, - (unsigned long)buffer + - RX_BUFFER_SIZE); - } - /* Give this buffer back to the DMA engine */ - rx_descr->vlan_byte_count = 0; - rx_descr->config_status = cpu_to_le32 ((RX_BUFFER_SIZE << 16) | - DMA_DESCR_RX_OWNER); - /* move descriptor pointer forward */ - rx_descr = - (struct dma_descriptor - *)(le32_to_cpu (rx_descr->next_descr_addr0)); - if (rx_descr == 0) - rx_descr = &rx_descr_array[0]; - } - /* remember where we are for next time */ - rx_descr_current = rx_descr; - - /* If the DMA engine has reached the end of the queue - * start over at the begining */ - if (reg_RX_EXTENDED_STATUS(base) & RX_EXTENDED_STATUS_EOQ_0) { - - reg_RX_EXTENDED_STATUS(base) = RX_EXTENDED_STATUS_EOQ_0; - reg_RX_QUEUE_0_PTR_LOW(base) = (u32) & rx_descr_array[0]; - reg_RX_QUEUE_0_PTR_HIGH(base) = RX_QUEUE_0_PTR_HIGH_VALID; - } - - return length; -} - -/* - * disable an ethernet interface - */ -static void tsi108_eth_halt (struct eth_device *dev) -{ - unsigned long base; - - base = dev->iobase; - - /* Put DMA/FIFO into reset state. */ - reg_TX_CONFIG(base) = TX_CONFIG_RST; - reg_RX_CONFIG(base) = RX_CONFIG_RST; - - /* Put MAC into reset state. */ - reg_MAC_CONFIG_1(base) = MAC_CONFIG_1_SOFT_RESET; -} diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 49be1ebdd77..1cd1e409e3e 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -860,6 +860,13 @@ static int decode_regions(struct pci_controller *hose, ofnode parent_node, } else { continue; } + + if (!IS_ENABLED(CONFIG_SYS_PCI_64BIT) && + type == PCI_REGION_MEM && upper_32_bits(pci_addr)) { + debug(" - beyond the 32-bit boundary, ignoring\n"); + continue; + } + pos = -1; for (i = 0; i < hose->region_count; i++) { if (hose->regions[i].flags == type) diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index d1feb503a0a..d7237f6eee0 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -98,7 +98,8 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, } if (!enum_only && pciauto_region_allocate(bar_res, bar_size, - &bar_value) == 0) { + &bar_value, + found_mem64) == 0) { /* Write it out and update our limit */ dm_pci_write_config32(dev, bar, (u32)bar_value); @@ -140,7 +141,8 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, debug("PCI Autoconfig: ROM, size=%#x, ", (unsigned int)bar_size); if (pciauto_region_allocate(mem, bar_size, - &bar_value) == 0) { + &bar_value, + false) == 0) { dm_pci_write_config32(dev, rom_addr, bar_value); } diff --git a/drivers/pci/pci_auto_common.c b/drivers/pci/pci_auto_common.c index 1d202ae2ef0..183787333e9 100644 --- a/drivers/pci/pci_auto_common.c +++ b/drivers/pci/pci_auto_common.c @@ -32,12 +32,12 @@ void pciauto_region_align(struct pci_region *res, pci_size_t size) } int pciauto_region_allocate(struct pci_region *res, pci_size_t size, - pci_addr_t *bar) + pci_addr_t *bar, bool supports_64bit) { pci_addr_t addr; if (!res) { - debug("No resource"); + debug("No resource\n"); goto error; } @@ -48,9 +48,14 @@ int pciauto_region_allocate(struct pci_region *res, pci_size_t size, goto error; } + if (upper_32_bits(addr) && !supports_64bit) { + debug("Cannot assign 64-bit address to 32-bit-only resource\n"); + goto error; + } + res->bus_lower = addr + size; - debug("address=0x%llx bus_lower=0x%llx", (unsigned long long)addr, + debug("address=0x%llx bus_lower=0x%llx\n", (unsigned long long)addr, (unsigned long long)res->bus_lower); *bar = addr; diff --git a/drivers/pci/pci_auto_old.c b/drivers/pci/pci_auto_old.c index bc119fba872..e705a3072e7 100644 --- a/drivers/pci/pci_auto_old.c +++ b/drivers/pci/pci_auto_old.c @@ -108,7 +108,8 @@ void pciauto_setup_device(struct pci_controller *hose, } #ifndef CONFIG_PCI_ENUM_ONLY - if (pciauto_region_allocate(bar_res, bar_size, &bar_value) == 0) { + if (pciauto_region_allocate(bar_res, bar_size, + &bar_value, found_mem64) == 0) { /* Write it out and update our limit */ pci_hose_write_config_dword(hose, dev, bar, (u32)bar_value); @@ -150,7 +151,7 @@ void pciauto_setup_device(struct pci_controller *hose, debug("PCI Autoconfig: ROM, size=%#x, ", (unsigned int)bar_size); if (pciauto_region_allocate(mem, bar_size, - &bar_value) == 0) { + &bar_value, false) == 0) { pci_hose_write_config_dword(hose, dev, rom_addr, bar_value); } diff --git a/drivers/ram/stm32_sdram.c b/drivers/ram/stm32_sdram.c index dc39f33d16a..f6cac8eb90b 100644 --- a/drivers/ram/stm32_sdram.c +++ b/drivers/ram/stm32_sdram.c @@ -11,6 +11,8 @@ #include <asm/io.h> #define MEM_MODE_MASK GENMASK(2, 0) +#define SWP_FMC_OFFSET 10 +#define SWP_FMC_MASK GENMASK(SWP_FMC_OFFSET+1, SWP_FMC_OFFSET) #define NOT_FOUND 0xff struct stm32_fmc_regs { @@ -256,27 +258,36 @@ static int stm32_fmc_ofdata_to_platdata(struct udevice *dev) struct ofnode_phandle_args args; u32 *syscfg_base; u32 mem_remap; + u32 swp_fmc; ofnode bank_node; char *bank_name; u8 bank = 0; int ret; - mem_remap = dev_read_u32_default(dev, "st,mem_remap", NOT_FOUND); - if (mem_remap != NOT_FOUND) { - ret = dev_read_phandle_with_args(dev, "st,syscfg", NULL, 0, 0, + ret = dev_read_phandle_with_args(dev, "st,syscfg", NULL, 0, 0, &args); - if (ret) { - debug("%s: can't find syscon device (%d)\n", __func__, - ret); - return ret; - } - + if (ret) { + dev_dbg(dev, "%s: can't find syscon device (%d)\n", __func__, ret); + } else { syscfg_base = (u32 *)ofnode_get_addr(args.node); - /* set memory mapping selection */ - clrsetbits_le32(syscfg_base, MEM_MODE_MASK, mem_remap); - } else { - debug("%s: cannot find st,mem_remap property\n", __func__); + mem_remap = dev_read_u32_default(dev, "st,mem_remap", NOT_FOUND); + if (mem_remap != NOT_FOUND) { + /* set memory mapping selection */ + clrsetbits_le32(syscfg_base, MEM_MODE_MASK, mem_remap); + } else { + dev_dbg(dev, "%s: cannot find st,mem_remap property\n", __func__); + } + + swp_fmc = dev_read_u32_default(dev, "st,swp_fmc", NOT_FOUND); + if (swp_fmc != NOT_FOUND) { + /* set fmc swapping selection */ + clrsetbits_le32(syscfg_base, SWP_FMC_MASK, swp_fmc << SWP_FMC_OFFSET); + } else { + dev_dbg(dev, "%s: cannot find st,swp_fmc property\n", __func__); + } + + dev_dbg(dev, "syscfg %x = %x\n", (u32)syscfg_base, *syscfg_base); } dev_for_each_subnode(bank_node, dev) { diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 5937910e5bf..2940bd05dc3 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -197,6 +197,15 @@ config DEBUG_UART_AR933X driver will be available until the real driver model serial is running. +config DEBUG_ARC_SERIAL + bool "ARC UART" + depends on ARC_SERIAL + help + Select this to enable a debug UART using the ARC UART driver. + You will need to provide parameters to make this work. The + driver will be available until the real driver model serial is + running. + config DEBUG_UART_ATMEL bool "Atmel USART" help @@ -315,6 +324,15 @@ config DEBUG_UART_MXC will need to provide parameters to make this work. The driver will be available until the real driver model serial is running. +config DEBUG_UART_STM32 + bool "STMicroelectronics STM32" + depends on STM32_SERIAL + help + Select this to enable a debug UART using the serial_stm32 driver + You will need to provide parameters to make this work. + The driver will be available until the real driver model + serial is running. + config DEBUG_UART_UNIPHIER bool "UniPhier on-chip UART" depends on ARCH_UNIPHIER @@ -425,6 +443,13 @@ config AR933X_UART tree binding to operate, please refer to the document at doc/device-tree-bindings/serial/qca,ar9330-uart.txt. +config ARC_SERIAL + bool "ARC UART support" + depends on DM_SERIAL + help + Select this to enable support for ARC UART now typically + only used in Synopsys DesignWare ARC simulators like nSIM. + config ATMEL_USART bool "Atmel USART support" help diff --git a/drivers/serial/serial_arc.c b/drivers/serial/serial_arc.c index da4a07ab2f6..925f0c25554 100644 --- a/drivers/serial/serial_arc.c +++ b/drivers/serial/serial_arc.c @@ -130,3 +130,29 @@ U_BOOT_DRIVER(serial_arc) = { .ops = &arc_serial_ops, .flags = DM_FLAG_PRE_RELOC, }; + +#ifdef CONFIG_DEBUG_ARC_SERIAL +#include <debug_uart.h> + +static inline void _debug_uart_init(void) +{ + struct arc_serial_regs *regs = (struct arc_serial_regs *)CONFIG_DEBUG_UART_BASE; + int arc_console_baud = CONFIG_DEBUG_UART_CLOCK / (CONFIG_BAUDRATE * 4) - 1; + + writeb(arc_console_baud & 0xff, ®s->baudl); + writeb((arc_console_baud & 0xff00) >> 8, ®s->baudh); +} + +static inline void _debug_uart_putc(int c) +{ + struct arc_serial_regs *regs = (struct arc_serial_regs *)CONFIG_DEBUG_UART_BASE; + + while (!(readb(®s->status) & UART_TXEMPTY)) + ; + + writeb(c, ®s->data); +} + +DEBUG_UART_FUNCS + +#endif diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c index 119e6b9846d..c462394dbdc 100644 --- a/drivers/serial/serial_msm.c +++ b/drivers/serial/serial_msm.c @@ -16,6 +16,7 @@ #include <watchdog.h> #include <asm/io.h> #include <linux/compiler.h> +#include <dm/pinctrl.h> /* Serial registers - this driver works in uartdm mode*/ @@ -25,6 +26,9 @@ #define UARTDM_RXFS 0x50 /* RX channel status register */ #define UARTDM_RXFS_BUF_SHIFT 0x7 /* Number of bytes in the packing buffer */ #define UARTDM_RXFS_BUF_MASK 0x7 +#define UARTDM_MR1 0x00 +#define UARTDM_MR2 0x04 +#define UARTDM_CSR 0xA0 #define UARTDM_SR 0xA4 /* Status register */ #define UARTDM_SR_RX_READY (1 << 0) /* Word is the receiver FIFO */ @@ -45,6 +49,10 @@ #define UARTDM_TF 0x100 /* UART Transmit FIFO register */ #define UARTDM_RF 0x140 /* UART Receive FIFO register */ +#define UART_DM_CLK_RX_TX_BIT_RATE 0xCC +#define MSM_BOOT_UART_DM_8_N_1_MODE 0x34 +#define MSM_BOOT_UART_DM_CMD_RESET_RX 0x10 +#define MSM_BOOT_UART_DM_CMD_RESET_TX 0x20 DECLARE_GLOBAL_DATA_PTR; @@ -179,19 +187,29 @@ static int msm_uart_clk_init(struct udevice *dev) return 0; } +static void uart_dm_init(struct msm_serial_data *priv) +{ + writel(UART_DM_CLK_RX_TX_BIT_RATE, priv->base + UARTDM_CSR); + writel(0x0, priv->base + UARTDM_MR1); + writel(MSM_BOOT_UART_DM_8_N_1_MODE, priv->base + UARTDM_MR2); + writel(MSM_BOOT_UART_DM_CMD_RESET_RX, priv->base + UARTDM_CR); + writel(MSM_BOOT_UART_DM_CMD_RESET_TX, priv->base + UARTDM_CR); +} static int msm_serial_probe(struct udevice *dev) { + int ret; struct msm_serial_data *priv = dev_get_priv(dev); - msm_uart_clk_init(dev); /* Ignore return value and hope clock was - properly initialized by earlier loaders */ + /* No need to reinitialize the UART after relocation */ + if (gd->flags & GD_FLG_RELOC) + return 0; - if (readl(priv->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN) - writel(UARTDM_CR_CMD_RESET_ERR, priv->base + UARTDM_CR); + ret = msm_uart_clk_init(dev); + if (ret) + return ret; - writel(0, priv->base + UARTDM_IMR); - writel(UARTDM_CR_CMD_STALE_EVENT_DISABLE, priv->base + UARTDM_CR); - msm_serial_fetch(dev); + pinctrl_select_state(dev, "uart"); + uart_dm_init(priv); return 0; } diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index 6717ffaaa5b..f26234549c3 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -7,19 +7,21 @@ #include <common.h> #include <clk.h> #include <dm.h> -#include <asm/io.h> #include <serial.h> +#include <watchdog.h> +#include <asm/io.h> #include <asm/arch/stm32.h> #include "serial_stm32.h" -static int stm32_serial_setbrg(struct udevice *dev, int baudrate) +static void _stm32_serial_setbrg(fdt_addr_t base, + struct stm32_uart_info *uart_info, + u32 clock_rate, + int baudrate) { - struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); - bool stm32f4 = plat->uart_info->stm32f4; - fdt_addr_t base = plat->base; + bool stm32f4 = uart_info->stm32f4; u32 int_div, mantissa, fraction, oversampling; - int_div = DIV_ROUND_CLOSEST(plat->clock_rate, baudrate); + int_div = DIV_ROUND_CLOSEST(clock_rate, baudrate); if (int_div < 16) { oversampling = 8; @@ -33,6 +35,53 @@ static int stm32_serial_setbrg(struct udevice *dev, int baudrate) fraction = int_div % oversampling; writel(mantissa | fraction, base + BRR_OFFSET(stm32f4)); +} + +static int stm32_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + + _stm32_serial_setbrg(plat->base, plat->uart_info, + plat->clock_rate, baudrate); + + return 0; +} + +static int stm32_serial_setparity(struct udevice *dev, enum serial_par parity) +{ + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + bool stm32f4 = plat->uart_info->stm32f4; + u8 uart_enable_bit = plat->uart_info->uart_enable_bit; + u32 cr1 = plat->base + CR1_OFFSET(stm32f4); + u32 config = 0; + + if (stm32f4) + return -EINVAL; /* not supported in driver*/ + + clrbits_le32(cr1, USART_CR1_RE | USART_CR1_TE | BIT(uart_enable_bit)); + /* update usart configuration (uart need to be disable) + * PCE: parity check control + * PS : '0' : Even / '1' : Odd + * M[1:0] = '00' : 8 Data bits + * M[1:0] = '01' : 9 Data bits with parity + */ + switch (parity) { + default: + case SERIAL_PAR_NONE: + config = 0; + break; + case SERIAL_PAR_ODD: + config = USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0; + break; + case SERIAL_PAR_EVEN: + config = USART_CR1_PCE | USART_CR1_M0; + break; + } + clrsetbits_le32(cr1, + USART_CR1_PCE | USART_CR1_PS | USART_CR1_M1 | + USART_CR1_M0, + config); + setbits_le32(cr1, USART_CR1_RE | USART_CR1_TE | BIT(uart_enable_bit)); return 0; } @@ -44,12 +93,13 @@ static int stm32_serial_getc(struct udevice *dev) fdt_addr_t base = plat->base; u32 isr = readl(base + ISR_OFFSET(stm32f4)); - if ((isr & USART_ISR_FLAG_RXNE) == 0) + if ((isr & USART_ISR_RXNE) == 0) return -EAGAIN; - if (isr & USART_ISR_FLAG_ORE) { + if (isr & (USART_ISR_PE | USART_ISR_ORE)) { if (!stm32f4) - setbits_le32(base + ICR_OFFSET, USART_ICR_OREF); + setbits_le32(base + ICR_OFFSET, + USART_ICR_PCECF | USART_ICR_ORECF); else readl(base + RDR_OFFSET(stm32f4)); return -EIO; @@ -58,13 +108,13 @@ static int stm32_serial_getc(struct udevice *dev) return readl(base + RDR_OFFSET(stm32f4)); } -static int stm32_serial_putc(struct udevice *dev, const char c) +static int _stm32_serial_putc(fdt_addr_t base, + struct stm32_uart_info *uart_info, + const char c) { - struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); - bool stm32f4 = plat->uart_info->stm32f4; - fdt_addr_t base = plat->base; + bool stm32f4 = uart_info->stm32f4; - if ((readl(base + ISR_OFFSET(stm32f4)) & USART_ISR_FLAG_TXE) == 0) + if ((readl(base + ISR_OFFSET(stm32f4)) & USART_ISR_TXE) == 0) return -EAGAIN; writel(c, base + TDR_OFFSET(stm32f4)); @@ -72,6 +122,13 @@ static int stm32_serial_putc(struct udevice *dev, const char c) return 0; } +static int stm32_serial_putc(struct udevice *dev, const char c) +{ + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + + return _stm32_serial_putc(plat->base, plat->uart_info, c); +} + static int stm32_serial_pending(struct udevice *dev, bool input) { struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); @@ -80,24 +137,34 @@ static int stm32_serial_pending(struct udevice *dev, bool input) if (input) return readl(base + ISR_OFFSET(stm32f4)) & - USART_ISR_FLAG_RXNE ? 1 : 0; + USART_ISR_RXNE ? 1 : 0; else return readl(base + ISR_OFFSET(stm32f4)) & - USART_ISR_FLAG_TXE ? 0 : 1; + USART_ISR_TXE ? 0 : 1; +} + +static void _stm32_serial_init(fdt_addr_t base, + struct stm32_uart_info *uart_info) +{ + bool stm32f4 = uart_info->stm32f4; + u8 uart_enable_bit = uart_info->uart_enable_bit; + + /* Disable uart-> enable fifo -> enable uart */ + clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE | + BIT(uart_enable_bit)); + if (uart_info->has_fifo) + setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_FIFOEN); + setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE | + BIT(uart_enable_bit)); } static int stm32_serial_probe(struct udevice *dev) { struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); struct clk clk; - fdt_addr_t base = plat->base; int ret; - bool stm32f4; - u8 uart_enable_bit; plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev); - stm32f4 = plat->uart_info->stm32f4; - uart_enable_bit = plat->uart_info->uart_enable_bit; ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) @@ -115,13 +182,7 @@ static int stm32_serial_probe(struct udevice *dev) return plat->clock_rate; }; - /* Disable uart-> enable fifo-> enable uart */ - clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE | - BIT(uart_enable_bit)); - if (plat->uart_info->has_fifo) - setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_FIFOEN); - setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE | - BIT(uart_enable_bit)); + _stm32_serial_init(plat->base, plat->uart_info); return 0; } @@ -149,6 +210,7 @@ static const struct dm_serial_ops stm32_serial_ops = { .pending = stm32_serial_pending, .getc = stm32_serial_getc, .setbrg = stm32_serial_setbrg, + .setparity = stm32_serial_setparity }; U_BOOT_DRIVER(serial_stm32) = { @@ -161,3 +223,43 @@ U_BOOT_DRIVER(serial_stm32) = { .probe = stm32_serial_probe, .flags = DM_FLAG_PRE_RELOC, }; + +#ifdef CONFIG_DEBUG_UART_STM32 +#include <debug_uart.h> +static inline struct stm32_uart_info *_debug_uart_info(void) +{ + struct stm32_uart_info *uart_info; + +#if defined(CONFIG_STM32F4) + uart_info = &stm32f4_info; +#elif defined(CONFIG_STM32F7) + uart_info = &stm32f7_info; +#else + uart_info = &stm32h7_info; +#endif + return uart_info; +} + +static inline void _debug_uart_init(void) +{ + fdt_addr_t base = CONFIG_DEBUG_UART_BASE; + struct stm32_uart_info *uart_info = _debug_uart_info(); + + _stm32_serial_init(base, uart_info); + _stm32_serial_setbrg(base, uart_info, + CONFIG_DEBUG_UART_CLOCK, + CONFIG_BAUDRATE); + printf("DEBUG done\n"); +} + +static inline void _debug_uart_putc(int c) +{ + fdt_addr_t base = CONFIG_DEBUG_UART_BASE; + struct stm32_uart_info *uart_info = _debug_uart_info(); + + while (_stm32_serial_putc(base, uart_info, c) == -EAGAIN) + WATCHDOG_RESET(); +} + +DEBUG_UART_FUNCS +#endif diff --git a/drivers/serial/serial_stm32.h b/drivers/serial/serial_stm32.h index 8a1a24fda8f..ccafa31219a 100644 --- a/drivers/serial/serial_stm32.h +++ b/drivers/serial/serial_stm32.h @@ -13,6 +13,7 @@ #define ISR_OFFSET(x) (x ? 0x00 : 0x1c) #define ICR_OFFSET 0x20 + /* * STM32F4 has one Data Register (DR) for received or transmitted * data, so map Receive Data Register (RDR) and Transmit Data @@ -53,19 +54,26 @@ struct stm32x7_serial_platdata { }; #define USART_CR1_FIFOEN BIT(29) +#define USART_CR1_M1 BIT(28) #define USART_CR1_OVER8 BIT(15) +#define USART_CR1_M0 BIT(12) +#define USART_CR1_PCE BIT(10) +#define USART_CR1_PS BIT(9) #define USART_CR1_TE BIT(3) #define USART_CR1_RE BIT(2) #define USART_CR3_OVRDIS BIT(12) -#define USART_ISR_FLAG_ORE BIT(3) -#define USART_ISR_FLAG_RXNE BIT(5) -#define USART_ISR_FLAG_TXE BIT(7) +#define USART_ISR_TXE BIT(7) +#define USART_ISR_RXNE BIT(5) +#define USART_ISR_ORE BIT(3) +#define USART_ISR_PE BIT(0) #define USART_BRR_F_MASK GENMASK(7, 0) #define USART_BRR_M_SHIFT 4 #define USART_BRR_M_MASK GENMASK(15, 4) -#define USART_ICR_OREF BIT(3) +#define USART_ICR_ORECF BIT(3) +#define USART_ICR_PCECF BIT(0) + #endif diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig index 2a64bc49c3f..93264ddd343 100644 --- a/drivers/tpm/Kconfig +++ b/drivers/tpm/Kconfig @@ -4,18 +4,31 @@ menu "TPM support" +comment "Please select only one TPM revision" + depends on TPM_V1 && TPM_V2 + +config TPM_V1 + bool "TPMv1.x support" + depends on TPM + default y + help + Major TPM versions are not compatible at all, choose either + one or the other. This option enables TPMv1.x drivers/commands. + +if TPM_V1 && !TPM_V2 + config TPM_TIS_SANDBOX bool "Enable sandbox TPM driver" - depends on SANDBOX + depends on TPM_V1 && SANDBOX help - This driver emulates a TPM, providing access to base functions + This driver emulates a TPMv1.x, providing access to base functions such as reading and writing TPM private data. This is enough to support Chrome OS verified boot. Extend functionality is not implemented. config TPM_ATMEL_TWI bool "Enable Atmel TWI TPM device driver" - depends on TPM + depends on TPM_V1 help This driver supports an Atmel TPM device connected on the I2C bus. The usual tpm operations and the 'tpm' command can be used to talk @@ -24,7 +37,7 @@ config TPM_ATMEL_TWI config TPM_TIS_INFINEON bool "Enable support for Infineon SLB9635/45 TPMs on I2C" - depends on TPM && DM_I2C + depends on TPM_V1 && DM_I2C help This driver supports Infineon TPM devices connected on the I2C bus. The usual tpm operations and the 'tpm' command can be used to talk @@ -48,7 +61,8 @@ config TPM_TIS_I2C_BURST_LIMITATION_LEN config TPM_TIS_LPC bool "Enable support for Infineon SLB9635/45 TPMs on LPC" - depends on TPM && X86 + depends on TPM_V1 && X86 + select TPM_DRIVER_SELECTED help This driver supports Infineon TPM devices connected on the LPC bus. The usual tpm operations and the 'tpm' command can be used to talk @@ -57,7 +71,7 @@ config TPM_TIS_LPC config TPM_AUTH_SESSIONS bool "Enable TPM authentication session support" - depends on TPM + depends on TPM_V1 help Enable support for authorised (AUTH1) commands as specified in the TCG Main Specification 1.2. OIAP-authorised versions of the commands @@ -66,7 +80,7 @@ config TPM_AUTH_SESSIONS config TPM_ST33ZP24_I2C bool "STMicroelectronics ST33ZP24 I2C TPM" - depends on TPM && DM_I2C + depends on TPM_V1 && DM_I2C ---help--- This driver supports STMicroelectronics TPM devices connected on the I2C bus. The usual tpm operations and the 'tpm' command can be used to talk @@ -75,7 +89,7 @@ config TPM_ST33ZP24_I2C config TPM_ST33ZP24_SPI bool "STMicroelectronics ST33ZP24 SPI TPM" - depends on TPM && DM_SPI + depends on TPM_V1 && DM_SPI ---help--- This driver supports STMicroelectronics TPM devices connected on the SPI bus. The usual tpm operations and the 'tpm' command can be used to talk @@ -84,14 +98,14 @@ config TPM_ST33ZP24_SPI config TPM_FLUSH_RESOURCES bool "Enable TPM resource flushing support" - depends on TPM + depends on TPM_V1 help Enable support to flush specific resources (e.g. keys) from the TPM. The functionality is available via the 'tpm' command as well. config TPM_LOAD_KEY_BY_SHA1 bool "Enable TPM key loading by SHA1 support" - depends on TPM + depends on TPM_V1 help Enable support to load keys into the TPM by identifying their parent via the public key's SHA1 hash. @@ -99,8 +113,41 @@ config TPM_LOAD_KEY_BY_SHA1 config TPM_LIST_RESOURCES bool "Enable TPM resource listing support" - depends on TPM + depends on TPM_V1 help Enable support to list specific resources (e.g. keys) within the TPM. The functionality is available via the 'tpm' command as well. + +endif # TPM_V1 + +config TPM_V2 + bool "TPMv2.x support" + depends on TPM + help + Major TPM versions are not compatible at all, choose either + one or the other. This option enables TPMv2.x drivers/commands. + +if TPM_V2 && !TPM_V1 + +config TPM2_TIS_SANDBOX + bool "Enable sandbox TPMv2.x driver" + depends on TPM_V2 && SANDBOX + select TPM_DRIVER_SELECTED + help + This driver emulates a TPMv2.x, providing access to base functions + such as basic configuration, PCR extension and PCR read. Extended + functionalities are not implemented. + +config TPM2_TIS_SPI + bool "Enable support for TPMv2.x SPI chips" + depends on TPM_V2 && DM_SPI + select TPM_DRIVER_SELECTED + help + This driver supports TPMv2.x devices connected on the SPI bus. + The usual TPM operations and the 'tpm' command can be used to talk + to the device using the standard TPM Interface Specification (TIS) + protocol. + +endif # TPM_V2 + endmenu diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index e5fc86ff953..af473ef662e 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -9,3 +9,6 @@ obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o obj-$(CONFIG_TPM_ST33ZP24_I2C) += tpm_tis_st33zp24_i2c.o obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o + +obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o +obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_spi.o diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c index e71545235cf..412697eedc4 100644 --- a/drivers/tpm/tpm-uclass.c +++ b/drivers/tpm/tpm-uclass.c @@ -6,8 +6,12 @@ #include <common.h> #include <dm.h> -#include <tpm.h> #include <linux/unaligned/be_byteshift.h> +#if defined(CONFIG_TPM_V1) +#include <tpm-v1.h> +#elif defined(CONFIG_TPM_V2) +#include <tpm-v2.h> +#endif #include "tpm_internal.h" int tpm_open(struct udevice *dev) diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c new file mode 100644 index 00000000000..3240cc5dbab --- /dev/null +++ b/drivers/tpm/tpm2_tis_sandbox.c @@ -0,0 +1,625 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2018, Bootlin + * Author: Miquel Raynal <miquel.raynal@bootlin.com> + */ + +#include <common.h> +#include <dm.h> +#include <tpm-v2.h> +#include <asm/state.h> +#include <asm/unaligned.h> +#include <linux/crc8.h> + +/* Hierarchies */ +enum tpm2_hierarchy { + TPM2_HIERARCHY_LOCKOUT = 0, + TPM2_HIERARCHY_ENDORSEMENT, + TPM2_HIERARCHY_PLATFORM, + TPM2_HIERARCHY_NB, +}; + +/* Subset of supported capabilities */ +enum tpm2_capability { + TPM_CAP_TPM_PROPERTIES = 0x6, +}; + +/* Subset of supported properties */ +#define TPM2_PROPERTIES_OFFSET 0x0000020E + +enum tpm2_cap_tpm_property { + TPM2_FAIL_COUNTER = 0, + TPM2_PROP_MAX_TRIES, + TPM2_RECOVERY_TIME, + TPM2_LOCKOUT_RECOVERY, + TPM2_PROPERTY_NB, +}; + +#define SANDBOX_TPM_PCR_NB 1 + +static const u8 sandbox_extended_once_pcr[] = { + 0xf5, 0xa5, 0xfd, 0x42, 0xd1, 0x6a, 0x20, 0x30, + 0x27, 0x98, 0xef, 0x6e, 0xd3, 0x09, 0x97, 0x9b, + 0x43, 0x00, 0x3d, 0x23, 0x20, 0xd9, 0xf0, 0xe8, + 0xea, 0x98, 0x31, 0xa9, 0x27, 0x59, 0xfb, 0x4b, +}; + +struct sandbox_tpm2 { + /* TPM internal states */ + bool init_done; + bool startup_done; + bool tests_done; + /* TPM password per hierarchy */ + char pw[TPM2_HIERARCHY_NB][TPM2_DIGEST_LEN + 1]; + int pw_sz[TPM2_HIERARCHY_NB]; + /* TPM properties */ + u32 properties[TPM2_PROPERTY_NB]; + /* TPM PCRs */ + u8 pcr[SANDBOX_TPM_PCR_NB][TPM2_DIGEST_LEN]; + /* TPM PCR extensions */ + u32 pcr_extensions[SANDBOX_TPM_PCR_NB]; +}; + +/* + * Check the tag validity depending on the command (authentication required or + * not). If authentication is required, check it is valid. Update the auth + * pointer to point to the next chunk of data to process if needed. + */ +static int sandbox_tpm2_check_session(struct udevice *dev, u32 command, u16 tag, + const u8 **auth, + enum tpm2_hierarchy *hierarchy) +{ + struct sandbox_tpm2 *tpm = dev_get_priv(dev); + u32 handle, auth_sz, session_handle; + u16 nonce_sz, pw_sz; + const char *pw; + + switch (command) { + case TPM2_CC_STARTUP: + case TPM2_CC_SELF_TEST: + case TPM2_CC_GET_CAPABILITY: + case TPM2_CC_PCR_READ: + if (tag != TPM2_ST_NO_SESSIONS) { + printf("No session required for command 0x%x\n", + command); + return TPM2_RC_BAD_TAG; + } + + return 0; + + case TPM2_CC_CLEAR: + case TPM2_CC_HIERCHANGEAUTH: + case TPM2_CC_DAM_RESET: + case TPM2_CC_DAM_PARAMETERS: + case TPM2_CC_PCR_EXTEND: + if (tag != TPM2_ST_SESSIONS) { + printf("Session required for command 0x%x\n", command); + return TPM2_RC_AUTH_CONTEXT; + } + + handle = get_unaligned_be32(*auth); + *auth += sizeof(handle); + + /* + * PCR_Extend had a different protection mechanism and does not + * use the same standards as other commands. + */ + if (command == TPM2_CC_PCR_EXTEND) + break; + + switch (handle) { + case TPM2_RH_LOCKOUT: + *hierarchy = TPM2_HIERARCHY_LOCKOUT; + break; + case TPM2_RH_ENDORSEMENT: + if (command == TPM2_CC_CLEAR) { + printf("Endorsement hierarchy unsupported\n"); + return TPM2_RC_AUTH_MISSING; + } + *hierarchy = TPM2_HIERARCHY_ENDORSEMENT; + break; + case TPM2_RH_PLATFORM: + *hierarchy = TPM2_HIERARCHY_PLATFORM; + break; + default: + printf("Wrong handle 0x%x\n", handle); + return TPM2_RC_VALUE; + } + + break; + + default: + printf("Command code not recognized: 0x%x\n", command); + return TPM2_RC_COMMAND_CODE; + } + + auth_sz = get_unaligned_be32(*auth); + *auth += sizeof(auth_sz); + + session_handle = get_unaligned_be32(*auth); + *auth += sizeof(session_handle); + if (session_handle != TPM2_RS_PW) { + printf("Wrong session handle 0x%x\n", session_handle); + return TPM2_RC_VALUE; + } + + nonce_sz = get_unaligned_be16(*auth); + *auth += sizeof(nonce_sz); + if (nonce_sz) { + printf("Nonces not supported in Sandbox, aborting\n"); + return TPM2_RC_HANDLE; + } + + /* Ignore attributes */ + *auth += sizeof(u8); + + pw_sz = get_unaligned_be16(*auth); + *auth += sizeof(pw_sz); + if (auth_sz != (9 + nonce_sz + pw_sz)) { + printf("Authentication size (%d) do not match %d\n", + auth_sz, 9 + nonce_sz + pw_sz); + return TPM2_RC_SIZE; + } + + /* No passwork is acceptable */ + if (!pw_sz && !tpm->pw_sz[*hierarchy]) + return TPM2_RC_SUCCESS; + + /* Password is too long */ + if (pw_sz > TPM2_DIGEST_LEN) { + printf("Password should not be more than %dB\n", + TPM2_DIGEST_LEN); + return TPM2_RC_AUTHSIZE; + } + + pw = (const char *)*auth; + *auth += pw_sz; + + /* Password is wrong */ + if (pw_sz != tpm->pw_sz[*hierarchy] || + strncmp(pw, tpm->pw[*hierarchy], tpm->pw_sz[*hierarchy])) { + printf("Authentication failed: wrong password.\n"); + return TPM2_RC_BAD_AUTH; + } + + return TPM2_RC_SUCCESS; +} + +static int sandbox_tpm2_check_readyness(struct udevice *dev, int command) +{ + struct sandbox_tpm2 *tpm = dev_get_priv(dev); + + switch (command) { + case TPM2_CC_STARTUP: + if (!tpm->init_done || tpm->startup_done) + return TPM2_RC_INITIALIZE; + + break; + case TPM2_CC_GET_CAPABILITY: + if (!tpm->init_done || !tpm->startup_done) + return TPM2_RC_INITIALIZE; + + break; + case TPM2_CC_SELF_TEST: + if (!tpm->startup_done) + return TPM2_RC_INITIALIZE; + + break; + default: + if (!tpm->tests_done) + return TPM2_RC_NEEDS_TEST; + + break; + } + + return 0; +} + +static int sandbox_tpm2_fill_buf(u8 **recv, size_t *recv_len, u16 tag, u32 rc) +{ + *recv_len = sizeof(tag) + sizeof(u32) + sizeof(rc); + + /* Write tag */ + put_unaligned_be16(tag, *recv); + *recv += sizeof(tag); + + /* Write length */ + put_unaligned_be32(*recv_len, *recv); + *recv += sizeof(u32); + + /* Write return code */ + put_unaligned_be32(rc, *recv); + *recv += sizeof(rc); + + /* Add trailing \0 */ + *recv = '\0'; + + return 0; +} + +static int sandbox_tpm2_extend(struct udevice *dev, int pcr_index, + const u8 *extension) +{ + struct sandbox_tpm2 *tpm = dev_get_priv(dev); + int i; + + /* Only simulate the first extensions from all '0' with only '0' */ + for (i = 0; i < TPM2_DIGEST_LEN; i++) + if (tpm->pcr[pcr_index][i] || extension[i]) + return TPM2_RC_FAILURE; + + memcpy(tpm->pcr[pcr_index], sandbox_extended_once_pcr, + TPM2_DIGEST_LEN); + tpm->pcr_extensions[pcr_index]++; + + return 0; +}; + +static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf, + size_t send_size, u8 *recvbuf, + size_t *recv_len) +{ + struct sandbox_tpm2 *tpm = dev_get_priv(dev); + enum tpm2_hierarchy hierarchy = 0; + const u8 *sent = sendbuf; + u8 *recv = recvbuf; + u32 length, command, rc = 0; + u16 tag, mode, new_pw_sz; + u8 yes_no; + int i, j; + + /* TPM2_GetProperty */ + u32 capability, property, property_count; + + /* TPM2_PCR_Read/Extend variables */ + int pcr_index; + u64 pcr_map = 0; + u32 selections, pcr_nb; + u16 alg; + u8 pcr_array_sz; + + tag = get_unaligned_be16(sent); + sent += sizeof(tag); + + length = get_unaligned_be32(sent); + sent += sizeof(length); + if (length != send_size) { + printf("TPM2: Unmatching length, received: %ld, expected: %d\n", + send_size, length); + rc = TPM2_RC_SIZE; + sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + return 0; + } + + command = get_unaligned_be32(sent); + sent += sizeof(command); + rc = sandbox_tpm2_check_readyness(dev, command); + if (rc) { + sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + return 0; + } + + rc = sandbox_tpm2_check_session(dev, command, tag, &sent, &hierarchy); + if (rc) { + sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + return 0; + } + + switch (command) { + case TPM2_CC_STARTUP: + mode = get_unaligned_be16(sent); + sent += sizeof(mode); + switch (mode) { + case TPM2_SU_CLEAR: + case TPM2_SU_STATE: + break; + default: + rc = TPM2_RC_VALUE; + } + + tpm->startup_done = true; + + sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + break; + + case TPM2_CC_SELF_TEST: + yes_no = *sent; + sent += sizeof(yes_no); + switch (yes_no) { + case TPMI_YES: + case TPMI_NO: + break; + default: + rc = TPM2_RC_VALUE; + } + + tpm->tests_done = true; + + sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + break; + + case TPM2_CC_CLEAR: + /* Reset this hierarchy password */ + tpm->pw_sz[hierarchy] = 0; + + /* Reset all password if thisis the PLATFORM hierarchy */ + if (hierarchy == TPM2_HIERARCHY_PLATFORM) + for (i = 0; i < TPM2_HIERARCHY_NB; i++) + tpm->pw_sz[i] = 0; + + /* Reset the properties */ + for (i = 0; i < TPM2_PROPERTY_NB; i++) + tpm->properties[i] = 0; + + /* Reset the PCRs and their number of extensions */ + for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) { + tpm->pcr_extensions[i] = 0; + for (j = 0; j < TPM2_DIGEST_LEN; j++) + tpm->pcr[i][j] = 0; + } + + sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + break; + + case TPM2_CC_HIERCHANGEAUTH: + new_pw_sz = get_unaligned_be16(sent); + sent += sizeof(new_pw_sz); + if (new_pw_sz > TPM2_DIGEST_LEN) { + rc = TPM2_RC_SIZE; + } else if (new_pw_sz) { + tpm->pw_sz[hierarchy] = new_pw_sz; + memcpy(tpm->pw[hierarchy], sent, new_pw_sz); + sent += new_pw_sz; + } + + sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + break; + + case TPM2_CC_GET_CAPABILITY: + capability = get_unaligned_be32(sent); + sent += sizeof(capability); + if (capability != TPM_CAP_TPM_PROPERTIES) { + printf("Sandbox TPM only support TPM_CAPABILITIES\n"); + return TPM2_RC_HANDLE; + } + + property = get_unaligned_be32(sent); + sent += sizeof(property); + property -= TPM2_PROPERTIES_OFFSET; + + property_count = get_unaligned_be32(sent); + sent += sizeof(property_count); + if (!property_count || + property + property_count > TPM2_PROPERTY_NB) { + rc = TPM2_RC_HANDLE; + return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + } + + /* Write tag */ + put_unaligned_be16(tag, recv); + recv += sizeof(tag); + + /* Ignore length for now */ + recv += sizeof(u32); + + /* Write return code */ + put_unaligned_be32(rc, recv); + recv += sizeof(rc); + + /* Tell there is more data to read */ + *recv = TPMI_YES; + recv += sizeof(yes_no); + + /* Repeat the capability */ + put_unaligned_be32(capability, recv); + recv += sizeof(capability); + + /* Give the number of properties that follow */ + put_unaligned_be32(property_count, recv); + recv += sizeof(property_count); + + /* Fill with the properties */ + for (i = 0; i < property_count; i++) { + put_unaligned_be32(TPM2_PROPERTIES_OFFSET + property + + i, recv); + recv += sizeof(property); + put_unaligned_be32(tpm->properties[property + i], + recv); + recv += sizeof(property); + } + + /* Add trailing \0 */ + *recv = '\0'; + + /* Write response length */ + *recv_len = recv - recvbuf; + put_unaligned_be32(*recv_len, recvbuf + sizeof(tag)); + + break; + + case TPM2_CC_DAM_PARAMETERS: + tpm->properties[TPM2_PROP_MAX_TRIES] = get_unaligned_be32(sent); + sent += sizeof(*tpm->properties); + tpm->properties[TPM2_RECOVERY_TIME] = get_unaligned_be32(sent); + sent += sizeof(*tpm->properties); + tpm->properties[TPM2_LOCKOUT_RECOVERY] = get_unaligned_be32(sent); + sent += sizeof(*tpm->properties); + + sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + break; + + case TPM2_CC_PCR_READ: + selections = get_unaligned_be32(sent); + sent += sizeof(selections); + if (selections != 1) { + printf("Sandbox cannot handle more than one PCR\n"); + rc = TPM2_RC_VALUE; + return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + } + + alg = get_unaligned_be16(sent); + sent += sizeof(alg); + if (alg != TPM2_ALG_SHA256) { + printf("Sandbox TPM only handle SHA256 algorithm\n"); + rc = TPM2_RC_VALUE; + return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + } + + pcr_array_sz = *sent; + sent += sizeof(pcr_array_sz); + if (!pcr_array_sz || pcr_array_sz > 8) { + printf("Sandbox TPM cannot handle so much PCRs\n"); + rc = TPM2_RC_VALUE; + return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + } + + for (i = 0; i < pcr_array_sz; i++) + pcr_map += (u64)sent[i] << (i * 8); + + if (pcr_map >> SANDBOX_TPM_PCR_NB) { + printf("Sandbox TPM handles up to %d PCR(s)\n", + SANDBOX_TPM_PCR_NB); + rc = TPM2_RC_VALUE; + return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + } + + if (pcr_map >> SANDBOX_TPM_PCR_NB) { + printf("Wrong PCR map.\n"); + rc = TPM2_RC_VALUE; + return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + } + + for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) + if (pcr_map & BIT(i)) + pcr_index = i; + + /* Write tag */ + put_unaligned_be16(tag, recv); + recv += sizeof(tag); + + /* Ignore length for now */ + recv += sizeof(u32); + + /* Write return code */ + put_unaligned_be32(rc, recv); + recv += sizeof(rc); + + /* Number of extensions */ + put_unaligned_be32(tpm->pcr_extensions[pcr_index], recv); + recv += sizeof(u32); + + /* Copy the PCR */ + memcpy(recv, tpm->pcr[pcr_index], TPM2_DIGEST_LEN); + recv += TPM2_DIGEST_LEN; + + /* Add trailing \0 */ + *recv = '\0'; + + /* Write response length */ + *recv_len = recv - recvbuf; + put_unaligned_be32(*recv_len, recvbuf + sizeof(tag)); + + break; + + case TPM2_CC_PCR_EXTEND: + /* Get the PCR index */ + pcr_index = get_unaligned_be32(sendbuf + sizeof(tag) + + sizeof(length) + + sizeof(command)); + if (pcr_index > SANDBOX_TPM_PCR_NB) { + printf("Sandbox TPM handles up to %d PCR(s)\n", + SANDBOX_TPM_PCR_NB); + rc = TPM2_RC_VALUE; + } + + /* Check the number of hashes */ + pcr_nb = get_unaligned_be32(sent); + sent += sizeof(pcr_nb); + if (pcr_nb != 1) { + printf("Sandbox cannot handle more than one PCR\n"); + rc = TPM2_RC_VALUE; + return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + } + + /* Check the hash algorithm */ + alg = get_unaligned_be16(sent); + sent += sizeof(alg); + if (alg != TPM2_ALG_SHA256) { + printf("Sandbox TPM only handle SHA256 algorithm\n"); + rc = TPM2_RC_VALUE; + return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + } + + /* Extend the PCR */ + rc = sandbox_tpm2_extend(dev, pcr_index, sent); + + sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + break; + + default: + printf("TPM2 command %02x unknown in Sandbox\n", command); + rc = TPM2_RC_COMMAND_CODE; + sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); + } + + return 0; +} + +static int sandbox_tpm2_get_desc(struct udevice *dev, char *buf, int size) +{ + if (size < 15) + return -ENOSPC; + + return snprintf(buf, size, "Sandbox TPM2.x"); +} + +static int sandbox_tpm2_open(struct udevice *dev) +{ + struct sandbox_tpm2 *tpm = dev_get_priv(dev); + + if (tpm->init_done) + return -EIO; + + tpm->init_done = true; + + return 0; +} + +static int sandbox_tpm2_probe(struct udevice *dev) +{ + struct sandbox_tpm2 *tpm = dev_get_priv(dev); + struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); + + memset(tpm, 0, sizeof(*tpm)); + + priv->pcr_count = 32; + priv->pcr_select_min = 2; + + return 0; +} + +static int sandbox_tpm2_close(struct udevice *dev) +{ + return 0; +} + +static const struct tpm_ops sandbox_tpm2_ops = { + .open = sandbox_tpm2_open, + .close = sandbox_tpm2_close, + .get_desc = sandbox_tpm2_get_desc, + .xfer = sandbox_tpm2_xfer, +}; + +static const struct udevice_id sandbox_tpm2_ids[] = { + { .compatible = "sandbox,tpm2" }, + { } +}; + +U_BOOT_DRIVER(sandbox_tpm2) = { + .name = "sandbox_tpm2", + .id = UCLASS_TPM, + .of_match = sandbox_tpm2_ids, + .ops = &sandbox_tpm2_ops, + .probe = sandbox_tpm2_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_tpm2), +}; diff --git a/drivers/tpm/tpm2_tis_spi.c b/drivers/tpm/tpm2_tis_spi.c new file mode 100644 index 00000000000..c5d17a679d2 --- /dev/null +++ b/drivers/tpm/tpm2_tis_spi.c @@ -0,0 +1,679 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: + * Miquel Raynal <miquel.raynal@bootlin.com> + * + * Description: + * SPI-level driver for TCG/TIS TPM (trusted platform module). + * Specifications at www.trustedcomputinggroup.org + * + * This device driver implements the TPM interface as defined in + * the TCG SPI protocol stack version 2.0. + * + * It is based on the U-Boot driver tpm_tis_infineon_i2c.c. + */ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <log.h> +#include <spi.h> +#include <tpm-v2.h> +#include <linux/errno.h> +#include <linux/compiler.h> +#include <linux/types.h> +#include <linux/unaligned/be_byteshift.h> +#include <asm-generic/gpio.h> + +#include "tpm_tis.h" +#include "tpm_internal.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define TPM_ACCESS(l) (0x0000 | ((l) << 12)) +#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12)) +#define TPM_STS(l) (0x0018 | ((l) << 12)) +#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12)) +#define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) +#define TPM_RID(l) (0x0F04 | ((l) << 12)) + +#define MAX_SPI_FRAMESIZE 64 + +/* Number of wait states to wait for */ +#define TPM_WAIT_STATES 100 + +/** + * struct tpm_tis_chip_data - Non-discoverable TPM information + * + * @pcr_count: Number of PCR per bank + * @pcr_select_min: Size in octets of the pcrSelect array + */ +struct tpm_tis_chip_data { + unsigned int pcr_count; + unsigned int pcr_select_min; + unsigned int time_before_first_cmd_ms; +}; + +/** + * tpm_tis_spi_read() - Read from TPM register + * + * @addr: register address to read from + * @buffer: provided by caller + * @len: number of bytes to read + * + * Read len bytes from TPM register and put them into + * buffer (little-endian format, i.e. first byte is put into buffer[0]). + * + * NOTE: TPM is big-endian for multi-byte values. Multi-byte + * values have to be swapped. + * + * @return -EIO on error, 0 on success. + */ +static int tpm_tis_spi_xfer(struct udevice *dev, u32 addr, const u8 *out, + u8 *in, u16 len) +{ + struct spi_slave *slave = dev_get_parent_priv(dev); + int transfer_len, ret; + u8 tx_buf[MAX_SPI_FRAMESIZE]; + u8 rx_buf[MAX_SPI_FRAMESIZE]; + + if (in && out) { + log(LOGC_NONE, LOGL_ERR, "%s: can't do full duplex\n", + __func__); + return -EINVAL; + } + + ret = spi_claim_bus(slave); + if (ret < 0) { + log(LOGC_NONE, LOGL_ERR, "%s: could not claim bus\n", __func__); + return ret; + } + + while (len) { + /* Request */ + transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE); + tx_buf[0] = (in ? BIT(7) : 0) | (transfer_len - 1); + tx_buf[1] = 0xD4; + tx_buf[2] = addr >> 8; + tx_buf[3] = addr; + + ret = spi_xfer(slave, 4 * 8, tx_buf, rx_buf, SPI_XFER_BEGIN); + if (ret < 0) { + log(LOGC_NONE, LOGL_ERR, + "%s: spi request transfer failed (err: %d)\n", + __func__, ret); + goto release_bus; + } + + /* Wait state */ + if (!(rx_buf[3] & 0x1)) { + int i; + + for (i = 0; i < TPM_WAIT_STATES; i++) { + ret = spi_xfer(slave, 1 * 8, NULL, rx_buf, 0); + if (ret) { + log(LOGC_NONE, LOGL_ERR, + "%s: wait state failed: %d\n", + __func__, ret); + goto release_bus; + } + + if (rx_buf[0] & 0x1) + break; + } + + if (i == TPM_WAIT_STATES) { + log(LOGC_NONE, LOGL_ERR, + "%s: timeout on wait state\n", __func__); + ret = -ETIMEDOUT; + goto release_bus; + } + } + + /* Read/Write */ + if (out) { + memcpy(tx_buf, out, transfer_len); + out += transfer_len; + } + + ret = spi_xfer(slave, transfer_len * 8, + out ? tx_buf : NULL, + in ? rx_buf : NULL, + SPI_XFER_END); + if (ret) { + log(LOGC_NONE, LOGL_ERR, + "%s: spi read transfer failed (err: %d)\n", + __func__, ret); + goto release_bus; + } + + if (in) { + memcpy(in, rx_buf, transfer_len); + in += transfer_len; + } + + len -= transfer_len; + } + +release_bus: + /* If an error occurred, release the chip by deasserting the CS */ + if (ret < 0) + spi_xfer(slave, 0, NULL, NULL, SPI_XFER_END); + + spi_release_bus(slave); + + return ret; +} + +static int tpm_tis_spi_read(struct udevice *dev, u16 addr, u8 *in, u16 len) +{ + return tpm_tis_spi_xfer(dev, addr, NULL, in, len); +} + +static int tpm_tis_spi_read32(struct udevice *dev, u32 addr, u32 *result) +{ + __le32 result_le; + int ret; + + ret = tpm_tis_spi_read(dev, addr, (u8 *)&result_le, sizeof(u32)); + if (!ret) + *result = le32_to_cpu(result_le); + + return ret; +} + +static int tpm_tis_spi_write(struct udevice *dev, u16 addr, const u8 *out, + u16 len) +{ + return tpm_tis_spi_xfer(dev, addr, out, NULL, len); +} + +static int tpm_tis_spi_check_locality(struct udevice *dev, int loc) +{ + const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID; + struct tpm_chip *chip = dev_get_priv(dev); + u8 buf; + int ret; + + ret = tpm_tis_spi_read(dev, TPM_ACCESS(loc), &buf, 1); + if (ret) + return ret; + + if ((buf & mask) == mask) { + chip->locality = loc; + return 0; + } + + return -ENOENT; +} + +static void tpm_tis_spi_release_locality(struct udevice *dev, int loc, + bool force) +{ + const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID; + u8 buf; + + if (tpm_tis_spi_read(dev, TPM_ACCESS(loc), &buf, 1) < 0) + return; + + if (force || (buf & mask) == mask) { + buf = TPM_ACCESS_ACTIVE_LOCALITY; + tpm_tis_spi_write(dev, TPM_ACCESS(loc), &buf, 1); + } +} + +static int tpm_tis_spi_request_locality(struct udevice *dev, int loc) +{ + struct tpm_chip *chip = dev_get_priv(dev); + unsigned long start, stop; + u8 buf = TPM_ACCESS_REQUEST_USE; + int ret; + + ret = tpm_tis_spi_check_locality(dev, loc); + if (!ret) + return 0; + + if (ret != -ENOENT) { + log(LOGC_NONE, LOGL_ERR, "%s: Failed to get locality: %d\n", + __func__, ret); + return ret; + } + + ret = tpm_tis_spi_write(dev, TPM_ACCESS(loc), &buf, 1); + if (ret) { + log(LOGC_NONE, LOGL_ERR, "%s: Failed to write to TPM: %d\n", + __func__, ret); + return ret; + } + + start = get_timer(0); + stop = chip->timeout_a; + do { + ret = tpm_tis_spi_check_locality(dev, loc); + if (!ret) + return 0; + + if (ret != -ENOENT) { + log(LOGC_NONE, LOGL_ERR, + "%s: Failed to get locality: %d\n", __func__, ret); + return ret; + } + + mdelay(TPM_TIMEOUT_MS); + } while (get_timer(start) < stop); + + log(LOGC_NONE, LOGL_ERR, "%s: Timeout getting locality: %d\n", __func__, + ret); + + return ret; +} + +static u8 tpm_tis_spi_status(struct udevice *dev, u8 *status) +{ + struct tpm_chip *chip = dev_get_priv(dev); + + return tpm_tis_spi_read(dev, TPM_STS(chip->locality), status, 1); +} + +static int tpm_tis_spi_wait_for_stat(struct udevice *dev, u8 mask, + unsigned long timeout, u8 *status) +{ + unsigned long start = get_timer(0); + unsigned long stop = timeout; + int ret; + + do { + mdelay(TPM_TIMEOUT_MS); + ret = tpm_tis_spi_status(dev, status); + if (ret) + return ret; + + if ((*status & mask) == mask) + return 0; + } while (get_timer(start) < stop); + + return -ETIMEDOUT; +} + +static int tpm_tis_spi_get_burstcount(struct udevice *dev) +{ + struct tpm_chip *chip = dev_get_priv(dev); + unsigned long start, stop; + u32 burstcount, ret; + + /* wait for burstcount */ + start = get_timer(0); + stop = chip->timeout_d; + do { + ret = tpm_tis_spi_read32(dev, TPM_STS(chip->locality), + &burstcount); + if (ret) + return -EBUSY; + + burstcount = (burstcount >> 8) & 0xFFFF; + if (burstcount) + return burstcount; + + mdelay(TPM_TIMEOUT_MS); + } while (get_timer(start) < stop); + + return -EBUSY; +} + +static int tpm_tis_spi_cancel(struct udevice *dev) +{ + struct tpm_chip *chip = dev_get_priv(dev); + u8 data = TPM_STS_COMMAND_READY; + + return tpm_tis_spi_write(dev, TPM_STS(chip->locality), &data, 1); +} + +static int tpm_tis_spi_recv_data(struct udevice *dev, u8 *buf, size_t count) +{ + struct tpm_chip *chip = dev_get_priv(dev); + int size = 0, burstcnt, len, ret; + u8 status; + + while (size < count && + tpm_tis_spi_wait_for_stat(dev, + TPM_STS_DATA_AVAIL | TPM_STS_VALID, + chip->timeout_c, &status) == 0) { + burstcnt = tpm_tis_spi_get_burstcount(dev); + if (burstcnt < 0) + return burstcnt; + + len = min_t(int, burstcnt, count - size); + ret = tpm_tis_spi_read(dev, TPM_DATA_FIFO(chip->locality), + buf + size, len); + if (ret < 0) + return ret; + + size += len; + } + + return size; +} + +static int tpm_tis_spi_recv(struct udevice *dev, u8 *buf, size_t count) +{ + struct tpm_chip *chip = dev_get_priv(dev); + int size, expected; + + if (!chip) + return -ENODEV; + + if (count < TPM_HEADER_SIZE) { + size = -EIO; + goto out; + } + + size = tpm_tis_spi_recv_data(dev, buf, TPM_HEADER_SIZE); + if (size < TPM_HEADER_SIZE) { + log(LOGC_NONE, LOGL_ERR, "TPM error, unable to read header\n"); + goto out; + } + + expected = get_unaligned_be32(buf + 2); + if (expected > count) { + size = -EIO; + goto out; + } + + size += tpm_tis_spi_recv_data(dev, &buf[TPM_HEADER_SIZE], + expected - TPM_HEADER_SIZE); + if (size < expected) { + log(LOGC_NONE, LOGL_ERR, + "TPM error, unable to read remaining bytes of result\n"); + size = -EIO; + goto out; + } + +out: + tpm_tis_spi_cancel(dev); + tpm_tis_spi_release_locality(dev, chip->locality, false); + + return size; +} + +static int tpm_tis_spi_send(struct udevice *dev, const u8 *buf, size_t len) +{ + struct tpm_chip *chip = dev_get_priv(dev); + u32 i, size; + u8 status; + int burstcnt, ret; + u8 data; + + if (!chip) + return -ENODEV; + + if (len > TPM_DEV_BUFSIZE) + return -E2BIG; /* Command is too long for our tpm, sorry */ + + ret = tpm_tis_spi_request_locality(dev, 0); + if (ret < 0) + return -EBUSY; + + /* + * Check if the TPM is ready. If not, if not, cancel the pending command + * and poll on the status to be finally ready. + */ + ret = tpm_tis_spi_status(dev, &status); + if (ret) + return ret; + + if (!(status & TPM_STS_COMMAND_READY)) { + /* Force the transition, usually this will be done at startup */ + ret = tpm_tis_spi_cancel(dev); + if (ret) { + log(LOGC_NONE, LOGL_ERR, + "%s: Could not cancel previous operation\n", + __func__); + goto out_err; + } + + ret = tpm_tis_spi_wait_for_stat(dev, TPM_STS_COMMAND_READY, + chip->timeout_b, &status); + if (ret < 0 || !(status & TPM_STS_COMMAND_READY)) { + log(LOGC_NONE, LOGL_ERR, + "status %d after wait for stat returned %d\n", + status, ret); + goto out_err; + } + } + + for (i = 0; i < len - 1;) { + burstcnt = tpm_tis_spi_get_burstcount(dev); + if (burstcnt < 0) + return burstcnt; + + size = min_t(int, len - i - 1, burstcnt); + ret = tpm_tis_spi_write(dev, TPM_DATA_FIFO(chip->locality), + buf + i, size); + if (ret < 0) + goto out_err; + + i += size; + } + + ret = tpm_tis_spi_status(dev, &status); + if (ret) + goto out_err; + + if ((status & TPM_STS_DATA_EXPECT) == 0) { + ret = -EIO; + goto out_err; + } + + ret = tpm_tis_spi_write(dev, TPM_DATA_FIFO(chip->locality), + buf + len - 1, 1); + if (ret) + goto out_err; + + ret = tpm_tis_spi_status(dev, &status); + if (ret) + goto out_err; + + if ((status & TPM_STS_DATA_EXPECT) != 0) { + ret = -EIO; + goto out_err; + } + + data = TPM_STS_GO; + ret = tpm_tis_spi_write(dev, TPM_STS(chip->locality), &data, 1); + if (ret) + goto out_err; + + return len; + +out_err: + tpm_tis_spi_cancel(dev); + tpm_tis_spi_release_locality(dev, chip->locality, false); + + return ret; +} + +static int tpm_tis_spi_cleanup(struct udevice *dev) +{ + struct tpm_chip *chip = dev_get_priv(dev); + + tpm_tis_spi_cancel(dev); + /* + * The TPM needs some time to clean up here, + * so we sleep rather than keeping the bus busy + */ + mdelay(2); + tpm_tis_spi_release_locality(dev, chip->locality, false); + + return 0; +} + +static int tpm_tis_spi_open(struct udevice *dev) +{ + struct tpm_chip *chip = dev_get_priv(dev); + + if (chip->is_open) + return -EBUSY; + + chip->is_open = 1; + + return 0; +} + +static int tpm_tis_spi_close(struct udevice *dev) +{ + struct tpm_chip *chip = dev_get_priv(dev); + + if (chip->is_open) { + tpm_tis_spi_release_locality(dev, chip->locality, true); + chip->is_open = 0; + } + + return 0; +} + +static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size) +{ + struct tpm_chip *chip = dev_get_priv(dev); + + if (size < 80) + return -ENOSPC; + + return snprintf(buf, size, + "%s v2.0: VendorID 0x%04x, DeviceID 0x%04x, RevisionID 0x%02x [%s]", + dev->name, chip->vend_dev & 0xFFFF, + chip->vend_dev >> 16, chip->rid, + (chip->is_open ? "open" : "closed")); +} + +static int tpm_tis_wait_init(struct udevice *dev, int loc) +{ + struct tpm_chip *chip = dev_get_priv(dev); + unsigned long start, stop; + u8 status; + int ret; + + start = get_timer(0); + stop = chip->timeout_b; + do { + mdelay(TPM_TIMEOUT_MS); + + ret = tpm_tis_spi_read(dev, TPM_ACCESS(loc), &status, 1); + if (ret) + break; + + if (status & TPM_ACCESS_VALID) + return 0; + } while (get_timer(start) < stop); + + return -EIO; +} + +static int tpm_tis_spi_probe(struct udevice *dev) +{ + struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(dev); + struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); + struct tpm_chip *chip = dev_get_priv(dev); + int ret; + + if (IS_ENABLED(CONFIG_DM_GPIO)) { + struct gpio_desc reset_gpio; + + ret = gpio_request_by_name(dev, "gpio-reset", 0, + &reset_gpio, GPIOD_IS_OUT); + if (ret) { + log(LOGC_NONE, LOGL_NOTICE, "%s: missing reset GPIO\n", + __func__); + } else { + dm_gpio_set_value(&reset_gpio, 0); + mdelay(1); + dm_gpio_set_value(&reset_gpio, 1); + } + } + + /* Ensure a minimum amount of time elapsed since reset of the TPM */ + mdelay(drv_data->time_before_first_cmd_ms); + + chip->locality = 0; + chip->timeout_a = TIS_SHORT_TIMEOUT_MS; + chip->timeout_b = TIS_LONG_TIMEOUT_MS; + chip->timeout_c = TIS_SHORT_TIMEOUT_MS; + chip->timeout_d = TIS_SHORT_TIMEOUT_MS; + priv->pcr_count = drv_data->pcr_count; + priv->pcr_select_min = drv_data->pcr_select_min; + + ret = tpm_tis_wait_init(dev, chip->locality); + if (ret) { + log(LOGC_DM, LOGL_ERR, "%s: no device found\n", __func__); + return ret; + } + + ret = tpm_tis_spi_request_locality(dev, chip->locality); + if (ret) { + log(LOGC_NONE, LOGL_ERR, "%s: could not request locality %d\n", + __func__, chip->locality); + return ret; + } + + ret = tpm_tis_spi_read32(dev, TPM_DID_VID(chip->locality), + &chip->vend_dev); + if (ret) { + log(LOGC_NONE, LOGL_ERR, + "%s: could not retrieve VendorID/DeviceID\n", __func__); + return ret; + } + + ret = tpm_tis_spi_read(dev, TPM_RID(chip->locality), &chip->rid, 1); + if (ret) { + log(LOGC_NONE, LOGL_ERR, "%s: could not retrieve RevisionID\n", + __func__); + return ret; + } + + log(LOGC_NONE, LOGL_ERR, + "SPI TPMv2.0 found (vid:%04x, did:%04x, rid:%02x)\n", + chip->vend_dev & 0xFFFF, chip->vend_dev >> 16, chip->rid); + + return 0; +} + +static int tpm_tis_spi_remove(struct udevice *dev) +{ + struct tpm_chip *chip = dev_get_priv(dev); + + tpm_tis_spi_release_locality(dev, chip->locality, true); + + return 0; +} + +static const struct tpm_ops tpm_tis_spi_ops = { + .open = tpm_tis_spi_open, + .close = tpm_tis_spi_close, + .get_desc = tpm_tis_get_desc, + .send = tpm_tis_spi_send, + .recv = tpm_tis_spi_recv, + .cleanup = tpm_tis_spi_cleanup, +}; + +static const struct tpm_tis_chip_data tpm_tis_std_chip_data = { + .pcr_count = 24, + .pcr_select_min = 3, + .time_before_first_cmd_ms = 30, +}; + +static const struct udevice_id tpm_tis_spi_ids[] = { + { + .compatible = "tis,tpm2-spi", + .data = (ulong)&tpm_tis_std_chip_data, + }, + { } +}; + +U_BOOT_DRIVER(tpm_tis_spi) = { + .name = "tpm_tis_spi", + .id = UCLASS_TPM, + .of_match = tpm_tis_spi_ids, + .ops = &tpm_tis_spi_ops, + .probe = tpm_tis_spi_probe, + .remove = tpm_tis_spi_remove, + .priv_auto_alloc_size = sizeof(struct tpm_chip), +}; diff --git a/drivers/tpm/tpm_atmel_twi.c b/drivers/tpm/tpm_atmel_twi.c index 8547580c244..2079ea913e4 100644 --- a/drivers/tpm/tpm_atmel_twi.c +++ b/drivers/tpm/tpm_atmel_twi.c @@ -7,7 +7,7 @@ #include <common.h> #include <dm.h> -#include <tpm.h> +#include <tpm-v1.h> #include <i2c.h> #include <asm/unaligned.h> diff --git a/drivers/tpm/tpm_tis.h b/drivers/tpm/tpm_tis.h index a899bc0b46a..947585f8e33 100644 --- a/drivers/tpm/tpm_tis.h +++ b/drivers/tpm/tpm_tis.h @@ -40,6 +40,7 @@ struct tpm_chip { int is_open; int locality; u32 vend_dev; + u8 rid; unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */ ulong chip_type; }; diff --git a/drivers/tpm/tpm_tis_infineon.c b/drivers/tpm/tpm_tis_infineon.c index 9b2a0250e19..b5fe43ee50f 100644 --- a/drivers/tpm/tpm_tis_infineon.c +++ b/drivers/tpm/tpm_tis_infineon.c @@ -23,7 +23,7 @@ #include <dm.h> #include <fdtdec.h> #include <i2c.h> -#include <tpm.h> +#include <tpm-v1.h> #include <linux/errno.h> #include <linux/compiler.h> #include <linux/types.h> diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c index 572926382ef..7664bb1a605 100644 --- a/drivers/tpm/tpm_tis_lpc.c +++ b/drivers/tpm/tpm_tis_lpc.c @@ -15,7 +15,7 @@ #include <common.h> #include <dm.h> #include <mapmem.h> -#include <tpm.h> +#include <tpm-v1.h> #include <asm/io.h> #define PREFIX "lpc_tpm: " diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c index 44157542a1f..8816d55759f 100644 --- a/drivers/tpm/tpm_tis_sandbox.c +++ b/drivers/tpm/tpm_tis_sandbox.c @@ -5,7 +5,7 @@ #include <common.h> #include <dm.h> -#include <tpm.h> +#include <tpm-v1.h> #include <asm/state.h> #include <asm/unaligned.h> #include <linux/crc8.h> diff --git a/drivers/tpm/tpm_tis_st33zp24_i2c.c b/drivers/tpm/tpm_tis_st33zp24_i2c.c index 9cf302caffd..0d380375eb3 100644 --- a/drivers/tpm/tpm_tis_st33zp24_i2c.c +++ b/drivers/tpm/tpm_tis_st33zp24_i2c.c @@ -16,7 +16,7 @@ #include <dm.h> #include <fdtdec.h> #include <i2c.h> -#include <tpm.h> +#include <tpm-v1.h> #include <errno.h> #include <linux/types.h> #include <asm/unaligned.h> diff --git a/drivers/tpm/tpm_tis_st33zp24_spi.c b/drivers/tpm/tpm_tis_st33zp24_spi.c index d5fde11a83d..f6087e76338 100644 --- a/drivers/tpm/tpm_tis_st33zp24_spi.c +++ b/drivers/tpm/tpm_tis_st33zp24_spi.c @@ -16,7 +16,7 @@ #include <dm.h> #include <fdtdec.h> #include <spi.h> -#include <tpm.h> +#include <tpm-v1.h> #include <errno.h> #include <linux/types.h> #include <asm/unaligned.h> diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c index 4b36a3e6082..2a28031d14c 100644 --- a/fs/ext4/ext4fs.c +++ b/fs/ext4/ext4fs.c @@ -164,7 +164,7 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, int ext4fs_ls(const char *dirname) { - struct ext2fs_node *dirnode; + struct ext2fs_node *dirnode = NULL; int status; if (dirname == NULL) @@ -174,7 +174,8 @@ int ext4fs_ls(const char *dirname) FILETYPE_DIRECTORY); if (status != 1) { printf("** Can not find directory. **\n"); - ext4fs_free_node(dirnode, &ext4fs_root->diropen); + if (dirnode) + ext4fs_free_node(dirnode, &ext4fs_root->diropen); return 1; } diff --git a/include/configs/at91-sama5_common.h b/include/configs/at91-sama5_common.h index 5af7d1d1d24..30c6cd47cac 100644 --- a/include/configs/at91-sama5_common.h +++ b/include/configs/at91-sama5_common.h @@ -57,7 +57,7 @@ #ifdef CONFIG_NAND_BOOT /* u-boot env in nand flash */ -#define CONFIG_ENV_OFFSET 0xc0000 +#define CONFIG_ENV_OFFSET 0x140000 #define CONFIG_ENV_OFFSET_REDUND 0x100000 #define CONFIG_ENV_SIZE 0x20000 #define CONFIG_BOOTCOMMAND "nand read 0x21000000 0x180000 0x80000;" \ diff --git a/include/configs/at91sam9260ek.h b/include/configs/at91sam9260ek.h index 433e4a8029c..137d7f0bbff 100644 --- a/include/configs/at91sam9260ek.h +++ b/include/configs/at91sam9260ek.h @@ -138,7 +138,7 @@ #elif defined(CONFIG_SYS_USE_NANDFLASH) /* bootstrap + u-boot + env + linux in nandflash */ -#define CONFIG_ENV_OFFSET 0x120000 +#define CONFIG_ENV_OFFSET 0x140000 #define CONFIG_ENV_OFFSET_REDUND 0x100000 #define CONFIG_ENV_SIZE 0x20000 /* 1 sector = 128 kB */ #define CONFIG_BOOTCOMMAND "nand read 0x22000000 0x200000 0x300000; bootm" diff --git a/include/configs/at91sam9261ek.h b/include/configs/at91sam9261ek.h index 6a085dd3e9e..9e852599094 100644 --- a/include/configs/at91sam9261ek.h +++ b/include/configs/at91sam9261ek.h @@ -125,7 +125,7 @@ #else /* CONFIG_SYS_USE_NANDFLASH */ /* bootstrap + u-boot + env + linux in nandflash */ -#define CONFIG_ENV_OFFSET 0x120000 +#define CONFIG_ENV_OFFSET 0x140000 #define CONFIG_ENV_OFFSET_REDUND 0x100000 #define CONFIG_ENV_SIZE 0x20000 /* 1 sector = 128 kB */ #define CONFIG_BOOTCOMMAND "nand read 0x22000000 0x200000 0x300000; bootm" diff --git a/include/configs/at91sam9263ek.h b/include/configs/at91sam9263ek.h index f37ef594e5c..4c476fc6a2b 100644 --- a/include/configs/at91sam9263ek.h +++ b/include/configs/at91sam9263ek.h @@ -234,7 +234,7 @@ #elif CONFIG_SYS_USE_NANDFLASH /* bootstrap + u-boot + env + linux in nandflash */ -#define CONFIG_ENV_OFFSET 0x120000 +#define CONFIG_ENV_OFFSET 0x140000 #define CONFIG_ENV_OFFSET_REDUND 0x100000 #define CONFIG_ENV_SIZE 0x20000 /* 1 sector = 128 kB */ #define CONFIG_BOOTCOMMAND "nand read 0x22000000 0x200000 0x300000; bootm" diff --git a/include/configs/at91sam9m10g45ek.h b/include/configs/at91sam9m10g45ek.h index 25970666c80..bec1558d6ba 100644 --- a/include/configs/at91sam9m10g45ek.h +++ b/include/configs/at91sam9m10g45ek.h @@ -76,7 +76,7 @@ #ifdef CONFIG_NAND_BOOT /* bootstrap + u-boot + env in nandflash */ -#define CONFIG_ENV_OFFSET 0x120000 +#define CONFIG_ENV_OFFSET 0x140000 #define CONFIG_ENV_OFFSET_REDUND 0x100000 #define CONFIG_ENV_SIZE 0x20000 diff --git a/include/configs/at91sam9n12ek.h b/include/configs/at91sam9n12ek.h index b284db36daa..a6865b2d6fb 100644 --- a/include/configs/at91sam9n12ek.h +++ b/include/configs/at91sam9n12ek.h @@ -110,7 +110,7 @@ #elif defined(CONFIG_NAND_BOOT) /* bootstrap + u-boot + env + linux in nandflash */ -#define CONFIG_ENV_OFFSET 0x120000 +#define CONFIG_ENV_OFFSET 0x140000 #define CONFIG_ENV_OFFSET_REDUND 0x100000 #define CONFIG_ENV_SIZE 0x20000 /* 1 sector = 128 kB */ #define CONFIG_BOOTCOMMAND \ diff --git a/include/configs/at91sam9rlek.h b/include/configs/at91sam9rlek.h index f805c7590fb..5ddb7673e54 100644 --- a/include/configs/at91sam9rlek.h +++ b/include/configs/at91sam9rlek.h @@ -86,7 +86,7 @@ #elif CONFIG_SYS_USE_NANDFLASH /* bootstrap + u-boot + env + linux in nandflash */ -#define CONFIG_ENV_OFFSET 0x120000 +#define CONFIG_ENV_OFFSET 0x140000 #define CONFIG_ENV_OFFSET_REDUND 0x100000 #define CONFIG_ENV_SIZE 0x20000 /* 1 sector = 128 kB */ #define CONFIG_BOOTCOMMAND "nand read 0x22000000 0x200000 0x600000; " \ diff --git a/include/configs/at91sam9x5ek.h b/include/configs/at91sam9x5ek.h index de10fadfbd9..8fc97509455 100644 --- a/include/configs/at91sam9x5ek.h +++ b/include/configs/at91sam9x5ek.h @@ -86,7 +86,7 @@ #ifdef CONFIG_NAND_BOOT /* bootstrap + u-boot + env + linux in nandflash */ -#define CONFIG_ENV_OFFSET 0x120000 +#define CONFIG_ENV_OFFSET 0x140000 #define CONFIG_ENV_OFFSET_REDUND 0x100000 #define CONFIG_ENV_SIZE 0x20000 /* 1 sector = 128 kB */ #define CONFIG_BOOTCOMMAND "nand read " \ diff --git a/include/configs/gw_ventana.h b/include/configs/gw_ventana.h index b8eefe3b118..1b7e29ca5e7 100644 --- a/include/configs/gw_ventana.h +++ b/include/configs/gw_ventana.h @@ -89,7 +89,6 @@ /* eMMC Configs */ #define CONFIG_SUPPORT_EMMC_BOOT -#define CONFIG_SUPPORT_EMMC_RPMB /* * SATA Configs diff --git a/include/configs/nsim.h b/include/configs/nsim.h index 0f22606feed..c3f34a91e43 100644 --- a/include/configs/nsim.h +++ b/include/configs/nsim.h @@ -25,16 +25,6 @@ #define CONFIG_SYS_LOAD_ADDR 0x82000000 /* - * UART configuration - * - */ -#define CONFIG_ARC_SERIAL - -/* - * Command line configuration - */ - -/* * Environment settings */ #define CONFIG_ENV_SIZE SZ_512 diff --git a/include/configs/rpi.h b/include/configs/rpi.h index 69a22e17009..649a425bcde 100644 --- a/include/configs/rpi.h +++ b/include/configs/rpi.h @@ -95,39 +95,50 @@ * * I suspect address 0 is used as the SMP pen on the RPi2, so avoid this. * - * fdt_addr_r simply shouldn't overlap anything else. However, the RPi's - * binary firmware loads a DT to address 0x100, so we choose this address to - * match it. This allows custom boot scripts to pass this DT on to Linux - * simply by not over-writing the data at this address. When using U-Boot, - * U-Boot (and scripts it executes) typicaly ignore the DT loaded by the FW - * and loads its own DT from disk (triggered by boot.scr or extlinux.conf). + * Older versions of the boot firmware place the firmware-loaded DTB at 0x100, + * newer versions place it in high memory. So prevent U-Boot from doing its own + * DTB + initrd relocation so that we won't accidentally relocate the initrd + * over the firmware-loaded DTB and generally try to lay out things starting + * from the bottom of RAM. * - * pxefile_addr_r can be pretty much anywhere that doesn't conflict with - * something else. Put it low in memory to avoid conflicts. + * kernel_addr_r has different constraints on ARM and Aarch64. For 32-bit ARM, + * it must be within the first 128M of RAM in order for the kernel's + * CONFIG_AUTO_ZRELADDR option to work. The kernel itself will be decompressed + * to 0x8000 but the decompressor clobbers 0x4000-0x8000 as well. The + * decompressor also likes to relocate itself to right past the end of the + * decompressed kernel, so in total the sum of the compressed and and + * decompressed kernel needs to be reserved. * - * kernel_addr_r must be within the first 128M of RAM in order for the - * kernel's CONFIG_AUTO_ZRELADDR option to work. Since the kernel will - * decompress itself to 0x8000 after the start of RAM, kernel_addr_r - * should not overlap that area, or the kernel will have to copy itself - * somewhere else before decompression. Similarly, the address of any other - * data passed to the kernel shouldn't overlap the start of RAM. Pushing - * this up to 16M allows for a sizable kernel to be decompressed below the - * compressed load address. + * For Aarch64, the kernel image is uncompressed and must be loaded at + * text_offset bytes (specified in the header of the Image) into a 2MB + * boundary. The 'booti' command relocates the image if necessary. Linux uses + * a default text_offset of 0x80000. In summary, loading at 0x80000 + * satisfies all these constraints and reserving memory up to 0x02400000 + * permits fairly large (roughly 36M) kernels. * - * scriptaddr can be pretty much anywhere that doesn't conflict with something - * else. Choosing 32M allows for the compressed kernel to be up to 16M. + * scriptaddr and pxefile_addr_r can be pretty much anywhere that doesn't + * conflict with something else. Reserving 1M for each of them at + * 0x02400000-0x02500000 and 0x02500000-0x02600000 should be plenty. * - * ramdisk_addr_r simply shouldn't overlap anything else. Choosing 33M allows - * for any boot script to be up to 1M, which is hopefully plenty. + * On ARM, both the DTB and any possible initrd must be loaded such that they + * fit inside the lowmem mapping in Linux. In practice, this usually means not + * more than ~700M away from the start of the kernel image but this number can + * be larger OR smaller depending on e.g. the 'vmalloc=xxxM' command line + * parameter given to the kernel. So reserving memory from low to high + * satisfies this constraint again. Reserving 1M at 0x02600000-0x02700000 for + * the DTB leaves rest of the free RAM to the initrd starting at 0x02700000. + * Even with the smallest possible CPU-GPU memory split of the CPU getting + * only 64M, the remaining 25M starting at 0x02700000 should allow quite + * large initrds before they start colliding with U-Boot. */ #define ENV_MEM_LAYOUT_SETTINGS \ "fdt_high=ffffffff\0" \ "initrd_high=ffffffff\0" \ - "fdt_addr_r=0x00000100\0" \ - "pxefile_addr_r=0x00100000\0" \ - "kernel_addr_r=0x01000000\0" \ - "scriptaddr=0x02000000\0" \ - "ramdisk_addr_r=0x02100000\0" \ + "kernel_addr_r=0x00080000\0" \ + "scriptaddr=0x02400000\0" \ + "pxefile_addr_r=0x02500000\0" \ + "fdt_addr_r=0x02600000\0" \ + "ramdisk_addr_r=0x02700000\0" #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 0) \ diff --git a/include/configs/sama5d2_xplained.h b/include/configs/sama5d2_xplained.h index f70ca83b25c..b205d8d6045 100644 --- a/include/configs/sama5d2_xplained.h +++ b/include/configs/sama5d2_xplained.h @@ -43,6 +43,15 @@ "fatload mmc 1:1 0x22000000 zImage; " \ "bootz 0x22000000 - 0x21000000" +#elif CONFIG_SPI_BOOT + +/* bootstrap + u-boot + env in sd card, but kernel + dtb in eMMC */ +#undef CONFIG_BOOTCOMMAND + +#define CONFIG_BOOTCOMMAND "ext4load mmc 0:1 0x21000000 /boot/at91-sama5d2_xplained.dtb; " \ + "ext4load mmc 0:1 0x22000000 /boot/zImage; " \ + "bootz 0x22000000 - 0x21000000" + #endif /* SPL */ diff --git a/include/configs/stm32f429-discovery.h b/include/configs/stm32f429-discovery.h index 4fd9c23e4e9..46eda1d5182 100644 --- a/include/configs/stm32f429-discovery.h +++ b/include/configs/stm32f429-discovery.h @@ -22,10 +22,10 @@ #define CONFIG_NR_DRAM_BANKS 1 #define CONFIG_SYS_RAM_CS 1 #define CONFIG_SYS_RAM_FREQ_DIV 2 -#define CONFIG_SYS_RAM_BASE 0xD0000000 +#define CONFIG_SYS_RAM_BASE 0x90000000 #define CONFIG_SYS_SDRAM_BASE CONFIG_SYS_RAM_BASE -#define CONFIG_SYS_LOAD_ADDR 0xD0400000 -#define CONFIG_LOADADDR 0xD0400000 +#define CONFIG_SYS_LOAD_ADDR 0x90400000 +#define CONFIG_LOADADDR 0x90400000 #define CONFIG_SYS_MAX_FLASH_SECT 12 #define CONFIG_SYS_MAX_FLASH_BANKS 2 diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h index f710c8fe2a4..b631f79df8c 100644 --- a/include/configs/uniphier.h +++ b/include/configs/uniphier.h @@ -168,10 +168,10 @@ "run boot_common\0" \ "tftpboot=tftpboot $kernel_addr_load $bootfile && " \ "tftpboot $ramdisk_addr_r $ramdisk_file &&" \ - "tftpboot $fdt_addr_r $fdt_file &&" \ + "tftpboot $fdt_addr_r $fdtfile &&" \ "run boot_common\0" \ "__nfsboot=tftpboot $kernel_addr_load $bootfile && " \ - "tftpboot $fdt_addr_r $fdt_file &&" \ + "tftpboot $fdt_addr_r $fdtfile &&" \ "setenv ramdisk_addr_r - &&" \ "run boot_common\0" #endif diff --git a/include/configs/vining_2000.h b/include/configs/vining_2000.h index 0b5f9403412..43f986342de 100644 --- a/include/configs/vining_2000.h +++ b/include/configs/vining_2000.h @@ -98,7 +98,6 @@ #ifdef CONFIG_ENV_IS_IN_MMC #define CONFIG_SUPPORT_EMMC_BOOT -#define CONFIG_SUPPORT_EMMC_RPMB #define CONFIG_SYS_MMC_ENV_DEV 0 /* USDHC4 eMMC */ /* 0=user, 1=boot0, 2=boot1, * 4..7=general0..3. */ #define CONFIG_SYS_MMC_ENV_PART 1 /* boot0 */ diff --git a/include/dt-bindings/pinctrl/pinctrl-snapdragon.h b/include/dt-bindings/pinctrl/pinctrl-snapdragon.h new file mode 100644 index 00000000000..615affb6f26 --- /dev/null +++ b/include/dt-bindings/pinctrl/pinctrl-snapdragon.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * This header provides constants for Qualcomm Snapdragon pinctrl bindings. + * + * (C) Copyright 2018 Ramon Fried <ramon.fried@gmail.com> + * + */ + +#ifndef _DT_BINDINGS_PINCTRL_SNAPDRAGON_H +#define _DT_BINDINGS_PINCTRL_SNAPDRAGON_H + +/* GPIO Drive Strength */ +#define DRIVE_STRENGTH_2MA 0 +#define DRIVE_STRENGTH_4MA 1 +#define DRIVE_STRENGTH_6MA 2 +#define DRIVE_STRENGTH_8MA 3 +#define DRIVE_STRENGTH_10MA 4 +#define DRIVE_STRENGTH_12MA 5 +#define DRIVE_STRENGTH_14MA 6 +#define DRIVE_STRENGTH_16MA 7 + +#endif diff --git a/include/dt_table.h b/include/dt_table.h new file mode 100644 index 00000000000..7fb16e900c1 --- /dev/null +++ b/include/dt_table.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * This is from the Android Project, + * Repository: https://android.googlesource.com/platform/system/libufdt + * File: utils/src/dt_table.h + * Commit: 2626d8b9e4d8e8c6cc67ceb1dc4e05a47779785c + * Copyright (C) 2017 The Android Open Source Project + */ + +#ifndef DT_TABLE_H +#define DT_TABLE_H + +#include <linux/types.h> + +#define DT_TABLE_MAGIC 0xd7b7ab1e +#define DT_TABLE_DEFAULT_PAGE_SIZE 2048 +#define DT_TABLE_DEFAULT_VERSION 0 + +struct dt_table_header { + u32 magic; /* DT_TABLE_MAGIC */ + u32 total_size; /* includes dt_table_header + all dt_table_entry + * and all dtb/dtbo + */ + u32 header_size; /* sizeof(dt_table_header) */ + + u32 dt_entry_size; /* sizeof(dt_table_entry) */ + u32 dt_entry_count; /* number of dt_table_entry */ + u32 dt_entries_offset; /* offset to the first dt_table_entry + * from head of dt_table_header. + * The value will be equal to header_size if + * no padding is appended + */ + u32 page_size; /* flash page size we assume */ + u32 version; /* DTBO image version, the current version is 0. + * The version will be incremented when the + * dt_table_header struct is updated. + */ +}; + +struct dt_table_entry { + u32 dt_size; + u32 dt_offset; /* offset from head of dt_table_header */ + + u32 id; /* optional, must be zero if unused */ + u32 rev; /* optional, must be zero if unused */ + u32 custom[4]; /* optional, must be zero if unused */ +}; + +#endif diff --git a/include/image.h b/include/image.h index df701e34705..95d5934344c 100644 --- a/include/image.h +++ b/include/image.h @@ -922,6 +922,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size); #define FIT_SETUP_PROP "setup" #define FIT_FPGA_PROP "fpga" #define FIT_FIRMWARE_PROP "firmware" +#define FIT_STANDALONE_PROP "standalone" #define FIT_MAX_HASH_LEN HASH_MAX_DIGEST_SIZE @@ -987,6 +988,8 @@ int fit_image_get_data_offset(const void *fit, int noffset, int *data_offset); int fit_image_get_data_position(const void *fit, int noffset, int *data_position); int fit_image_get_data_size(const void *fit, int noffset, int *data_size); +int fit_image_get_data_and_size(const void *fit, int noffset, + const void **data, size_t *size); int fit_image_hash_get_algo(const void *fit, int noffset, char **algo); int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value, @@ -1046,8 +1049,6 @@ int fit_conf_get_node(const void *fit, const char *conf_uname); int fit_conf_get_prop_node(const void *fit, int noffset, const char *prop_name); -void fit_conf_print(const void *fit, int noffset, const char *p); - int fit_check_ramdisk(const void *fit, int os_noffset, uint8_t arch, int verify); diff --git a/include/netdev.h b/include/netdev.h index 79fcee56d41..f27869072f4 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -69,7 +69,6 @@ int sh_eth_initialize(bd_t *bis); int skge_initialize(bd_t *bis); int smc91111_initialize(u8 dev_num, int base_addr); int smc911x_initialize(u8 dev_num, int base_addr); -int tsi108_eth_initialize(bd_t *bis); int uec_standard_init(bd_t *bis); int uli526x_initialize(bd_t *bis); int armada100_fec_register(unsigned long base_addr); diff --git a/include/pci.h b/include/pci.h index cda69076889..8e27cbfaf14 100644 --- a/include/pci.h +++ b/include/pci.h @@ -680,8 +680,21 @@ extern int pci_write_config_dword(pci_dev_t dev, int where, u32 val); void pciauto_region_init(struct pci_region *res); void pciauto_region_align(struct pci_region *res, pci_size_t size); void pciauto_config_init(struct pci_controller *hose); + +/** + * pciauto_region_allocate() - Allocate resources from a PCI resource region + * + * Allocates @size bytes from the PCI resource @res. If @supports_64bit is + * false, the result will be guaranteed to fit in 32 bits. + * + * @res: PCI region to allocate from + * @size: Amount of bytes to allocate + * @bar: Returns the PCI bus address of the allocated resource + * @supports_64bit: Whether to allow allocations above the 32-bit boundary + * @return 0 if successful, -1 on failure + */ int pciauto_region_allocate(struct pci_region *res, pci_size_t size, - pci_addr_t *bar); + pci_addr_t *bar, bool supports_64bit); #if !defined(CONFIG_DM_PCI) || defined(CONFIG_DM_PCI_COMPAT) extern int pci_hose_read_config_byte_via_dword(struct pci_controller *hose, diff --git a/include/serial.h b/include/serial.h index 384df94ed0b..b9ef6d91c9c 100644 --- a/include/serial.h +++ b/include/serial.h @@ -67,6 +67,12 @@ extern int usbtty_tstc(void); struct udevice; +enum serial_par { + SERIAL_PAR_NONE, + SERIAL_PAR_ODD, + SERIAL_PAR_EVEN +}; + /** * struct struct dm_serial_ops - Driver model serial operations * @@ -143,6 +149,16 @@ struct dm_serial_ops { */ int (*loop)(struct udevice *dev, int on); #endif + /** + * setparity() - Set up the parity + * + * Set up a new parity for this device. + * + * @dev: Device pointer + * @parity: parity to use + * @return 0 if OK, -ve on error + */ + int (*setparity)(struct udevice *dev, enum serial_par parity); }; /** diff --git a/include/tpm-common.h b/include/tpm-common.h new file mode 100644 index 00000000000..734c2c9d539 --- /dev/null +++ b/include/tpm-common.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#ifndef __TPM_COMMON_H +#define __TPM_COMMON_H + +enum tpm_duration { + TPM_SHORT = 0, + TPM_MEDIUM = 1, + TPM_LONG = 2, + TPM_UNDEFINED, + + TPM_DURATION_COUNT, +}; + +/* + * Here is a partial implementation of TPM commands. Please consult TCG Main + * Specification for definitions of TPM commands. + */ + +#define TPM_HEADER_SIZE 10 + +/* Max buffer size supported by our tpm */ +#define TPM_DEV_BUFSIZE 1260 + +/** + * struct tpm_chip_priv - Information about a TPM, stored by the uclass + * + * These values must be set up by the device's probe() method before + * communcation is attempted. If the device has an xfer() method, this is + * not needed. There is no need to set up @buf. + * + * @duration_ms: Length of each duration type in milliseconds + * @retry_time_ms: Time to wait before retrying receive + * @pcr_count: Number of PCR per bank + * @pcr_select_min: Minimum size in bytes of the pcrSelect array + * @buf: Buffer used during the exchanges with the chip + */ +struct tpm_chip_priv { + uint duration_ms[TPM_DURATION_COUNT]; + uint retry_time_ms; +#if defined(CONFIG_TPM_V2) + uint pcr_count; + uint pcr_select_min; +#endif + u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ +}; + +/** + * struct tpm_ops - low-level TPM operations + * + * These are designed to avoid loops and delays in the driver itself. These + * should be handled in the uclass. + * + * In gneral you should implement everything except xfer(). Where you need + * complete control of the transfer, then xfer() can be provided and will + * override the other methods. + * + * This interface is for low-level TPM access. It does not understand the + * concept of localities or the various TPM messages. That interface is + * defined in the functions later on in this file, but they all translate + * to bytes which are sent and received. + */ +struct tpm_ops { + /** + * open() - Request access to locality 0 for the caller + * + * After all commands have been completed the caller should call + * close(). + * + * @dev: Device to close + * @return 0 ok OK, -ve on error + */ + int (*open)(struct udevice *dev); + + /** + * close() - Close the current session + * + * Releasing the locked locality. Returns 0 on success, -ve 1 on + * failure (in case lock removal did not succeed). + * + * @dev: Device to close + * @return 0 ok OK, -ve on error + */ + int (*close)(struct udevice *dev); + + /** + * get_desc() - Get a text description of the TPM + * + * @dev: Device to check + * @buf: Buffer to put the string + * @size: Maximum size of buffer + * @return length of string, or -ENOSPC it no space + */ + int (*get_desc)(struct udevice *dev, char *buf, int size); + + /** + * send() - send data to the TPM + * + * @dev: Device to talk to + * @sendbuf: Buffer of the data to send + * @send_size: Size of the data to send + * + * Returns 0 on success or -ve on failure. + */ + int (*send)(struct udevice *dev, const u8 *sendbuf, size_t send_size); + + /** + * recv() - receive a response from the TPM + * + * @dev: Device to talk to + * @recvbuf: Buffer to save the response to + * @max_size: Maximum number of bytes to receive + * + * Returns number of bytes received on success, -EAGAIN if the TPM + * response is not ready, -EINTR if cancelled, or other -ve value on + * failure. + */ + int (*recv)(struct udevice *dev, u8 *recvbuf, size_t max_size); + + /** + * cleanup() - clean up after an operation in progress + * + * This is called if receiving times out. The TPM may need to abort + * the current transaction if it did not complete, and make itself + * ready for another. + * + * @dev: Device to talk to + */ + int (*cleanup)(struct udevice *dev); + + /** + * xfer() - send data to the TPM and get response + * + * This method is optional. If it exists it is used in preference + * to send(), recv() and cleanup(). It should handle all aspects of + * TPM communication for a single transfer. + * + * @dev: Device to talk to + * @sendbuf: Buffer of the data to send + * @send_size: Size of the data to send + * @recvbuf: Buffer to save the response to + * @recv_size: Pointer to the size of the response buffer + * + * Returns 0 on success (and places the number of response bytes at + * recv_size) or -ve on failure. + */ + int (*xfer)(struct udevice *dev, const u8 *sendbuf, size_t send_size, + u8 *recvbuf, size_t *recv_size); +}; + +#define tpm_get_ops(dev) ((struct tpm_ops *)device_get_ops(dev)) + +#define MAKE_TPM_CMD_ENTRY(cmd) \ + U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "") + +#define TPM_COMMAND_NO_ARG(cmd) \ +int do_##cmd(cmd_tbl_t *cmdtp, int flag, \ + int argc, char * const argv[]) \ +{ \ + if (argc != 1) \ + return CMD_RET_USAGE; \ + return report_return_code(cmd()); \ +} + +/** + * tpm_get_desc() - Get a text description of the TPM + * + * @dev: Device to check + * @buf: Buffer to put the string + * @size: Maximum size of buffer + * @return length of string, or -ENOSPC it no space + */ +int tpm_get_desc(struct udevice *dev, char *buf, int size); + +/** + * tpm_xfer() - send data to the TPM and get response + * + * This first uses the device's send() method to send the bytes. Then it calls + * recv() to get the reply. If recv() returns -EAGAIN then it will delay a + * short time and then call recv() again. + * + * Regardless of whether recv() completes successfully, it will then call + * cleanup() to finish the transaction. + * + * Note that the outgoing data is inspected to determine command type + * (ordinal) and a timeout is used for that command type. + * + * @sendbuf - buffer of the data to send + * @send_size size of the data to send + * @recvbuf - memory to save the response to + * @recv_len - pointer to the size of the response buffer + * + * Returns 0 on success (and places the number of response bytes at + * recv_len) or -ve on failure. + */ +int tpm_xfer(struct udevice *dev, const u8 *sendbuf, size_t send_size, + u8 *recvbuf, size_t *recv_size); + +/** + * Initialize TPM device. It must be called before any TPM commands. + * + * @return 0 on success, non-0 on error. + */ +int tpm_init(void); + +/** + * Retrieve the array containing all the commands. + * + * @return a cmd_tbl_t array. + */ +cmd_tbl_t *get_tpm_commands(unsigned int *size); + +#endif /* __TPM_COMMON_H */ diff --git a/include/tpm.h b/include/tpm-v1.h index c6316329f5a..6b4941ef9a2 100644 --- a/include/tpm.h +++ b/include/tpm-v1.h @@ -4,23 +4,22 @@ * Coypright (c) 2013 Guntermann & Drunck GmbH */ -#ifndef __TPM_H -#define __TPM_H +#ifndef __TPM_V1_H +#define __TPM_V1_H -/* - * Here is a partial implementation of TPM commands. Please consult TCG Main - * Specification for definitions of TPM commands. - */ - -#define TPM_HEADER_SIZE 10 +#include <tpm-common.h> -enum tpm_duration { - TPM_SHORT = 0, - TPM_MEDIUM = 1, - TPM_LONG = 2, - TPM_UNDEFINED, - - TPM_DURATION_COUNT, +/* Useful constants */ +enum { + TPM_REQUEST_HEADER_LENGTH = 10, + TPM_RESPONSE_HEADER_LENGTH = 10, + PCR_DIGEST_LENGTH = 20, + DIGEST_LENGTH = 20, + TPM_REQUEST_AUTH_LENGTH = 45, + TPM_RESPONSE_AUTH_LENGTH = 41, + /* some max lengths, valid for RSA keys <= 2048 bits */ + TPM_KEY12_MAX_LENGTH = 618, + TPM_PUBKEY_MAX_LENGTH = 288, }; enum tpm_startup_type { @@ -82,13 +81,13 @@ enum tpm_capability_areas { TPM_CAP_VERSION_VAL = 0x0000001A, }; -#define TPM_NV_PER_GLOBALLOCK (1U << 15) -#define TPM_NV_PER_PPREAD (1U << 16) -#define TPM_NV_PER_PPWRITE (1U << 0) -#define TPM_NV_PER_READ_STCLEAR (1U << 31) -#define TPM_NV_PER_WRITE_STCLEAR (1U << 14) -#define TPM_NV_PER_WRITEDEFINE (1U << 13) -#define TPM_NV_PER_WRITEALL (1U << 12) +#define TPM_NV_PER_GLOBALLOCK BIT(15) +#define TPM_NV_PER_PPREAD BIT(16) +#define TPM_NV_PER_PPWRITE BIT(0) +#define TPM_NV_PER_READ_STCLEAR BIT(31) +#define TPM_NV_PER_WRITE_STCLEAR BIT(14) +#define TPM_NV_PER_WRITEDEFINE BIT(13) +#define TPM_NV_PER_WRITEALL BIT(12) enum { TPM_PUBEK_SIZE = 256, @@ -232,211 +231,27 @@ struct tpm_permanent_flags { u8 disable_full_da_logic_info; } __packed; -/* Max buffer size supported by our tpm */ -#define TPM_DEV_BUFSIZE 1260 - -/** - * struct tpm_chip_priv - Information about a TPM, stored by the uclass - * - * These values must be set up by the device's probe() method before - * communcation is attempted. If the device has an xfer() method, this is - * not needed. There is no need to set up @buf. - * - * @duration_ms: Length of each duration type in milliseconds - * @retry_time_ms: Time to wait before retrying receive - */ -struct tpm_chip_priv { - uint duration_ms[TPM_DURATION_COUNT]; - uint retry_time_ms; - u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ -}; - -/** - * struct tpm_ops - low-level TPM operations - * - * These are designed to avoid loops and delays in the driver itself. These - * should be handled in the uclass. - * - * In gneral you should implement everything except xfer(). Where you need - * complete control of the transfer, then xfer() can be provided and will - * override the other methods. - * - * This interface is for low-level TPM access. It does not understand the - * concept of localities or the various TPM messages. That interface is - * defined in the functions later on in this file, but they all translate - * to bytes which are sent and received. - */ -struct tpm_ops { - /** - * open() - Request access to locality 0 for the caller - * - * After all commands have been completed the caller should call - * close(). - * - * @dev: Device to close - * @return 0 ok OK, -ve on error - */ - int (*open)(struct udevice *dev); - - /** - * close() - Close the current session - * - * Releasing the locked locality. Returns 0 on success, -ve 1 on - * failure (in case lock removal did not succeed). - * - * @dev: Device to close - * @return 0 ok OK, -ve on error - */ - int (*close)(struct udevice *dev); - - /** - * get_desc() - Get a text description of the TPM - * - * @dev: Device to check - * @buf: Buffer to put the string - * @size: Maximum size of buffer - * @return length of string, or -ENOSPC it no space - */ - int (*get_desc)(struct udevice *dev, char *buf, int size); - - /** - * send() - send data to the TPM - * - * @dev: Device to talk to - * @sendbuf: Buffer of the data to send - * @send_size: Size of the data to send - * - * Returns 0 on success or -ve on failure. - */ - int (*send)(struct udevice *dev, const uint8_t *sendbuf, - size_t send_size); - - /** - * recv() - receive a response from the TPM - * - * @dev: Device to talk to - * @recvbuf: Buffer to save the response to - * @max_size: Maximum number of bytes to receive - * - * Returns number of bytes received on success, -EAGAIN if the TPM - * response is not ready, -EINTR if cancelled, or other -ve value on - * failure. - */ - int (*recv)(struct udevice *dev, uint8_t *recvbuf, size_t max_size); - - /** - * cleanup() - clean up after an operation in progress - * - * This is called if receiving times out. The TPM may need to abort - * the current transaction if it did not complete, and make itself - * ready for another. - * - * @dev: Device to talk to - */ - int (*cleanup)(struct udevice *dev); - - /** - * xfer() - send data to the TPM and get response - * - * This method is optional. If it exists it is used in preference - * to send(), recv() and cleanup(). It should handle all aspects of - * TPM communication for a single transfer. - * - * @dev: Device to talk to - * @sendbuf: Buffer of the data to send - * @send_size: Size of the data to send - * @recvbuf: Buffer to save the response to - * @recv_size: Pointer to the size of the response buffer - * - * Returns 0 on success (and places the number of response bytes at - * recv_size) or -ve on failure. - */ - int (*xfer)(struct udevice *dev, const uint8_t *sendbuf, - size_t send_size, uint8_t *recvbuf, size_t *recv_size); -}; - -#define tpm_get_ops(dev) ((struct tpm_ops *)device_get_ops(dev)) - -/** - * tpm_open() - Request access to locality 0 for the caller - * - * After all commands have been completed the caller is supposed to - * call tpm_close(). - * - * Returns 0 on success, -ve on failure. - */ -int tpm_open(struct udevice *dev); - -/** - * tpm_close() - Close the current session - * - * Releasing the locked locality. Returns 0 on success, -ve 1 on - * failure (in case lock removal did not succeed). - */ -int tpm_close(struct udevice *dev); - -/** - * tpm_get_desc() - Get a text description of the TPM - * - * @dev: Device to check - * @buf: Buffer to put the string - * @size: Maximum size of buffer - * @return length of string, or -ENOSPC it no space - */ -int tpm_get_desc(struct udevice *dev, char *buf, int size); - -/** - * tpm_xfer() - send data to the TPM and get response - * - * This first uses the device's send() method to send the bytes. Then it calls - * recv() to get the reply. If recv() returns -EAGAIN then it will delay a - * short time and then call recv() again. - * - * Regardless of whether recv() completes successfully, it will then call - * cleanup() to finish the transaction. - * - * Note that the outgoing data is inspected to determine command type - * (ordinal) and a timeout is used for that command type. - * - * @sendbuf - buffer of the data to send - * @send_size size of the data to send - * @recvbuf - memory to save the response to - * @recv_len - pointer to the size of the response buffer - * - * Returns 0 on success (and places the number of response bytes at - * recv_len) or -ve on failure. - */ -int tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size, - uint8_t *recvbuf, size_t *recv_size); - -/** - * Initialize TPM device. It must be called before any TPM commands. - * - * @return 0 on success, non-0 on error. - */ -int tpm_init(void); - /** * Issue a TPM_Startup command. * * @param mode TPM startup mode * @return return code of the operation */ -uint32_t tpm_startup(enum tpm_startup_type mode); +u32 tpm_startup(enum tpm_startup_type mode); /** * Issue a TPM_SelfTestFull command. * * @return return code of the operation */ -uint32_t tpm_self_test_full(void); +u32 tpm_self_test_full(void); /** * Issue a TPM_ContinueSelfTest command. * * @return return code of the operation */ -uint32_t tpm_continue_self_test(void); +u32 tpm_continue_self_test(void); /** * Issue a TPM_NV_DefineSpace command. The implementation is limited @@ -448,7 +263,7 @@ uint32_t tpm_continue_self_test(void); * @param size size of the area * @return return code of the operation */ -uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size); +u32 tpm_nv_define_space(u32 index, u32 perm, u32 size); /** * Issue a TPM_NV_ReadValue command. This implementation is limited @@ -460,7 +275,7 @@ uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size); * @param count size of output buffer * @return return code of the operation */ -uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count); +u32 tpm_nv_read_value(u32 index, void *data, u32 count); /** * Issue a TPM_NV_WriteValue command. This implementation is limited @@ -472,7 +287,7 @@ uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count); * @param length length of data bytes of input buffer * @return return code of the operation */ -uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length); +u32 tpm_nv_write_value(u32 index, const void *data, u32 length); /** * Issue a TPM_Extend command. @@ -484,7 +299,7 @@ uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length); * command * @return return code of the operation */ -uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest); +u32 tpm_extend(u32 index, const void *in_digest, void *out_digest); /** * Issue a TPM_PCRRead command. @@ -494,7 +309,7 @@ uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest); * @param count size of output buffer * @return return code of the operation */ -uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count); +u32 tpm_pcr_read(u32 index, void *data, size_t count); /** * Issue a TSC_PhysicalPresence command. TPM physical presence flag @@ -503,37 +318,37 @@ uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count); * @param presence TPM physical presence flag * @return return code of the operation */ -uint32_t tpm_tsc_physical_presence(uint16_t presence); +u32 tpm_tsc_physical_presence(u16 presence); /** * Issue a TPM_ReadPubek command. * * @param data output buffer for the public endorsement key - * @param count size of ouput buffer + * @param count size of output buffer * @return return code of the operation */ -uint32_t tpm_read_pubek(void *data, size_t count); +u32 tpm_read_pubek(void *data, size_t count); /** * Issue a TPM_ForceClear command. * * @return return code of the operation */ -uint32_t tpm_force_clear(void); +u32 tpm_force_clear(void); /** * Issue a TPM_PhysicalEnable command. * * @return return code of the operation */ -uint32_t tpm_physical_enable(void); +u32 tpm_physical_enable(void); /** * Issue a TPM_PhysicalDisable command. * * @return return code of the operation */ -uint32_t tpm_physical_disable(void); +u32 tpm_physical_disable(void); /** * Issue a TPM_PhysicalSetDeactivated command. @@ -541,7 +356,7 @@ uint32_t tpm_physical_disable(void); * @param state boolean state of the deactivated flag * @return return code of the operation */ -uint32_t tpm_physical_set_deactivated(uint8_t state); +u32 tpm_physical_set_deactivated(u8 state); /** * Issue a TPM_GetCapability command. This implementation is limited @@ -551,22 +366,21 @@ uint32_t tpm_physical_set_deactivated(uint8_t state); * @param sub_cap further definition of capability, which is * limited to be 4-byte wide * @param cap output buffer for capability information - * @param count size of ouput buffer + * @param count size of output buffer * @return return code of the operation */ -uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, - void *cap, size_t count); +u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count); /** - * Issue a TPM_FlushSpecific command for a AUTH ressource. + * Issue a TPM_FlushSpecific command for a AUTH resource. * * @param auth_handle handle of the auth session * @return return code of the operation */ -uint32_t tpm_terminate_auth_session(uint32_t auth_handle); +u32 tpm_terminate_auth_session(u32 auth_handle); /** - * Issue a TPM_OIAP command to setup an object independant authorization + * Issue a TPM_OIAP command to setup an object independent authorization * session. * Information about the session is stored internally. * If there was already an OIAP session active it is terminated and a new @@ -575,14 +389,14 @@ uint32_t tpm_terminate_auth_session(uint32_t auth_handle); * @param auth_handle pointer to the (new) auth handle or NULL. * @return return code of the operation */ -uint32_t tpm_oiap(uint32_t *auth_handle); +u32 tpm_oiap(u32 *auth_handle); /** * Ends an active OIAP session. * * @return return code of the operation */ -uint32_t tpm_end_oiap(void); +u32 tpm_end_oiap(void); /** * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating @@ -595,10 +409,8 @@ uint32_t tpm_end_oiap(void); * @param key_handle pointer to the key handle * @return return code of the operation */ -uint32_t tpm_load_key2_oiap(uint32_t parent_handle, - const void *key, size_t key_length, - const void *parent_key_usage_auth, - uint32_t *key_handle); +u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length, + const void *parent_key_usage_auth, u32 *key_handle); /** * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for @@ -613,8 +425,8 @@ uint32_t tpm_load_key2_oiap(uint32_t parent_handle, * of the stored TPM_PUBKEY structure (iff pubkey != NULL). * @return return code of the operation */ -uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, - void *pubkey, size_t *pubkey_len); +u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey, + size_t *pubkey_len); /** * Get the TPM permanent flags value @@ -622,7 +434,7 @@ uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, * @param pflags Place to put permanent flags * @return return code of the operation */ -uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags); +u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags); /** * Get the TPM permissions @@ -630,7 +442,7 @@ uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags); * @param perm Returns permissions value * @return return code of the operation */ -uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm); +u32 tpm_get_permissions(u32 index, u32 *perm); /** * Flush a resource with a given handle and type from the TPM @@ -639,7 +451,7 @@ uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm); * @param resource_type type of the resource * @return return code of the operation */ -uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type); +u32 tpm_flush_specific(u32 key_handle, u32 resource_type); #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 /** @@ -650,8 +462,8 @@ uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type); * @param[out] handle The handle of the key (Non-null iff found) * @return 0 if key was found in TPM; != 0 if not. */ -uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t - pubkey_digest[20], uint32_t *handle); +u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20], + u32 *handle); #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ /** @@ -663,6 +475,6 @@ uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t * @param count size of output buffer * @return return code of the operation */ -uint32_t tpm_get_random(void *data, uint32_t count); +u32 tpm_get_random(void *data, u32 count); -#endif /* __TPM_H */ +#endif /* __TPM_V1_H */ diff --git a/include/tpm-v2.h b/include/tpm-v2.h new file mode 100644 index 00000000000..780e0619750 --- /dev/null +++ b/include/tpm-v2.h @@ -0,0 +1,262 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2018 Bootlin + * Author: Miquel Raynal <miquel.raynal@bootlin.com> + */ + +#ifndef __TPM_V2_H +#define __TPM_V2_H + +#include <tpm-common.h> + +#define TPM2_DIGEST_LEN 32 + +/** + * TPM2 Structure Tags for command/response buffers. + * + * @TPM2_ST_NO_SESSIONS: the command does not need an authentication. + * @TPM2_ST_SESSIONS: the command needs an authentication. + */ +enum tpm2_structures { + TPM2_ST_NO_SESSIONS = 0x8001, + TPM2_ST_SESSIONS = 0x8002, +}; + +/** + * TPM2 type of boolean. + */ +enum tpm2_yes_no { + TPMI_YES = 1, + TPMI_NO = 0, +}; + +/** + * TPM2 startup values. + * + * @TPM2_SU_CLEAR: reset the internal state. + * @TPM2_SU_STATE: restore saved state (if any). + */ +enum tpm2_startup_types { + TPM2_SU_CLEAR = 0x0000, + TPM2_SU_STATE = 0x0001, +}; + +/** + * TPM2 permanent handles. + * + * @TPM2_RH_OWNER: refers to the 'owner' hierarchy. + * @TPM2_RS_PW: indicates a password. + * @TPM2_RH_LOCKOUT: refers to the 'lockout' hierarchy. + * @TPM2_RH_ENDORSEMENT: refers to the 'endorsement' hierarchy. + * @TPM2_RH_PLATFORM: refers to the 'platform' hierarchy. + */ +enum tpm2_handles { + TPM2_RH_OWNER = 0x40000001, + TPM2_RS_PW = 0x40000009, + TPM2_RH_LOCKOUT = 0x4000000A, + TPM2_RH_ENDORSEMENT = 0x4000000B, + TPM2_RH_PLATFORM = 0x4000000C, +}; + +/** + * TPM2 command codes used at the beginning of a buffer, gives the command. + * + * @TPM2_CC_STARTUP: TPM2_Startup(). + * @TPM2_CC_SELF_TEST: TPM2_SelfTest(). + * @TPM2_CC_CLEAR: TPM2_Clear(). + * @TPM2_CC_CLEARCONTROL: TPM2_ClearControl(). + * @TPM2_CC_HIERCHANGEAUTH: TPM2_HierarchyChangeAuth(). + * @TPM2_CC_PCR_SETAUTHPOL: TPM2_PCR_SetAuthPolicy(). + * @TPM2_CC_DAM_RESET: TPM2_DictionaryAttackLockReset(). + * @TPM2_CC_DAM_PARAMETERS: TPM2_DictionaryAttackParameters(). + * @TPM2_CC_GET_CAPABILITY: TPM2_GetCapibility(). + * @TPM2_CC_PCR_READ: TPM2_PCR_Read(). + * @TPM2_CC_PCR_EXTEND: TPM2_PCR_Extend(). + * @TPM2_CC_PCR_SETAUTHVAL: TPM2_PCR_SetAuthValue(). + */ +enum tpm2_command_codes { + TPM2_CC_STARTUP = 0x0144, + TPM2_CC_SELF_TEST = 0x0143, + TPM2_CC_CLEAR = 0x0126, + TPM2_CC_CLEARCONTROL = 0x0127, + TPM2_CC_HIERCHANGEAUTH = 0x0129, + TPM2_CC_PCR_SETAUTHPOL = 0x012C, + TPM2_CC_DAM_RESET = 0x0139, + TPM2_CC_DAM_PARAMETERS = 0x013A, + TPM2_CC_GET_CAPABILITY = 0x017A, + TPM2_CC_PCR_READ = 0x017E, + TPM2_CC_PCR_EXTEND = 0x0182, + TPM2_CC_PCR_SETAUTHVAL = 0x0183, +}; + +/** + * TPM2 return codes. + */ +enum tpm2_return_codes { + TPM2_RC_SUCCESS = 0x0000, + TPM2_RC_BAD_TAG = 0x001E, + TPM2_RC_FMT1 = 0x0080, + TPM2_RC_HASH = TPM2_RC_FMT1 + 0x0003, + TPM2_RC_VALUE = TPM2_RC_FMT1 + 0x0004, + TPM2_RC_SIZE = TPM2_RC_FMT1 + 0x0015, + TPM2_RC_BAD_AUTH = TPM2_RC_FMT1 + 0x0022, + TPM2_RC_HANDLE = TPM2_RC_FMT1 + 0x000B, + TPM2_RC_VER1 = 0x0100, + TPM2_RC_INITIALIZE = TPM2_RC_VER1 + 0x0000, + TPM2_RC_FAILURE = TPM2_RC_VER1 + 0x0001, + TPM2_RC_DISABLED = TPM2_RC_VER1 + 0x0020, + TPM2_RC_AUTH_MISSING = TPM2_RC_VER1 + 0x0025, + TPM2_RC_COMMAND_CODE = TPM2_RC_VER1 + 0x0043, + TPM2_RC_AUTHSIZE = TPM2_RC_VER1 + 0x0044, + TPM2_RC_AUTH_CONTEXT = TPM2_RC_VER1 + 0x0045, + TPM2_RC_NEEDS_TEST = TPM2_RC_VER1 + 0x0053, + TPM2_RC_WARN = 0x0900, + TPM2_RC_TESTING = TPM2_RC_WARN + 0x000A, + TPM2_RC_REFERENCE_H0 = TPM2_RC_WARN + 0x0010, + TPM2_RC_LOCKOUT = TPM2_RC_WARN + 0x0021, +}; + +/** + * TPM2 algorithms. + */ +enum tpm2_algorithms { + TPM2_ALG_XOR = 0x0A, + TPM2_ALG_SHA256 = 0x0B, + TPM2_ALG_SHA384 = 0x0C, + TPM2_ALG_SHA512 = 0x0D, + TPM2_ALG_NULL = 0x10, +}; + +/** + * Issue a TPM2_Startup command. + * + * @mode TPM startup mode + * + * @return code of the operation + */ +u32 tpm2_startup(enum tpm2_startup_types mode); + +/** + * Issue a TPM2_SelfTest command. + * + * @full_test Asking to perform all tests or only the untested ones + * + * @return code of the operation + */ +u32 tpm2_self_test(enum tpm2_yes_no full_test); + +/** + * Issue a TPM2_Clear command. + * + * @handle Handle + * @pw Password + * @pw_sz Length of the password + * + * @return code of the operation + */ +u32 tpm2_clear(u32 handle, const char *pw, const ssize_t pw_sz); + +/** + * Issue a TPM2_PCR_Extend command. + * + * @index Index of the PCR + * @digest Value representing the event to be recorded + * + * @return code of the operation + */ +u32 tpm2_pcr_extend(u32 index, const uint8_t *digest); + +/** + * Issue a TPM2_PCR_Read command. + * + * @idx Index of the PCR + * @idx_min_sz Minimum size in bytes of the pcrSelect array + * @data Output buffer for contents of the named PCR + * @updates Optional out parameter: number of updates for this PCR + * + * @return code of the operation + */ +u32 tpm2_pcr_read(u32 idx, unsigned int idx_min_sz, void *data, + unsigned int *updates); + +/** + * Issue a TPM2_GetCapability command. This implementation is limited + * to query property index that is 4-byte wide. + * + * @capability Partition of capabilities + * @property Further definition of capability, limited to be 4 bytes wide + * @buf Output buffer for capability information + * @prop_count Size of output buffer + * + * @return code of the operation + */ +u32 tpm2_get_capability(u32 capability, u32 property, void *buf, + size_t prop_count); + +/** + * Issue a TPM2_DictionaryAttackLockReset command. + * + * @pw Password + * @pw_sz Length of the password + * + * @return code of the operation + */ +u32 tpm2_dam_reset(const char *pw, const ssize_t pw_sz); + +/** + * Issue a TPM2_DictionaryAttackParameters command. + * + * @pw Password + * @pw_sz Length of the password + * @max_tries Count of authorizations before lockout + * @recovery_time Time before decrementation of the failure count + * @lockout_recovery Time to wait after a lockout + * + * @return code of the operation + */ +u32 tpm2_dam_parameters(const char *pw, const ssize_t pw_sz, + unsigned int max_tries, unsigned int recovery_time, + unsigned int lockout_recovery); + +/** + * Issue a TPM2_HierarchyChangeAuth command. + * + * @handle Handle + * @newpw New password + * @newpw_sz Length of the new password + * @oldpw Old password + * @oldpw_sz Length of the old password + * + * @return code of the operation + */ +int tpm2_change_auth(u32 handle, const char *newpw, const ssize_t newpw_sz, + const char *oldpw, const ssize_t oldpw_sz); + +/** + * Issue a TPM_PCR_SetAuthPolicy command. + * + * @pw Platform password + * @pw_sz Length of the password + * @index Index of the PCR + * @digest New key to access the PCR + * + * @return code of the operation + */ +u32 tpm2_pcr_setauthpolicy(const char *pw, const ssize_t pw_sz, u32 index, + const char *key); + +/** + * Issue a TPM_PCR_SetAuthValue command. + * + * @pw Platform password + * @pw_sz Length of the password + * @index Index of the PCR + * @digest New key to access the PCR + * @key_sz Length of the new key + * + * @return code of the operation + */ +u32 tpm2_pcr_setauthvalue(const char *pw, const ssize_t pw_sz, u32 index, + const char *key, const ssize_t key_sz); + +#endif /* __TPM_V2_H */ diff --git a/include/tsi108.h b/include/tsi108.h deleted file mode 100644 index 8e246b857e7..00000000000 --- a/include/tsi108.h +++ /dev/null @@ -1,207 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/***************************************************************************** - * (C) Copyright 2003; Tundra Semiconductor Corp. - * (C) Copyright 2006; Freescale Semiconductor Corp. - *****************************************************************************/ - -/* - * FILENAME: tsi108.h - * - * Originator: Alex Bounine - * - * DESCRIPTION: - * Common definitions for the Tundra Tsi108 bridge chip - * - */ - -#ifndef _TSI108_H_ -#define _TSI108_H_ - -#define TSI108_HLP_REG_OFFSET (0x0000) -#define TSI108_PCI_REG_OFFSET (0x1000) -#define TSI108_CLK_REG_OFFSET (0x2000) -#define TSI108_PB_REG_OFFSET (0x3000) -#define TSI108_SD_REG_OFFSET (0x4000) -#define TSI108_MPIC_REG_OFFSET (0x7400) - -#define PB_ID (0x000) -#define PB_RSR (0x004) -#define PB_BUS_MS_SELECT (0x008) -#define PB_ISR (0x00C) -#define PB_ARB_CTRL (0x018) -#define PB_PVT_CTRL2 (0x034) -#define PB_SCR (0x400) -#define PB_ERRCS (0x404) -#define PB_AERR (0x408) -#define PB_REG_BAR (0x410) -#define PB_OCN_BAR1 (0x414) -#define PB_OCN_BAR2 (0x418) -#define PB_SDRAM_BAR1 (0x41C) -#define PB_SDRAM_BAR2 (0x420) -#define PB_MCR (0xC00) -#define PB_MCMD (0xC04) - -#define HLP_B0_ADDR (0x000) -#define HLP_B1_ADDR (0x010) -#define HLP_B2_ADDR (0x020) -#define HLP_B3_ADDR (0x030) - -#define HLP_B0_MASK (0x004) -#define HLP_B1_MASK (0x014) -#define HLP_B2_MASK (0x024) -#define HLP_B3_MASK (0x034) - -#define HLP_B0_CTRL0 (0x008) -#define HLP_B1_CTRL0 (0x018) -#define HLP_B2_CTRL0 (0x028) -#define HLP_B3_CTRL0 (0x038) - -#define HLP_B0_CTRL1 (0x00C) -#define HLP_B1_CTRL1 (0x01C) -#define HLP_B2_CTRL1 (0x02C) -#define HLP_B3_CTRL1 (0x03C) - -#define PCI_CSR (0x004) -#define PCI_P2O_BAR0 (0x010) -#define PCI_P2O_BAR0_UPPER (0x014) -#define PCI_P2O_BAR2 (0x018) -#define PCI_P2O_BAR2_UPPER (0x01C) -#define PCI_P2O_BAR3 (0x020) -#define PCI_P2O_BAR3_UPPER (0x024) - -#define PCI_MISC_CSR (0x040) -#define PCI_P2O_PAGE_SIZES (0x04C) - -#define PCI_PCIX_STAT (0x0F4) - -#define PCI_IRP_STAT (0x184) - -#define PCI_PFAB_BAR0 (0x204) -#define PCI_PFAB_BAR0_UPPER (0x208) -#define PCI_PFAB_IO (0x20C) -#define PCI_PFAB_IO_UPPER (0x210) - -#define PCI_PFAB_MEM32 (0x214) -#define PCI_PFAB_MEM32_REMAP (0x218) -#define PCI_PFAB_MEM32_MASK (0x21C) - -#define CG_PLL0_CTRL0 (0x210) -#define CG_PLL0_CTRL1 (0x214) -#define CG_PLL1_CTRL0 (0x220) -#define CG_PLL1_CTRL1 (0x224) -#define CG_PWRUP_STATUS (0x234) - -#define MPIC_CSR(n) (0x30C + (n * 0x40)) - -#define SD_CTRL (0x000) -#define SD_STATUS (0x004) -#define SD_TIMING (0x008) -#define SD_REFRESH (0x00C) -#define SD_INT_STATUS (0x010) -#define SD_INT_ENABLE (0x014) -#define SD_INT_SET (0x018) -#define SD_D0_CTRL (0x020) -#define SD_D1_CTRL (0x024) -#define SD_D0_BAR (0x028) -#define SD_D1_BAR (0x02C) -#define SD_ECC_CTRL (0x040) -#define SD_DLL_STATUS (0x250) - -#define TS_SD_CTRL_ENABLE (1 << 31) - -#define PB_ERRCS_ES (1 << 1) -#define PB_ISR_PBS_RD_ERR (1 << 8) -#define PCI_IRP_STAT_P_CSR (1 << 23) - -/* - * I2C : Register address offset definitions - */ -#define I2C_CNTRL1 (0x00000000) -#define I2C_CNTRL2 (0x00000004) -#define I2C_RD_DATA (0x00000008) -#define I2C_TX_DATA (0x0000000c) - -/* - * I2C : Register Bit Masks and Reset Values - * definitions for every register - */ - -/* I2C_CNTRL1 : Reset Value */ -#define I2C_CNTRL1_RESET_VALUE (0x0000000a) - -/* I2C_CNTRL1 : Register Bits Masks Definitions */ -#define I2C_CNTRL1_DEVCODE (0x0000000f) -#define I2C_CNTRL1_PAGE (0x00000700) -#define I2C_CNTRL1_BYTADDR (0x00ff0000) -#define I2C_CNTRL1_I2CWRITE (0x01000000) - -/* I2C_CNTRL1 : Read/Write Bit Mask Definition */ -#define I2C_CNTRL1_RWMASK (0x01ff070f) - -/* I2C_CNTRL1 : Unused/Reserved bits Definition */ -#define I2C_CNTRL1_RESERVED (0xfe00f8f0) - -/* I2C_CNTRL2 : Reset Value */ -#define I2C_CNTRL2_RESET_VALUE (0x00000000) - -/* I2C_CNTRL2 : Register Bits Masks Definitions */ -#define I2C_CNTRL2_SIZE (0x00000003) -#define I2C_CNTRL2_LANE (0x0000000c) -#define I2C_CNTRL2_MULTIBYTE (0x00000010) -#define I2C_CNTRL2_START (0x00000100) -#define I2C_CNTRL2_WR_STATUS (0x00010000) -#define I2C_CNTRL2_RD_STATUS (0x00020000) -#define I2C_CNTRL2_I2C_TO_ERR (0x04000000) -#define I2C_CNTRL2_I2C_CFGERR (0x08000000) -#define I2C_CNTRL2_I2C_CMPLT (0x10000000) - -/* I2C_CNTRL2 : Read/Write Bit Mask Definition */ -#define I2C_CNTRL2_RWMASK (0x0000011f) - -/* I2C_CNTRL2 : Unused/Reserved bits Definition */ -#define I2C_CNTRL2_RESERVED (0xe3fcfee0) - -/* I2C_RD_DATA : Reset Value */ -#define I2C_RD_DATA_RESET_VALUE (0x00000000) - -/* I2C_RD_DATA : Register Bits Masks Definitions */ -#define I2C_RD_DATA_RBYTE0 (0x000000ff) -#define I2C_RD_DATA_RBYTE1 (0x0000ff00) -#define I2C_RD_DATA_RBYTE2 (0x00ff0000) -#define I2C_RD_DATA_RBYTE3 (0xff000000) - -/* I2C_RD_DATA : Read/Write Bit Mask Definition */ -#define I2C_RD_DATA_RWMASK (0x00000000) - -/* I2C_RD_DATA : Unused/Reserved bits Definition */ -#define I2C_RD_DATA_RESERVED (0x00000000) - -/* I2C_TX_DATA : Reset Value */ -#define I2C_TX_DATA_RESET_VALUE (0x00000000) - -/* I2C_TX_DATA : Register Bits Masks Definitions */ -#define I2C_TX_DATA_TBYTE0 (0x000000ff) -#define I2C_TX_DATA_TBYTE1 (0x0000ff00) -#define I2C_TX_DATA_TBYTE2 (0x00ff0000) -#define I2C_TX_DATA_TBYTE3 (0xff000000) - -/* I2C_TX_DATA : Read/Write Bit Mask Definition */ -#define I2C_TX_DATA_RWMASK (0xffffffff) - -/* I2C_TX_DATA : Unused/Reserved bits Definition */ -#define I2C_TX_DATA_RESERVED (0x00000000) - -#define TSI108_I2C_OFFSET 0x7000 /* offset for general use I2C channel */ -#define TSI108_I2C_SDRAM_OFFSET 0x4400 /* offset for SPD I2C channel */ - -#define I2C_EEPROM_DEVCODE 0xA /* standard I2C EEPROM device code */ - -/* I2C status codes */ - -#define TSI108_I2C_SUCCESS 0 -#define TSI108_I2C_PARAM_ERR 1 -#define TSI108_I2C_TIMEOUT_ERR 2 -#define TSI108_I2C_IF_BUSY 3 -#define TSI108_I2C_IF_ERROR 4 - -#endif /* _TSI108_H_ */ diff --git a/lib/Makefile b/lib/Makefile index d531ea54b31..e6cb4afc232 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -39,7 +39,9 @@ obj-$(CONFIG_PHYSMEM) += physmem.o obj-y += qsort.o obj-y += rc4.o obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o -obj-$(CONFIG_TPM) += tpm.o +obj-$(CONFIG_TPM) += tpm-common.o +obj-$(CONFIG_TPM_V1) += tpm-v1.o +obj-$(CONFIG_TPM_V2) += tpm-v2.o obj-$(CONFIG_RBTREE) += rbtree.o obj-$(CONFIG_BITREVERSE) += bitrev.o obj-y += list_sort.o diff --git a/lib/tpm-common.c b/lib/tpm-common.c new file mode 100644 index 00000000000..43b530865a0 --- /dev/null +++ b/lib/tpm-common.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#include <common.h> +#include <dm.h> +#include <asm/unaligned.h> +#include <tpm-common.h> +#include "tpm-utils.h" + +int pack_byte_string(u8 *str, size_t size, const char *format, ...) +{ + va_list args; + size_t offset = 0, length = 0; + u8 *data = NULL; + u32 value = 0; + + va_start(args, format); + for (; *format; format++) { + switch (*format) { + case 'b': + offset = va_arg(args, size_t); + value = va_arg(args, int); + length = 1; + break; + case 'w': + offset = va_arg(args, size_t); + value = va_arg(args, int); + length = 2; + break; + case 'd': + offset = va_arg(args, size_t); + value = va_arg(args, u32); + length = 4; + break; + case 's': + offset = va_arg(args, size_t); + data = va_arg(args, u8 *); + length = va_arg(args, u32); + break; + default: + debug("Couldn't recognize format string\n"); + va_end(args); + return -1; + } + + if (offset + length > size) { + va_end(args); + return -1; + } + + switch (*format) { + case 'b': + str[offset] = value; + break; + case 'w': + put_unaligned_be16(value, str + offset); + break; + case 'd': + put_unaligned_be32(value, str + offset); + break; + case 's': + memcpy(str + offset, data, length); + break; + } + } + va_end(args); + + return 0; +} + +int unpack_byte_string(const u8 *str, size_t size, const char *format, ...) +{ + va_list args; + size_t offset = 0, length = 0; + u8 *ptr8 = NULL; + u16 *ptr16 = NULL; + u32 *ptr32 = NULL; + + va_start(args, format); + for (; *format; format++) { + switch (*format) { + case 'b': + offset = va_arg(args, size_t); + ptr8 = va_arg(args, u8 *); + length = 1; + break; + case 'w': + offset = va_arg(args, size_t); + ptr16 = va_arg(args, u16 *); + length = 2; + break; + case 'd': + offset = va_arg(args, size_t); + ptr32 = va_arg(args, u32 *); + length = 4; + break; + case 's': + offset = va_arg(args, size_t); + ptr8 = va_arg(args, u8 *); + length = va_arg(args, u32); + break; + default: + va_end(args); + debug("Couldn't recognize format string\n"); + return -1; + } + + if (offset + length > size) { + va_end(args); + return -1; + } + + switch (*format) { + case 'b': + *ptr8 = str[offset]; + break; + case 'w': + *ptr16 = get_unaligned_be16(str + offset); + break; + case 'd': + *ptr32 = get_unaligned_be32(str + offset); + break; + case 's': + memcpy(ptr8, str + offset, length); + break; + } + } + va_end(args); + + return 0; +} + +u32 tpm_command_size(const void *command) +{ + const size_t command_size_offset = 2; + + return get_unaligned_be32(command + command_size_offset); +} + +u32 tpm_return_code(const void *response) +{ + const size_t return_code_offset = 6; + + return get_unaligned_be32(response + return_code_offset); +} + +u32 tpm_sendrecv_command(const void *command, void *response, size_t *size_ptr) +{ + struct udevice *dev; + int err, ret; + u8 response_buffer[COMMAND_BUFFER_SIZE]; + size_t response_length; + int i; + + if (response) { + response_length = *size_ptr; + } else { + response = response_buffer; + response_length = sizeof(response_buffer); + } + + ret = uclass_first_device_err(UCLASS_TPM, &dev); + if (ret) + return ret; + err = tpm_xfer(dev, command, tpm_command_size(command), + response, &response_length); + + if (err < 0) + return err; + + if (size_ptr) + *size_ptr = response_length; + + ret = tpm_return_code(response); + + log(LOGC_NONE, LOGL_DEBUG, "TPM response [ret:%d]: ", ret); + for (i = 0; i < response_length; i++) + log(LOGC_NONE, LOGL_DEBUG, "%02x ", ((u8 *)response)[i]); + log(LOGC_NONE, LOGL_DEBUG, "\n"); + + return ret; +} + +int tpm_init(void) +{ + struct udevice *dev; + int err; + + err = uclass_first_device_err(UCLASS_TPM, &dev); + if (err) + return err; + + return tpm_open(dev); +} diff --git a/lib/tpm-utils.h b/lib/tpm-utils.h new file mode 100644 index 00000000000..a9cb7dc7ee5 --- /dev/null +++ b/lib/tpm-utils.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#ifndef __TPM_UTILS_H +#define __TPM_UTILS_H + +#define COMMAND_BUFFER_SIZE 256 + +/* Internal error of TPM command library */ +#define TPM_LIB_ERROR ((u32)~0u) + +/* To make strings of commands more easily */ +#define __MSB(x) ((x) >> 8) +#define __LSB(x) ((x) & 0xFF) +#define tpm_u16(x) __MSB(x), __LSB(x) +#define tpm_u32(x) tpm_u16((x) >> 16), tpm_u16((x) & 0xFFFF) + +/** + * tpm_open() - Request access to locality 0 for the caller + * + * After all commands have been completed the caller is supposed to + * call tpm_close(). + * + * Returns 0 on success, -ve on failure. + */ +int tpm_open(struct udevice *dev); + +/** + * tpm_close() - Close the current session + * + * Releasing the locked locality. Returns 0 on success, -ve 1 on + * failure (in case lock removal did not succeed). + */ +int tpm_close(struct udevice *dev); + +/** + * Pack data into a byte string. The data types are specified in + * the format string: 'b' means unsigned byte, 'w' unsigned word, + * 'd' unsigned double word, and 's' byte string. The data are a + * series of offsets and values (for type byte string there are also + * lengths). The data values are packed into the byte string + * sequentially, and so a latter value could over-write a former + * value. + * + * @param str output string + * @param size size of output string + * @param format format string + * @param ... data points + * @return 0 on success, non-0 on error + */ +int pack_byte_string(u8 *str, size_t size, const char *format, ...); + +/** + * Unpack data from a byte string. The data types are specified in + * the format string: 'b' means unsigned byte, 'w' unsigned word, + * 'd' unsigned double word, and 's' byte string. The data are a + * series of offsets and pointers (for type byte string there are also + * lengths). + * + * @param str output string + * @param size size of output string + * @param format format string + * @param ... data points + * @return 0 on success, non-0 on error + */ +int unpack_byte_string(const u8 *str, size_t size, const char *format, ...); + +/** + * Get TPM command size. + * + * @param command byte string of TPM command + * @return command size of the TPM command + */ +u32 tpm_command_size(const void *command); + +/** + * Get TPM response return code, which is one of TPM_RESULT values. + * + * @param response byte string of TPM response + * @return return code of the TPM response + */ +u32 tpm_return_code(const void *response); + +/** + * Send a TPM command and return response's return code, and optionally + * return response to caller. + * + * @param command byte string of TPM command + * @param response output buffer for TPM response, or NULL if the + * caller does not care about it + * @param size_ptr output buffer size (input parameter) and TPM + * response length (output parameter); this parameter + * is a bidirectional + * @return return code of the TPM response + */ +u32 tpm_sendrecv_command(const void *command, void *response, size_t *size_ptr); + +#endif /* __TPM_UTILS_H */ diff --git a/lib/tpm.c b/lib/tpm-v1.c index bc9652d8e4e..7aecb24f921 100644 --- a/lib/tpm.c +++ b/lib/tpm-v1.c @@ -6,26 +6,11 @@ #include <common.h> #include <dm.h> -#include <tpm.h> #include <asm/unaligned.h> #include <u-boot/sha1.h> - -/* Internal error of TPM command library */ -#define TPM_LIB_ERROR ((uint32_t)~0u) - -/* Useful constants */ -enum { - COMMAND_BUFFER_SIZE = 256, - TPM_REQUEST_HEADER_LENGTH = 10, - TPM_RESPONSE_HEADER_LENGTH = 10, - PCR_DIGEST_LENGTH = 20, - DIGEST_LENGTH = 20, - TPM_REQUEST_AUTH_LENGTH = 45, - TPM_RESPONSE_AUTH_LENGTH = 41, - /* some max lengths, valid for RSA keys <= 2048 bits */ - TPM_KEY12_MAX_LENGTH = 618, - TPM_PUBKEY_MAX_LENGTH = 288, -}; +#include <tpm-common.h> +#include <tpm-v1.h> +#include "tpm-utils.h" #ifdef CONFIG_TPM_AUTH_SESSIONS @@ -35,277 +20,50 @@ enum { struct session_data { int valid; - uint32_t handle; - uint8_t nonce_even[DIGEST_LENGTH]; - uint8_t nonce_odd[DIGEST_LENGTH]; + u32 handle; + u8 nonce_even[DIGEST_LENGTH]; + u8 nonce_odd[DIGEST_LENGTH]; }; static struct session_data oiap_session = {0, }; #endif /* CONFIG_TPM_AUTH_SESSIONS */ -/** - * Pack data into a byte string. The data types are specified in - * the format string: 'b' means unsigned byte, 'w' unsigned word, - * 'd' unsigned double word, and 's' byte string. The data are a - * series of offsets and values (for type byte string there are also - * lengths). The data values are packed into the byte string - * sequentially, and so a latter value could over-write a former - * value. - * - * @param str output string - * @param size size of output string - * @param format format string - * @param ... data points - * @return 0 on success, non-0 on error - */ -int pack_byte_string(uint8_t *str, size_t size, const char *format, ...) -{ - va_list args; - size_t offset = 0, length = 0; - uint8_t *data = NULL; - uint32_t value = 0; - - va_start(args, format); - for (; *format; format++) { - switch (*format) { - case 'b': - offset = va_arg(args, size_t); - value = va_arg(args, int); - length = 1; - break; - case 'w': - offset = va_arg(args, size_t); - value = va_arg(args, int); - length = 2; - break; - case 'd': - offset = va_arg(args, size_t); - value = va_arg(args, uint32_t); - length = 4; - break; - case 's': - offset = va_arg(args, size_t); - data = va_arg(args, uint8_t *); - length = va_arg(args, uint32_t); - break; - default: - debug("Couldn't recognize format string\n"); - va_end(args); - return -1; - } - - if (offset + length > size) { - va_end(args); - return -1; - } - - switch (*format) { - case 'b': - str[offset] = value; - break; - case 'w': - put_unaligned_be16(value, str + offset); - break; - case 'd': - put_unaligned_be32(value, str + offset); - break; - case 's': - memcpy(str + offset, data, length); - break; - } - } - va_end(args); - - return 0; -} - -/** - * Unpack data from a byte string. The data types are specified in - * the format string: 'b' means unsigned byte, 'w' unsigned word, - * 'd' unsigned double word, and 's' byte string. The data are a - * series of offsets and pointers (for type byte string there are also - * lengths). - * - * @param str output string - * @param size size of output string - * @param format format string - * @param ... data points - * @return 0 on success, non-0 on error - */ -int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...) -{ - va_list args; - size_t offset = 0, length = 0; - uint8_t *ptr8 = NULL; - uint16_t *ptr16 = NULL; - uint32_t *ptr32 = NULL; - - va_start(args, format); - for (; *format; format++) { - switch (*format) { - case 'b': - offset = va_arg(args, size_t); - ptr8 = va_arg(args, uint8_t *); - length = 1; - break; - case 'w': - offset = va_arg(args, size_t); - ptr16 = va_arg(args, uint16_t *); - length = 2; - break; - case 'd': - offset = va_arg(args, size_t); - ptr32 = va_arg(args, uint32_t *); - length = 4; - break; - case 's': - offset = va_arg(args, size_t); - ptr8 = va_arg(args, uint8_t *); - length = va_arg(args, uint32_t); - break; - default: - va_end(args); - debug("Couldn't recognize format string\n"); - return -1; - } - - if (offset + length > size) { - va_end(args); - return -1; - } - - switch (*format) { - case 'b': - *ptr8 = str[offset]; - break; - case 'w': - *ptr16 = get_unaligned_be16(str + offset); - break; - case 'd': - *ptr32 = get_unaligned_be32(str + offset); - break; - case 's': - memcpy(ptr8, str + offset, length); - break; - } - } - va_end(args); - - return 0; -} - -/** - * Get TPM command size. - * - * @param command byte string of TPM command - * @return command size of the TPM command - */ -static uint32_t tpm_command_size(const void *command) +u32 tpm_startup(enum tpm_startup_type mode) { - const size_t command_size_offset = 2; - return get_unaligned_be32(command + command_size_offset); -} - -/** - * Get TPM response return code, which is one of TPM_RESULT values. - * - * @param response byte string of TPM response - * @return return code of the TPM response - */ -static uint32_t tpm_return_code(const void *response) -{ - const size_t return_code_offset = 6; - return get_unaligned_be32(response + return_code_offset); -} - -/** - * Send a TPM command and return response's return code, and optionally - * return response to caller. - * - * @param command byte string of TPM command - * @param response output buffer for TPM response, or NULL if the - * caller does not care about it - * @param size_ptr output buffer size (input parameter) and TPM - * response length (output parameter); this parameter - * is a bidirectional - * @return return code of the TPM response - */ -static uint32_t tpm_sendrecv_command(const void *command, - void *response, size_t *size_ptr) -{ - struct udevice *dev; - int err, ret; - uint8_t response_buffer[COMMAND_BUFFER_SIZE]; - size_t response_length; - - if (response) { - response_length = *size_ptr; - } else { - response = response_buffer; - response_length = sizeof(response_buffer); - } - - ret = uclass_first_device_err(UCLASS_TPM, &dev); - if (ret) - return ret; - err = tpm_xfer(dev, command, tpm_command_size(command), - response, &response_length); - - if (err < 0) - return TPM_LIB_ERROR; - if (size_ptr) - *size_ptr = response_length; - - return tpm_return_code(response); -} - -int tpm_init(void) -{ - int err; - struct udevice *dev; - - err = uclass_first_device_err(UCLASS_TPM, &dev); - if (err) - return err; - return tpm_open(dev); -} - -uint32_t tpm_startup(enum tpm_startup_type mode) -{ - const uint8_t command[12] = { + const u8 command[12] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0, }; const size_t mode_offset = 10; - uint8_t buf[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE]; if (pack_byte_string(buf, sizeof(buf), "sw", - 0, command, sizeof(command), - mode_offset, mode)) + 0, command, sizeof(command), + mode_offset, mode)) return TPM_LIB_ERROR; return tpm_sendrecv_command(buf, NULL, NULL); } -uint32_t tpm_self_test_full(void) +u32 tpm_self_test_full(void) { - const uint8_t command[10] = { + const u8 command[10] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, }; return tpm_sendrecv_command(command, NULL, NULL); } -uint32_t tpm_continue_self_test(void) +u32 tpm_continue_self_test(void) { - const uint8_t command[10] = { + const u8 command[10] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53, }; return tpm_sendrecv_command(command, NULL, NULL); } -uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size) +u32 tpm_nv_define_space(u32 index, u32 perm, u32 size) { - const uint8_t command[101] = { + const u8 command[101] = { 0x0, 0xc1, /* TPM_TAG */ 0x0, 0x0, 0x0, 0x65, /* parameter size */ 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */ @@ -334,55 +92,55 @@ uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size) const size_t index_offset = 12; const size_t perm_offset = 70; const size_t size_offset = 77; - uint8_t buf[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE]; if (pack_byte_string(buf, sizeof(buf), "sddd", - 0, command, sizeof(command), - index_offset, index, - perm_offset, perm, - size_offset, size)) + 0, command, sizeof(command), + index_offset, index, + perm_offset, perm, + size_offset, size)) return TPM_LIB_ERROR; return tpm_sendrecv_command(buf, NULL, NULL); } -uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count) +u32 tpm_nv_read_value(u32 index, void *data, u32 count) { - const uint8_t command[22] = { + const u8 command[22] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, }; const size_t index_offset = 10; const size_t length_offset = 18; const size_t data_size_offset = 10; const size_t data_offset = 14; - uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; size_t response_length = sizeof(response); - uint32_t data_size; - uint32_t err; + u32 data_size; + u32 err; if (pack_byte_string(buf, sizeof(buf), "sdd", - 0, command, sizeof(command), - index_offset, index, - length_offset, count)) + 0, command, sizeof(command), + index_offset, index, + length_offset, count)) return TPM_LIB_ERROR; err = tpm_sendrecv_command(buf, response, &response_length); if (err) return err; if (unpack_byte_string(response, response_length, "d", - data_size_offset, &data_size)) + data_size_offset, &data_size)) return TPM_LIB_ERROR; if (data_size > count) return TPM_LIB_ERROR; if (unpack_byte_string(response, response_length, "s", - data_offset, data, data_size)) + data_offset, data, data_size)) return TPM_LIB_ERROR; return 0; } -uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length) +u32 tpm_nv_write_value(u32 index, const void *data, u32 length) { - const uint8_t command[256] = { + const u8 command[256] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, }; const size_t command_size_offset = 2; @@ -390,18 +148,18 @@ uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length) const size_t length_offset = 18; const size_t data_offset = 22; const size_t write_info_size = 12; - const uint32_t total_length = + const u32 total_length = TPM_REQUEST_HEADER_LENGTH + write_info_size + length; - uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; size_t response_length = sizeof(response); - uint32_t err; + u32 err; if (pack_byte_string(buf, sizeof(buf), "sddds", - 0, command, sizeof(command), - command_size_offset, total_length, - index_offset, index, - length_offset, length, - data_offset, data, length)) + 0, command, sizeof(command), + command_size_offset, total_length, + index_offset, index, + length_offset, length, + data_offset, data, length)) return TPM_LIB_ERROR; err = tpm_sendrecv_command(buf, response, &response_length); if (err) @@ -410,99 +168,99 @@ uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length) return 0; } -uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest) +u32 tpm_extend(u32 index, const void *in_digest, void *out_digest) { - const uint8_t command[34] = { + const u8 command[34] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14, }; const size_t index_offset = 10; const size_t in_digest_offset = 14; const size_t out_digest_offset = 10; - uint8_t buf[COMMAND_BUFFER_SIZE]; - uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH]; + u8 buf[COMMAND_BUFFER_SIZE]; + u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH]; size_t response_length = sizeof(response); - uint32_t err; + u32 err; if (pack_byte_string(buf, sizeof(buf), "sds", - 0, command, sizeof(command), - index_offset, index, - in_digest_offset, in_digest, - PCR_DIGEST_LENGTH)) + 0, command, sizeof(command), + index_offset, index, + in_digest_offset, in_digest, + PCR_DIGEST_LENGTH)) return TPM_LIB_ERROR; err = tpm_sendrecv_command(buf, response, &response_length); if (err) return err; if (unpack_byte_string(response, response_length, "s", - out_digest_offset, out_digest, - PCR_DIGEST_LENGTH)) + out_digest_offset, out_digest, + PCR_DIGEST_LENGTH)) return TPM_LIB_ERROR; return 0; } -uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count) +u32 tpm_pcr_read(u32 index, void *data, size_t count) { - const uint8_t command[14] = { + const u8 command[14] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15, }; const size_t index_offset = 10; const size_t out_digest_offset = 10; - uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; size_t response_length = sizeof(response); - uint32_t err; + u32 err; if (count < PCR_DIGEST_LENGTH) return TPM_LIB_ERROR; if (pack_byte_string(buf, sizeof(buf), "sd", - 0, command, sizeof(command), - index_offset, index)) + 0, command, sizeof(command), + index_offset, index)) return TPM_LIB_ERROR; err = tpm_sendrecv_command(buf, response, &response_length); if (err) return err; if (unpack_byte_string(response, response_length, "s", - out_digest_offset, data, PCR_DIGEST_LENGTH)) + out_digest_offset, data, PCR_DIGEST_LENGTH)) return TPM_LIB_ERROR; return 0; } -uint32_t tpm_tsc_physical_presence(uint16_t presence) +u32 tpm_tsc_physical_presence(u16 presence) { - const uint8_t command[12] = { + const u8 command[12] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0, }; const size_t presence_offset = 10; - uint8_t buf[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE]; if (pack_byte_string(buf, sizeof(buf), "sw", - 0, command, sizeof(command), - presence_offset, presence)) + 0, command, sizeof(command), + presence_offset, presence)) return TPM_LIB_ERROR; return tpm_sendrecv_command(buf, NULL, NULL); } -uint32_t tpm_read_pubek(void *data, size_t count) +u32 tpm_read_pubek(void *data, size_t count) { - const uint8_t command[30] = { + const u8 command[30] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c, }; const size_t response_size_offset = 2; const size_t data_offset = 10; const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20; - uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE]; + u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE]; size_t response_length = sizeof(response); - uint32_t data_size; - uint32_t err; + u32 data_size; + u32 err; err = tpm_sendrecv_command(command, response, &response_length); if (err) return err; if (unpack_byte_string(response, response_length, "d", - response_size_offset, &data_size)) + response_size_offset, &data_size)) return TPM_LIB_ERROR; if (data_size < header_and_checksum_size) return TPM_LIB_ERROR; @@ -510,59 +268,58 @@ uint32_t tpm_read_pubek(void *data, size_t count) if (data_size > count) return TPM_LIB_ERROR; if (unpack_byte_string(response, response_length, "s", - data_offset, data, data_size)) + data_offset, data, data_size)) return TPM_LIB_ERROR; return 0; } -uint32_t tpm_force_clear(void) +u32 tpm_force_clear(void) { - const uint8_t command[10] = { + const u8 command[10] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d, }; return tpm_sendrecv_command(command, NULL, NULL); } -uint32_t tpm_physical_enable(void) +u32 tpm_physical_enable(void) { - const uint8_t command[10] = { + const u8 command[10] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f, }; return tpm_sendrecv_command(command, NULL, NULL); } -uint32_t tpm_physical_disable(void) +u32 tpm_physical_disable(void) { - const uint8_t command[10] = { + const u8 command[10] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70, }; return tpm_sendrecv_command(command, NULL, NULL); } -uint32_t tpm_physical_set_deactivated(uint8_t state) +u32 tpm_physical_set_deactivated(u8 state) { - const uint8_t command[11] = { + const u8 command[11] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72, }; const size_t state_offset = 10; - uint8_t buf[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE]; if (pack_byte_string(buf, sizeof(buf), "sb", - 0, command, sizeof(command), - state_offset, state)) + 0, command, sizeof(command), + state_offset, state)) return TPM_LIB_ERROR; return tpm_sendrecv_command(buf, NULL, NULL); } -uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, - void *cap, size_t count) +u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count) { - const uint8_t command[22] = { + const u8 command[22] = { 0x0, 0xc1, /* TPM_TAG */ 0x0, 0x0, 0x0, 0x16, /* parameter size */ 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ @@ -574,34 +331,34 @@ uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, const size_t sub_cap_offset = 18; const size_t cap_offset = 14; const size_t cap_size_offset = 10; - uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; size_t response_length = sizeof(response); - uint32_t cap_size; - uint32_t err; + u32 cap_size; + u32 err; if (pack_byte_string(buf, sizeof(buf), "sdd", - 0, command, sizeof(command), - cap_area_offset, cap_area, - sub_cap_offset, sub_cap)) + 0, command, sizeof(command), + cap_area_offset, cap_area, + sub_cap_offset, sub_cap)) return TPM_LIB_ERROR; err = tpm_sendrecv_command(buf, response, &response_length); if (err) return err; if (unpack_byte_string(response, response_length, "d", - cap_size_offset, &cap_size)) + cap_size_offset, &cap_size)) return TPM_LIB_ERROR; if (cap_size > response_length || cap_size > count) return TPM_LIB_ERROR; if (unpack_byte_string(response, response_length, "s", - cap_offset, cap, cap_size)) + cap_offset, cap, cap_size)) return TPM_LIB_ERROR; return 0; } -uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags) +u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags) { - const uint8_t command[22] = { + const u8 command[22] = { 0x0, 0xc1, /* TPM_TAG */ 0x0, 0x0, 0x0, 0x16, /* parameter size */ 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ @@ -610,11 +367,11 @@ uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags) 0x0, 0x0, 0x1, 0x8, /* subcap value */ }; const size_t data_size_offset = TPM_HEADER_SIZE; - const size_t data_offset = TPM_HEADER_SIZE + sizeof (uint32_t); - uint8_t response[COMMAND_BUFFER_SIZE]; + const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32); + u8 response[COMMAND_BUFFER_SIZE]; size_t response_length = sizeof(response); - uint32_t err; - uint32_t data_size; + u32 err; + u32 data_size; err = tpm_sendrecv_command(command, response, &response_length); if (err) @@ -631,9 +388,9 @@ uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags) return 0; } -uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm) +u32 tpm_get_permissions(u32 index, u32 *perm) { - const uint8_t command[22] = { + const u8 command[22] = { 0x0, 0xc1, /* TPM_TAG */ 0x0, 0x0, 0x0, 0x16, /* parameter size */ 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ @@ -642,9 +399,9 @@ uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm) }; const size_t index_offset = 18; const size_t perm_offset = 60; - uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; size_t response_length = sizeof(response); - uint32_t err; + u32 err; if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command), index_offset, index)) @@ -660,9 +417,9 @@ uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm) } #ifdef CONFIG_TPM_FLUSH_RESOURCES -uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type) +u32 tpm_flush_specific(u32 key_handle, u32 resource_type) { - const uint8_t command[18] = { + const u8 command[18] = { 0x00, 0xc1, /* TPM_TAG */ 0x00, 0x00, 0x00, 0x12, /* parameter size */ 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */ @@ -671,9 +428,9 @@ uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type) }; const size_t key_handle_offset = 10; const size_t resource_type_offset = 14; - uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; size_t response_length = sizeof(response); - uint32_t err; + u32 err; if (pack_byte_string(buf, sizeof(buf), "sdd", 0, command, sizeof(command), @@ -702,12 +459,12 @@ uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type) * @param request_auth pointer to the auth block of the request to be filled * @param auth authentication data (HMAC key) */ -static uint32_t create_request_auth(const void *request, size_t request_len0, - size_t handles_len, - struct session_data *auth_session, - void *request_auth, const void *auth) +static u32 create_request_auth(const void *request, size_t request_len0, + size_t handles_len, + struct session_data *auth_session, + void *request_auth, const void *auth) { - uint8_t hmac_data[DIGEST_LENGTH * 3 + 1]; + u8 hmac_data[DIGEST_LENGTH * 3 + 1]; sha1_context hash_ctx; const size_t command_code_offset = 6; const size_t auth_nonce_odd_offset = 4; @@ -765,19 +522,18 @@ static uint32_t create_request_auth(const void *request, size_t request_len0, * @param response_auth pointer to the auth block of the response to be verified * @param auth authentication data (HMAC key) */ -static uint32_t verify_response_auth(uint32_t command_code, - const void *response, size_t response_len0, - size_t handles_len, - struct session_data *auth_session, - const void *response_auth, const void *auth) +static u32 verify_response_auth(u32 command_code, const void *response, + size_t response_len0, size_t handles_len, + struct session_data *auth_session, + const void *response_auth, const void *auth) { - uint8_t hmac_data[DIGEST_LENGTH * 3 + 1]; - uint8_t computed_auth[DIGEST_LENGTH]; + u8 hmac_data[DIGEST_LENGTH * 3 + 1]; + u8 computed_auth[DIGEST_LENGTH]; sha1_context hash_ctx; const size_t return_code_offset = 6; const size_t auth_continue_offset = 20; const size_t auth_auth_offset = 21; - uint8_t auth_continue; + u8 auth_continue; if (!auth_session || !auth_session->valid) return TPM_AUTHFAIL; @@ -798,7 +554,7 @@ static uint32_t verify_response_auth(uint32_t command_code, sha1_finish(&hash_ctx, hmac_data); memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH); - auth_continue = ((uint8_t *)response_auth)[auth_continue_offset]; + auth_continue = ((u8 *)response_auth)[auth_continue_offset]; if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb", DIGEST_LENGTH, response_auth, @@ -820,18 +576,17 @@ static uint32_t verify_response_auth(uint32_t command_code, return TPM_SUCCESS; } - -uint32_t tpm_terminate_auth_session(uint32_t auth_handle) +u32 tpm_terminate_auth_session(u32 auth_handle) { - const uint8_t command[18] = { + const u8 command[18] = { 0x00, 0xc1, /* TPM_TAG */ 0x00, 0x00, 0x00, 0x00, /* parameter size */ 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */ 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */ - 0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */ + 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */ }; const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH; - uint8_t request[COMMAND_BUFFER_SIZE]; + u8 request[COMMAND_BUFFER_SIZE]; if (pack_byte_string(request, sizeof(request), "sd", 0, command, sizeof(command), @@ -843,26 +598,27 @@ uint32_t tpm_terminate_auth_session(uint32_t auth_handle) return tpm_sendrecv_command(request, NULL, NULL); } -uint32_t tpm_end_oiap(void) +u32 tpm_end_oiap(void) { - uint32_t err = TPM_SUCCESS; + u32 err = TPM_SUCCESS; + if (oiap_session.valid) err = tpm_terminate_auth_session(oiap_session.handle); return err; } -uint32_t tpm_oiap(uint32_t *auth_handle) +u32 tpm_oiap(u32 *auth_handle) { - const uint8_t command[10] = { + const u8 command[10] = { 0x00, 0xc1, /* TPM_TAG */ 0x00, 0x00, 0x00, 0x0a, /* parameter size */ 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */ }; const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH; const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4; - uint8_t response[COMMAND_BUFFER_SIZE]; + u8 response[COMMAND_BUFFER_SIZE]; size_t response_length = sizeof(response); - uint32_t err; + u32 err; if (oiap_session.valid) tpm_terminate_auth_session(oiap_session.handle); @@ -873,7 +629,7 @@ uint32_t tpm_oiap(uint32_t *auth_handle) if (unpack_byte_string(response, response_length, "ds", res_auth_handle_offset, &oiap_session.handle, res_nonce_even_offset, &oiap_session.nonce_even, - (uint32_t)DIGEST_LENGTH)) + (u32)DIGEST_LENGTH)) return TPM_LIB_ERROR; oiap_session.valid = 1; if (auth_handle) @@ -881,12 +637,10 @@ uint32_t tpm_oiap(uint32_t *auth_handle) return 0; } -uint32_t tpm_load_key2_oiap(uint32_t parent_handle, - const void *key, size_t key_length, - const void *parent_key_usage_auth, - uint32_t *key_handle) +u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length, + const void *parent_key_usage_auth, u32 *key_handle) { - const uint8_t command[14] = { + const u8 command[14] = { 0x00, 0xc2, /* TPM_TAG */ 0x00, 0x00, 0x00, 0x00, /* parameter size */ 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */ @@ -896,11 +650,11 @@ uint32_t tpm_load_key2_oiap(uint32_t parent_handle, const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH; const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4; const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH; - uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH - + TPM_REQUEST_AUTH_LENGTH]; - uint8_t response[COMMAND_BUFFER_SIZE]; + u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH + + TPM_REQUEST_AUTH_LENGTH]; + u8 response[COMMAND_BUFFER_SIZE]; size_t response_length = sizeof(response); - uint32_t err; + u32 err; if (!oiap_session.valid) { err = tpm_oiap(NULL); @@ -918,9 +672,9 @@ uint32_t tpm_load_key2_oiap(uint32_t parent_handle, return TPM_LIB_ERROR; err = create_request_auth(request, sizeof(command) + key_length, 4, - &oiap_session, - request + sizeof(command) + key_length, - parent_key_usage_auth); + &oiap_session, + request + sizeof(command) + key_length, + parent_key_usage_auth); if (err) return err; err = tpm_sendrecv_command(request, response, &response_length); @@ -931,10 +685,11 @@ uint32_t tpm_load_key2_oiap(uint32_t parent_handle, } err = verify_response_auth(0x00000041, response, - response_length - TPM_RESPONSE_AUTH_LENGTH, - 4, &oiap_session, - response + response_length - TPM_RESPONSE_AUTH_LENGTH, - parent_key_usage_auth); + response_length - TPM_RESPONSE_AUTH_LENGTH, + 4, &oiap_session, + response + response_length - + TPM_RESPONSE_AUTH_LENGTH, + parent_key_usage_auth); if (err) return err; @@ -947,10 +702,10 @@ uint32_t tpm_load_key2_oiap(uint32_t parent_handle, return 0; } -uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, - void *pubkey, size_t *pubkey_len) +u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey, + size_t *pubkey_len) { - const uint8_t command[14] = { + const u8 command[14] = { 0x00, 0xc2, /* TPM_TAG */ 0x00, 0x00, 0x00, 0x00, /* parameter size */ 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */ @@ -959,11 +714,11 @@ uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, const size_t req_size_offset = 2; const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH; const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH; - uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH]; - uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH - + TPM_RESPONSE_AUTH_LENGTH]; + u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH]; + u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH + + TPM_RESPONSE_AUTH_LENGTH]; size_t response_length = sizeof(response); - uint32_t err; + u32 err; if (!oiap_session.valid) { err = tpm_oiap(NULL); @@ -973,13 +728,13 @@ uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, if (pack_byte_string(request, sizeof(request), "sdd", 0, command, sizeof(command), req_size_offset, - (uint32_t)(sizeof(command) + (u32)(sizeof(command) + TPM_REQUEST_AUTH_LENGTH), req_key_handle_offset, key_handle )) return TPM_LIB_ERROR; err = create_request_auth(request, sizeof(command), 4, &oiap_session, - request + sizeof(command), usage_auth); + request + sizeof(command), usage_auth); if (err) return err; err = tpm_sendrecv_command(request, response, &response_length); @@ -989,16 +744,17 @@ uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, return err; } err = verify_response_auth(0x00000021, response, - response_length - TPM_RESPONSE_AUTH_LENGTH, - 0, &oiap_session, - response + response_length - TPM_RESPONSE_AUTH_LENGTH, - usage_auth); + response_length - TPM_RESPONSE_AUTH_LENGTH, + 0, &oiap_session, + response + response_length - + TPM_RESPONSE_AUTH_LENGTH, + usage_auth); if (err) return err; if (pubkey) { if ((response_length - TPM_RESPONSE_HEADER_LENGTH - - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len) + - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len) return TPM_LIB_ERROR; *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH - TPM_RESPONSE_AUTH_LENGTH; @@ -1011,15 +767,15 @@ uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, } #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 -uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t - pubkey_digest[20], uint32_t *handle) -{ - uint16_t key_count; - uint32_t key_handles[10]; - uint8_t buf[288]; - uint8_t *ptr; - uint32_t err; - uint8_t digest[20]; +u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20], + u32 *handle) +{ + u16 key_count; + u32 key_handles[10]; + u8 buf[288]; + u8 *ptr; + u32 err; + u8 digest[20]; size_t buf_len; unsigned int i; @@ -1052,9 +808,9 @@ uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t #endif /* CONFIG_TPM_AUTH_SESSIONS */ -uint32_t tpm_get_random(void *data, uint32_t count) +u32 tpm_get_random(void *data, u32 count) { - const uint8_t command[14] = { + const u8 command[14] = { 0x0, 0xc1, /* TPM_TAG */ 0x0, 0x0, 0x0, 0xe, /* parameter size */ 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */ @@ -1062,15 +818,15 @@ uint32_t tpm_get_random(void *data, uint32_t count) const size_t length_offset = 10; const size_t data_size_offset = 10; const size_t data_offset = 14; - uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; size_t response_length = sizeof(response); - uint32_t data_size; - uint8_t *out = data; + u32 data_size; + u8 *out = data; while (count > 0) { - uint32_t this_bytes = min((size_t)count, - sizeof (response) - data_offset); - uint32_t err; + u32 this_bytes = min((size_t)count, + sizeof(response) - data_offset); + u32 err; if (pack_byte_string(buf, sizeof(buf), "sd", 0, command, sizeof(command), diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c new file mode 100644 index 00000000000..f1bbca8e7aa --- /dev/null +++ b/lib/tpm-v2.c @@ -0,0 +1,419 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2018 Bootlin + * Author: Miquel Raynal <miquel.raynal@bootlin.com> + */ + +#include <common.h> +#include <dm.h> +#include <tpm-common.h> +#include <tpm-v2.h> +#include "tpm-utils.h" + +u32 tpm2_startup(enum tpm2_startup_types mode) +{ + const u8 command_v2[12] = { + tpm_u16(TPM2_ST_NO_SESSIONS), + tpm_u32(12), + tpm_u32(TPM2_CC_STARTUP), + tpm_u16(mode), + }; + int ret; + + /* + * Note TPM2_Startup command will return RC_SUCCESS the first time, + * but will return RC_INITIALIZE otherwise. + */ + ret = tpm_sendrecv_command(command_v2, NULL, NULL); + if (ret && ret != TPM2_RC_INITIALIZE) + return ret; + + return 0; +} + +u32 tpm2_self_test(enum tpm2_yes_no full_test) +{ + const u8 command_v2[12] = { + tpm_u16(TPM2_ST_NO_SESSIONS), + tpm_u32(11), + tpm_u32(TPM2_CC_SELF_TEST), + full_test, + }; + + return tpm_sendrecv_command(command_v2, NULL, NULL); +} + +u32 tpm2_clear(u32 handle, const char *pw, const ssize_t pw_sz) +{ + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(27 + pw_sz), /* Length */ + tpm_u32(TPM2_CC_CLEAR), /* Command code */ + + /* HANDLE */ + tpm_u32(handle), /* TPM resource handle */ + + /* AUTH_SESSION */ + tpm_u32(9 + pw_sz), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* Session handle */ + tpm_u16(0), /* Size of <nonce> */ + /* <nonce> (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(pw_sz), /* Size of <hmac/password> */ + /* STRING(pw) <hmac/password> (if any) */ + }; + unsigned int offset = 27; + int ret; + + /* + * Fill the command structure starting from the first buffer: + * - the password (if any) + */ + ret = pack_byte_string(command_v2, sizeof(command_v2), "s", + offset, pw, pw_sz); + offset += pw_sz; + if (ret) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(command_v2, NULL, NULL); +} + +u32 tpm2_pcr_extend(u32 index, const uint8_t *digest) +{ + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(33 + TPM2_DIGEST_LEN), /* Length */ + tpm_u32(TPM2_CC_PCR_EXTEND), /* Command code */ + + /* HANDLE */ + tpm_u32(index), /* Handle (PCR Index) */ + + /* AUTH_SESSION */ + tpm_u32(9), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* Session handle */ + tpm_u16(0), /* Size of <nonce> */ + /* <nonce> (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(0), /* Size of <hmac/password> */ + /* <hmac/password> (if any) */ + tpm_u32(1), /* Count (number of hashes) */ + tpm_u16(TPM2_ALG_SHA256), /* Algorithm of the hash */ + /* STRING(digest) Digest */ + }; + unsigned int offset = 33; + int ret; + + /* + * Fill the command structure starting from the first buffer: + * - the digest + */ + ret = pack_byte_string(command_v2, sizeof(command_v2), "s", + offset, digest, TPM2_DIGEST_LEN); + offset += TPM2_DIGEST_LEN; + if (ret) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(command_v2, NULL, NULL); +} + +u32 tpm2_pcr_read(u32 idx, unsigned int idx_min_sz, void *data, + unsigned int *updates) +{ + u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8)); + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ + tpm_u32(17 + idx_array_sz), /* Length */ + tpm_u32(TPM2_CC_PCR_READ), /* Command code */ + + /* TPML_PCR_SELECTION */ + tpm_u32(1), /* Number of selections */ + tpm_u16(TPM2_ALG_SHA256), /* Algorithm of the hash */ + idx_array_sz, /* Array size for selection */ + /* bitmap(idx) Selected PCR bitmap */ + }; + size_t response_len = COMMAND_BUFFER_SIZE; + u8 response[COMMAND_BUFFER_SIZE]; + unsigned int pcr_sel_idx = idx / 8; + u8 pcr_sel_bit = BIT(idx % 8); + unsigned int counter = 0; + int ret; + + if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b", + 17 + pcr_sel_idx, pcr_sel_bit)) + return TPM_LIB_ERROR; + + ret = tpm_sendrecv_command(command_v2, response, &response_len); + if (ret) + return ret; + + if (unpack_byte_string(response, response_len, "ds", + 10, &counter, + response_len - TPM2_DIGEST_LEN, data, + TPM2_DIGEST_LEN)) + return TPM_LIB_ERROR; + + if (updates) + *updates = counter; + + return 0; +} + +u32 tpm2_get_capability(u32 capability, u32 property, void *buf, + size_t prop_count) +{ + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ + tpm_u32(22), /* Length */ + tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */ + + tpm_u32(capability), /* Capability */ + tpm_u32(property), /* Property */ + tpm_u32(prop_count), /* Property count */ + }; + u8 response[COMMAND_BUFFER_SIZE]; + size_t response_len = COMMAND_BUFFER_SIZE; + unsigned int properties_off; + int ret; + + ret = tpm_sendrecv_command(command_v2, response, &response_len); + if (ret) + return ret; + + /* + * In the response buffer, the properties are located after the: + * tag (u16), response size (u32), response code (u32), + * YES/NO flag (u8), TPM_CAP (u32) and TPMU_CAPABILITIES (u32). + */ + properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) + + sizeof(u8) + sizeof(u32) + sizeof(u32); + memcpy(buf, &response[properties_off], response_len - properties_off); + + return 0; +} + +u32 tpm2_dam_reset(const char *pw, const ssize_t pw_sz) +{ + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(27 + pw_sz), /* Length */ + tpm_u32(TPM2_CC_DAM_RESET), /* Command code */ + + /* HANDLE */ + tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */ + + /* AUTH_SESSION */ + tpm_u32(9 + pw_sz), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* Session handle */ + tpm_u16(0), /* Size of <nonce> */ + /* <nonce> (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(pw_sz), /* Size of <hmac/password> */ + /* STRING(pw) <hmac/password> (if any) */ + }; + unsigned int offset = 27; + int ret; + + /* + * Fill the command structure starting from the first buffer: + * - the password (if any) + */ + ret = pack_byte_string(command_v2, sizeof(command_v2), "s", + offset, pw, pw_sz); + offset += pw_sz; + if (ret) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(command_v2, NULL, NULL); +} + +u32 tpm2_dam_parameters(const char *pw, const ssize_t pw_sz, + unsigned int max_tries, unsigned int recovery_time, + unsigned int lockout_recovery) +{ + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(27 + pw_sz + 12), /* Length */ + tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */ + + /* HANDLE */ + tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */ + + /* AUTH_SESSION */ + tpm_u32(9 + pw_sz), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* Session handle */ + tpm_u16(0), /* Size of <nonce> */ + /* <nonce> (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(pw_sz), /* Size of <hmac/password> */ + /* STRING(pw) <hmac/password> (if any) */ + + /* LOCKOUT PARAMETERS */ + /* tpm_u32(max_tries) Max tries (0, always lock) */ + /* tpm_u32(recovery_time) Recovery time (0, no lock) */ + /* tpm_u32(lockout_recovery) Lockout recovery */ + }; + unsigned int offset = 27; + int ret; + + /* + * Fill the command structure starting from the first buffer: + * - the password (if any) + * - max tries + * - recovery time + * - lockout recovery + */ + ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd", + offset, pw, pw_sz, + offset + pw_sz, max_tries, + offset + pw_sz + 4, recovery_time, + offset + pw_sz + 8, lockout_recovery); + offset += pw_sz + 12; + if (ret) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(command_v2, NULL, NULL); +} + +int tpm2_change_auth(u32 handle, const char *newpw, const ssize_t newpw_sz, + const char *oldpw, const ssize_t oldpw_sz) +{ + unsigned int offset = 27; + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */ + tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */ + + /* HANDLE */ + tpm_u32(handle), /* TPM resource handle */ + + /* AUTH_SESSION */ + tpm_u32(9 + oldpw_sz), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* Session handle */ + tpm_u16(0), /* Size of <nonce> */ + /* <nonce> (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(oldpw_sz) /* Size of <hmac/password> */ + /* STRING(oldpw) <hmac/password> (if any) */ + + /* TPM2B_AUTH (TPM2B_DIGEST) */ + /* tpm_u16(newpw_sz) Digest size, new pw length */ + /* STRING(newpw) Digest buffer, new pw */ + }; + int ret; + + /* + * Fill the command structure starting from the first buffer: + * - the old password (if any) + * - size of the new password + * - new password + */ + ret = pack_byte_string(command_v2, sizeof(command_v2), "sws", + offset, oldpw, oldpw_sz, + offset + oldpw_sz, newpw_sz, + offset + oldpw_sz + 2, newpw, newpw_sz); + offset += oldpw_sz + 2 + newpw_sz; + if (ret) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(command_v2, NULL, NULL); +} + +u32 tpm2_pcr_setauthpolicy(const char *pw, const ssize_t pw_sz, u32 index, + const char *key) +{ + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */ + tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */ + + /* HANDLE */ + tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */ + + /* AUTH_SESSION */ + tpm_u32(9 + pw_sz), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* session handle */ + tpm_u16(0), /* Size of <nonce> */ + /* <nonce> (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(pw_sz) /* Size of <hmac/password> */ + /* STRING(pw) <hmac/password> (if any) */ + + /* TPM2B_AUTH (TPM2B_DIGEST) */ + /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */ + /* STRING(key) Digest buffer (PCR key) */ + + /* TPMI_ALG_HASH */ + /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */ + + /* TPMI_DH_PCR */ + /* tpm_u32(index), PCR Index */ + }; + unsigned int offset = 27; + int ret; + + /* + * Fill the command structure starting from the first buffer: + * - the password (if any) + * - the PCR key length + * - the PCR key + * - the hash algorithm + * - the PCR index + */ + ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd", + offset, pw, pw_sz, + offset + pw_sz, TPM2_DIGEST_LEN, + offset + pw_sz + 2, key, TPM2_DIGEST_LEN, + offset + pw_sz + 2 + TPM2_DIGEST_LEN, + TPM2_ALG_SHA256, + offset + pw_sz + 4 + TPM2_DIGEST_LEN, index); + offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4; + if (ret) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(command_v2, NULL, NULL); +} + +u32 tpm2_pcr_setauthvalue(const char *pw, const ssize_t pw_sz, u32 index, + const char *key, const ssize_t key_sz) +{ + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */ + tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */ + + /* HANDLE */ + tpm_u32(index), /* Handle (PCR Index) */ + + /* AUTH_SESSION */ + tpm_u32(9 + pw_sz), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* session handle */ + tpm_u16(0), /* Size of <nonce> */ + /* <nonce> (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(pw_sz), /* Size of <hmac/password> */ + /* STRING(pw) <hmac/password> (if any) */ + + /* TPM2B_DIGEST */ + /* tpm_u16(key_sz) Key length */ + /* STRING(key) Key */ + }; + unsigned int offset = 27; + int ret; + + /* + * Fill the command structure starting from the first buffer: + * - the password (if any) + * - the number of digests, 1 in our case + * - the algorithm, sha256 in our case + * - the digest (64 bytes) + */ + ret = pack_byte_string(command_v2, sizeof(command_v2), "sws", + offset, pw, pw_sz, + offset + pw_sz, key_sz, + offset + pw_sz + 2, key, key_sz); + offset += pw_sz + 2 + key_sz; + if (ret) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(command_v2, NULL, NULL); +} diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 83277981792..705ed89a659 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -47,7 +47,6 @@ CONFIG_ARCH_RMOBILE_EXTRAM_BOOT CONFIG_ARCH_TEGRA CONFIG_ARCH_USE_BUILTIN_BSWAP CONFIG_ARC_MMU_VER -CONFIG_ARC_SERIAL CONFIG_ARIES_M28_V10 CONFIG_ARMADA100 CONFIG_ARMADA100_FEC @@ -1334,7 +1333,6 @@ CONFIG_MTD_UBI_MODULE CONFIG_MULTI_CS CONFIG_MUSB_HOST CONFIG_MVEBU_MMC -CONFIG_MVGBE CONFIG_MVGBE_PORTS CONFIG_MVMFP_V2 CONFIG_MVS @@ -2033,7 +2031,6 @@ CONFIG_SUNXI_MAX_FB_SIZE CONFIG_SUNXI_USB_PHYS CONFIG_SUPERH_ON_CHIP_R8A66597 CONFIG_SUPPORT_EMMC_BOOT -CONFIG_SUPPORT_EMMC_RPMB CONFIG_SUVD3 CONFIG_SXNI855T CONFIG_SYSFLAGS_ADDR @@ -4549,7 +4546,6 @@ CONFIG_TSECV2 CONFIG_TSECV2_1 CONFIG_TSEC_TBI CONFIG_TSEC_TBICR_SETTINGS -CONFIG_TSI108_ETH_NUM_PORTS CONFIG_TUGE1 CONFIG_TULIP CONFIG_TULIP_FIX_DAVICOM diff --git a/scripts/decodecode b/scripts/decodecode new file mode 100755 index 00000000000..9cef558528a --- /dev/null +++ b/scripts/decodecode @@ -0,0 +1,125 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# Disassemble the Code: line in Linux oopses +# usage: decodecode < oops.file +# +# options: set env. variable AFLAGS=options to pass options to "as"; +# e.g., to decode an i386 oops on an x86_64 system, use: +# AFLAGS=--32 decodecode < 386.oops + +cleanup() { + rm -f $T $T.s $T.o $T.oo $T.aa $T.dis + exit 1 +} + +die() { + echo "$@" + exit 1 +} + +trap cleanup EXIT + +T=`mktemp` || die "cannot create temp file" +code= +cont= + +while read i ; do + +case "$i" in +*Code:*) + code=$i + cont=yes + ;; +*) + [ -n "$cont" ] && { + xdump="$(echo $i | grep '^[[:xdigit:]<>[:space:]]\+$')" + if [ -n "$xdump" ]; then + code="$code $xdump" + else + cont= + fi + } + ;; +esac + +done + +if [ -z "$code" ]; then + rm $T + exit +fi + +echo $code +code=`echo $code | sed -e 's/.*Code: //'` + +width=`expr index "$code" ' '` +width=$((($width-1)/2)) +case $width in +1) type=byte ;; +2) type=2byte ;; +4) type=4byte ;; +esac + +disas() { + ${CROSS_COMPILE}as $AFLAGS -o $1.o $1.s > /dev/null 2>&1 + + if [ "$ARCH" = "arm" ]; then + if [ $width -eq 2 ]; then + OBJDUMPFLAGS="-M force-thumb" + fi + + ${CROSS_COMPILE}strip $1.o + fi + + if [ "$ARCH" = "arm64" ]; then + if [ $width -eq 4 ]; then + type=inst + fi + + ${CROSS_COMPILE}strip $1.o + fi + + ${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $1.o | \ + grep -v "/tmp\|Disassembly\|\.text\|^$" > $1.dis 2>&1 +} + +marker=`expr index "$code" "\<"` +if [ $marker -eq 0 ]; then + marker=`expr index "$code" "\("` +fi + +touch $T.oo +if [ $marker -ne 0 ]; then + echo All code >> $T.oo + echo ======== >> $T.oo + beforemark=`echo "$code"` + echo -n " .$type 0x" > $T.s + echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s + disas $T + cat $T.dis >> $T.oo + rm -f $T.o $T.s $T.dis + +# and fix code at-and-after marker + code=`echo "$code" | cut -c$((${marker} + 1))-` +fi +echo Code starting with the faulting instruction > $T.aa +echo =========================================== >> $T.aa +code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'` +echo -n " .$type 0x" > $T.s +echo $code >> $T.s +disas $T +cat $T.dis >> $T.aa + +# (lines of whole $T.oo) - (lines of $T.aa, i.e. "Code starting") + 3, +# i.e. the title + the "===..=" line (sed is counting from 1, 0 address is +# special) +faultlinenum=$(( $(wc -l $T.oo | cut -d" " -f1) - \ + $(wc -l $T.aa | cut -d" " -f1) + 3)) + +faultline=`cat $T.dis | head -1 | cut -d":" -f2-` +faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'` + +cat $T.oo | sed -e "${faultlinenum}s/^\(.*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/" +echo +cat $T.aa +cleanup diff --git a/scripts/dtc/pylibfdt/Makefile b/scripts/dtc/pylibfdt/Makefile index 01d5e0ffe30..c769d7db062 100644 --- a/scripts/dtc/pylibfdt/Makefile +++ b/scripts/dtc/pylibfdt/Makefile @@ -14,7 +14,8 @@ PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) \ $(obj)/libfdt.i quiet_cmd_pymod = PYMOD $@ - cmd_pymod = unset CC; unset CROSS_COMPILE; unset CFLAGS;\ + cmd_pymod = unset CROSS_COMPILE; unset CFLAGS; \ + CC="$(HOSTCC)" LDSHARED="$(HOSTCC) -shared " \ LDFLAGS="$(HOSTLDFLAGS)" \ VERSION="u-boot-$(UBOOTVERSION)" \ CPPFLAGS="$(HOSTCFLAGS) -I$(LIBFDT_srcdir)" OBJDIR=$(obj) \ diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index b6b9461a107..2e8d5ee4df9 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -223,6 +223,8 @@ setenv bind 'if test "\$sb" != sb; then sb bind 0 "$1"; fi' run bind # Test Case 1 - ls ${PREFIX}ls host${SUFFIX} $6 +# In addition, test with a nonexistent directory to see if we crash. +${PREFIX}ls host${SUFFIX} invalid_d # # We want ${PREFIX}size host 0:0 $3 for host commands and # sb size hostfs - $3 for hostfs commands. diff --git a/test/py/tests/test_tpm2.py b/test/py/tests/test_tpm2.py new file mode 100644 index 00000000000..01ffb3178db --- /dev/null +++ b/test/py/tests/test_tpm2.py @@ -0,0 +1,233 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2018, Bootlin +# Author: Miquel Raynal <miquel.raynal@bootlin.com> + +import os.path +import pytest +import u_boot_utils +import re +import time + +""" +Test the TPMv2.x related commands. You must have a working hardware setup in +order to do these tests. + +Notes: +* These tests will prove the password mechanism. The TPM chip must be cleared of +any password. +* Commands like pcr_setauthpolicy and pcr_resetauthpolicy are not implemented +here because they would fail the tests in most cases (TPMs do not implement them +and return an error). +""" + +updates = 0 + +def force_init(u_boot_console, force=False): + """When a test fails, U-Boot is reset. Because TPM stack must be initialized + after each reboot, we must ensure these lines are always executed before + trying any command or they will fail with no reason. Executing 'tpm init' + twice will spawn an error used to detect that the TPM was not reset and no + initialization code should be run. + """ + output = u_boot_console.run_command('tpm init') + if force or not 'Error' in output: + u_boot_console.run_command('echo --- start of init ---') + u_boot_console.run_command('tpm startup TPM2_SU_CLEAR') + u_boot_console.run_command('tpm self_test full') + u_boot_console.run_command('tpm clear TPM2_RH_LOCKOUT') + output = u_boot_console.run_command('echo $?') + if not output.endswith('0'): + u_boot_console.run_command('tpm clear TPM2_RH_PLATFORM') + u_boot_console.run_command('echo --- end of init ---') + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_init(u_boot_console): + """Init the software stack to use TPMv2 commands.""" + + u_boot_console.run_command('tpm init') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_startup(u_boot_console): + """Execute a TPM2_Startup command. + + Initiate the TPM internal state machine. + """ + + u_boot_console.run_command('tpm startup TPM2_SU_CLEAR') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_self_test_full(u_boot_console): + """Execute a TPM2_SelfTest (full) command. + + Ask the TPM to perform all self tests to also enable full capabilities. + """ + + u_boot_console.run_command('tpm self_test full') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_continue_self_test(u_boot_console): + """Execute a TPM2_SelfTest (continued) command. + + Ask the TPM to finish its self tests (alternative to the full test) in order + to enter a fully operational state. + """ + + u_boot_console.run_command('tpm self_test continue') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_clear(u_boot_console): + """Execute a TPM2_Clear command. + + Ask the TPM to reset entirely its internal state (including internal + configuration, passwords, counters and DAM parameters). This is half of the + TAKE_OWNERSHIP command from TPMv1. + + Use the LOCKOUT hierarchy for this. The LOCKOUT/PLATFORM hierarchies must + not have a password set, otherwise this test will fail. ENDORSEMENT and + PLATFORM hierarchies are also available. + """ + + u_boot_console.run_command('tpm clear TPM2_RH_LOCKOUT') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + + u_boot_console.run_command('tpm clear TPM2_RH_PLATFORM') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_change_auth(u_boot_console): + """Execute a TPM2_HierarchyChangeAuth command. + + Ask the TPM to change the owner, ie. set a new password: 'unicorn' + + Use the LOCKOUT hierarchy for this. ENDORSEMENT and PLATFORM hierarchies are + also available. + """ + + force_init(u_boot_console) + + u_boot_console.run_command('tpm change_auth TPM2_RH_LOCKOUT unicorn') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + + u_boot_console.run_command('tpm clear TPM2_RH_LOCKOUT unicorn') + output = u_boot_console.run_command('echo $?') + u_boot_console.run_command('tpm clear TPM2_RH_PLATFORM') + assert output.endswith('0') + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_get_capability(u_boot_console): + """Execute a TPM_GetCapability command. + + Display one capability. In our test case, let's display the default DAM + lockout counter that should be 0 since the CLEAR: + - TPM_CAP_TPM_PROPERTIES = 0x6 + - TPM_PT_LOCKOUT_COUNTER (1st parameter) = PTR_VAR + 14 + + There is no expected default values because it would depend on the chip + used. We can still save them in order to check they have changed later. + """ + + force_init(u_boot_console) + ram = u_boot_utils.find_ram_base(u_boot_console) + + read_cap = u_boot_console.run_command('tpm get_capability 0x6 0x20e 0x200 1') #0x%x 1' % ram) + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + assert 'Property 0x0000020e: 0x00000000' in read_cap + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_dam_parameters(u_boot_console): + """Execute a TPM2_DictionaryAttackParameters command. + + Change Dictionary Attack Mitigation (DAM) parameters. Ask the TPM to change: + - Max number of failed authentication before lockout: 3 + - Time before the failure counter is automatically decremented: 10 sec + - Time after a lockout failure before it can be attempted again: 0 sec + + For an unknown reason, the DAM parameters must be changed before changing + the authentication, otherwise the lockout will be engaged after the first + failed authentication attempt. + """ + + force_init(u_boot_console) + ram = u_boot_utils.find_ram_base(u_boot_console) + + # Set the DAM parameters to known values + u_boot_console.run_command('tpm dam_parameters 3 10 0') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + + # Check the values have been saved + read_cap = u_boot_console.run_command('tpm get_capability 0x6 0x20f 0x%x 3' % ram) + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + assert 'Property 0x0000020f: 0x00000003' in read_cap + assert 'Property 0x00000210: 0x0000000a' in read_cap + assert 'Property 0x00000211: 0x00000000' in read_cap + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_pcr_read(u_boot_console): + """Execute a TPM2_PCR_Read command. + + Perform a PCR read of the 0th PCR. Must be zero. + """ + + force_init(u_boot_console) + ram = u_boot_utils.find_ram_base(u_boot_console) + 1024 + + read_pcr = u_boot_console.run_command('tpm pcr_read 0 0x%x' % ram) + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + + # Save the number of PCR updates + str = re.findall(r'\d+ known updates', read_pcr)[0] + global updates + updates = int(re.findall(r'\d+', str)[0]) + + # Check the output value + assert 'PCR #0 content' in read_pcr + assert '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' in read_pcr + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_pcr_extend(u_boot_console): + """Execute a TPM2_PCR_Extend command. + + Perform a PCR extension with a known hash in memory (zeroed since the board + must have been rebooted). + + No authentication mechanism is used here, not protecting against packet + replay, yet. + """ + + force_init(u_boot_console) + ram = u_boot_utils.find_ram_base(u_boot_console) + 1024 + + u_boot_console.run_command('tpm pcr_extend 0 0x%x' % ram) + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + + read_pcr = u_boot_console.run_command('tpm pcr_read 0 0x%x' % ram) + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + assert 'f5 a5 fd 42 d1 6a 20 30 27 98 ef 6e d3 09 97 9b' in read_pcr + assert '43 00 3d 23 20 d9 f0 e8 ea 98 31 a9 27 59 fb 4b' in read_pcr + + str = re.findall(r'\d+ known updates', read_pcr)[0] + new_updates = int(re.findall(r'\d+', str)[0]) + assert (updates + 1) == new_updates + +@pytest.mark.buildconfigspec('cmd_tpm_v2') +def test_tpm2_cleanup(u_boot_console): + """Ensure the TPM is cleared from password or test related configuration.""" + + force_init(u_boot_console, True) diff --git a/tools/buildman/toolchain.py b/tools/buildman/toolchain.py index fb3157b2ea8..4b35f400e97 100644 --- a/tools/buildman/toolchain.py +++ b/tools/buildman/toolchain.py @@ -32,7 +32,7 @@ class MyHTMLParser(HTMLParser): HTMLParser.__init__(self) self.arch_link = None self.links = [] - self._match = '_%s-' % arch + self.re_arch = re.compile('[-_]%s-' % arch) def handle_starttag(self, tag, attrs): if tag == 'a': @@ -40,7 +40,7 @@ class MyHTMLParser(HTMLParser): if tag == 'href': if value and value.endswith('.xz'): self.links.append(value) - if self._match in value: + if self.re_arch.search(value): self.arch_link = value @@ -430,7 +430,7 @@ class Toolchains: """ arch = command.OutputOneLine('uname', '-m') base = 'https://www.kernel.org/pub/tools/crosstool/files/bin' - versions = ['4.9.0', '4.6.3', '4.6.2', '4.5.1', '4.2.4'] + versions = ['7.3.0', '6.4.0', '4.9.4'] links = [] for version in versions: url = '%s/%s/%s/' % (base, arch, version) |