diff options
45 files changed, 2412 insertions, 267 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000000..e27d86f9628 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,361 @@ +# SPDX-License-Identifier: GPL-2.0+ + +# Grab our configured image. The source for this is found at: +# https://gitlab.denx.de/u-boot/gitlab-ci-runner +image: trini/u-boot-gitlab-ci-runner:xenial-20190222-24April2019 + +# We run some tests in different order, to catch some failures quicker. +stages: + - test.py + - testsuites + - world build + +.buildman_and_testpy_template: &buildman_and_testpy_dfn + tags: [ 'all' ] + stage: test.py + before_script: + # Clone uboot-test-hooks + - git clone --depth=1 git://github.com/swarren/uboot-test-hooks.git /tmp/uboot-test-hooks + - ln -s travis-ci /tmp/uboot-test-hooks/bin/`hostname` + - ln -s travis-ci /tmp/uboot-test-hooks/py/`hostname` + - virtualenv /tmp/venv + - . /tmp/venv/bin/activate + - pip install pytest==2.8.7 + - pip install python-subunit + - grub-mkimage -o ~/grub_x86.efi -O i386-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd + - grub-mkimage -o ~/grub_x64.efi -O x86_64-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd + - mkdir ~/grub2-arm + - ( cd ~/grub2-arm; wget -O - http://download.opensuse.org/ports/armv7hl/distribution/leap/42.2/repo/oss/suse/armv7hl/grub2-arm-efi-2.02~beta2-87.1.armv7hl.rpm | rpm2cpio | cpio -di ) + - mkdir ~/grub2-arm64 + - ( cd ~/grub2-arm64; wget -O - http://download.opensuse.org/ports/aarch64/distribution/leap/42.2/repo/oss/suse/aarch64/grub2-arm64-efi-2.02~beta2-87.1.aarch64.rpm | rpm2cpio | cpio -di ) + - if [[ "${QEMU_TARGET}" != "" ]]; then + git clone git://git.qemu.org/qemu.git /tmp/qemu; + pushd /tmp/qemu; + git submodule update --init dtc && + git checkout ${QEMU_VERSION} && + ./configure --prefix=/tmp/qemu-install --target-list=${QEMU_TARGET} && + make -j$(nproc) all install; + popd; + fi + after_script: + - rm -rf ~/grub2* /tmp/uboot-test-hooks /tmp/qemu /tmp/venv + script: + # From buildman, exit code 129 means warnings only. If we've been asked to + # use clang only do one configuration. + - if [[ "${BUILDMAN}" != "" ]]; then + ret=0; + tools/buildman/buildman -P -E ${BUILDMAN} ${OVERRIDE}|| ret=$?; + if [[ $ret -ne 0 && $ret -ne 129 ]]; then + tools/buildman/buildman -sdeP ${BUILDMAN}; + exit $ret; + fi; + fi + # "not a_test_which_does_not_exist" is a dummy -k parameter which will + # never prevent any test from running. That way, we can always pass + # "-k something" even when $TEST_PY_TEST_SPEC doesnt need a custom + # value. + - export UBOOT_TRAVIS_BUILD_DIR=`cd .. && pwd`/.bm-work/${TEST_PY_BD}; + export PATH=/tmp/qemu-install/bin:/tmp/uboot-test-hooks/bin:/usr/bin:/bin; + export PYTHONPATH=/tmp/uboot-test-hooks/py/travis-ci; + if [[ "${TEST_PY_BD}" != "" ]]; then + ./test/py/test.py --bd ${TEST_PY_BD} ${TEST_PY_ID} + -k "${TEST_PY_TEST_SPEC:-not a_test_which_does_not_exist}" + --build-dir "$UBOOT_TRAVIS_BUILD_DIR"; + ret=$?; + if [[ $ret -ne 0 ]]; then + exit $ret; + fi; + fi; + +build all 32bit ARM plaforms: + tags: [ 'all' ] + stage: world build + script: + - ret=0; + ./tools/buildman/buildman -P -E arm -x aarch64 || ret=$?; + if [[ $ret -ne 0 && $ret -ne 129 ]]; then + ./tools/buildman/buildman -sdeP; + exit $ret; + fi; + +build all 64bit ARM plaforms: + tags: [ 'all' ] + stage: world build + script: + - virtualenv /tmp/venv + - . /tmp/venv/bin/activate + - pip install pyelftools + - ret=0; + ./tools/buildman/buildman -P -E aarch64 || ret=$?; + if [[ $ret -ne 0 && $ret -ne 129 ]]; then + ./tools/buildman/buildman -sdeP; + exit $ret; + fi; + +build all PowerPC plaforms: + tags: [ 'all' ] + stage: world build + script: + - ret=0; + ./tools/buildman/buildman -P -E powerpc || ret=$?; + if [[ $ret -ne 0 && $ret -ne 129 ]]; then + ./tools/buildman/buildman -sdeP; + exit $ret; + fi; + +build all other plaforms: + tags: [ 'all' ] + stage: world build + script: + - ret=0; + ./tools/buildman/buildman -P -E -x arm,powerpc || ret=$?; + if [[ $ret -ne 0 && $ret -ne 129 ]]; then + ./tools/buildman/buildman -sdeP; + exit $ret; + fi; + +# QA jobs for code analytics +# static code analysis with cppcheck (we can add --enable=all later) +cppcheck: + tags: [ 'all' ] + stage: testsuites + script: + - cppcheck --force --quiet --inline-suppr . + +# search for TODO within source tree +grep TODO/FIXME/HACK: + tags: [ 'all' ] + stage: testsuites + script: + - grep -r TODO . + - grep -r FIXME . + # search for HACK within source tree and ignore HACKKIT board + - grep -r HACK . | grep -v HACKKIT + +# some statistics about the code base +sloccount: + tags: [ 'all' ] + stage: testsuites + script: + - sloccount . + +# ensure all configs have MAINTAINERS entries +Check for configs without MAINTAINERS entry: + tags: [ 'all' ] + stage: testsuites + script: + - if [ `./tools/genboardscfg.py -f 2>&1 | wc -l` -ne 0 ]; then exit 1; fi + +# Ensure host tools build +Build tools-only: + tags: [ 'all' ] + stage: testsuites + script: + - make tools-only_config tools-only -j$(nproc) + +# Run various tool tests +Run patman testsuite: + tags: [ 'all' ] + stage: testsuites + script: + - git config --global user.name "GitLab CI Runner" + - git config --global user.email trini@konsulko.com + - ./tools/patman/patman --test + +Run buildman testsuite: + tags: [ 'all' ] + stage: testsuites + script: + - ./tools/buildman/buildman -t + +Run binman and dtoc testsuite: + tags: [ 'all' ] + stage: testsuites + script: + - export UBOOT_TRAVIS_BUILD_DIR=`cd .. && pwd`/.bm-work/sandbox_spl; + ./tools/buildman/buildman -P sandbox_spl && + export PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt"; + export PATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}"; + ./tools/binman/binman -t && + ./tools/dtoc/dtoc -t + +# Test sandbox with test.py +sandbox test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "sandbox" + BUILDMAN: "^sandbox$" + <<: *buildman_and_testpy_dfn + +sandbox_spl test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "sandbox_spl" + BUILDMAN: "^sandbox_spl$" + TEST_PY_TEST_SPEC: "test_ofplatdata" + <<: *buildman_and_testpy_dfn + +evb-ast2500 test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "evb-ast2500" + TEST_PY_ID: "--id qemu" + QEMU_TARGET: "arm-softmmu" + QEMU_VERSION: "506179e42112be77bfd071f050b15762d3b2cd43" + BUILDMAN: "^evb-ast2500$" + <<: *buildman_and_testpy_dfn + +sandbox_flattree test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "sandbox_flattree" + BUILDMAN: "^sandbox_flattree$" + <<: *buildman_and_testpy_dfn + +vexpress_ca15_tc2 test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "vexpress_ca15_tc2" + TEST_PY_ID: "--id qemu" + QEMU_TARGET: "arm-softmmu" + QEMU_VERSION: "v3.0.0" + BUILDMAN: "^vexpress_ca15_tc2$" + <<: *buildman_and_testpy_dfn + +vexpress_ca9x4 test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "vexpress_ca9x4" + TEST_PY_ID: "--id qemu" + QEMU_TARGET: "arm-softmmu" + BUILDMAN: "^vexpress_ca9x4$" + <<: *buildman_and_testpy_dfn + +integratorcp_cm926ejs test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "integratorcp_cm926ejs" + TEST_PY_TEST_SPEC: "not sleep" + TEST_PY_ID: "--id qemu" + QEMU_TARGET: "arm-softmmu" + BUILDMAN: "^integratorcp_cm926ejs$" + <<: *buildman_and_testpy_dfn + +qemu_arm test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "qemu_arm" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "arm-softmmu" + BUILDMAN: "^qemu_arm$" + <<: *buildman_and_testpy_dfn + +qemu_arm64 test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "qemu_arm64" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "aarch64-softmmu" + BUILDMAN: "^qemu_arm64$" + <<: *buildman_and_testpy_dfn + +qemu_mips test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "qemu_mips" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "mips-softmmu" + BUILDMAN: "^qemu_mips$" + TOOLCHAIN: "mips" + <<: *buildman_and_testpy_dfn + +qemu_mipsel test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "qemu_mipsel" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "mipsel-softmmu" + BUILDMAN: "^qemu_mipsel$" + TOOLCHAIN: "mips" + <<: *buildman_and_testpy_dfn + +qemu_mips64 test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "qemu_mips64" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "mips64-softmmu" + BUILDMAN: "^qemu_mips64$" + TOOLCHAIN: "mips" + <<: *buildman_and_testpy_dfn + +qemu_mips64el test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "qemu_mips64el" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "mips64el-softmmu" + BUILDMAN: "^qemu_mips64el$" + TOOLCHAIN: "mips" + <<: *buildman_and_testpy_dfn + +qemu-ppce500 test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "qemu-ppce500" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "ppc-softmmu" + BUILDMAN: "^qemu-ppce500$" + TOOLCHAIN: "powerpc" + <<: *buildman_and_testpy_dfn + +qemu-x86 test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "qemu-x86" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "i386-softmmu" + BUILDMAN: "^qemu-x86$" + TOOLCHAIN: "i386" + <<: *buildman_and_testpy_dfn + +qemu-x86_64 test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "qemu-x86_64" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "x86_64-softmmu" + BUILDMAN: "^qemu-x86_64$" + TOOLCHAIN: "i386" + <<: *buildman_and_testpy_dfn + +zynq_zc702 test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "zynq_zc702" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "arm-softmmu" + TEST_PY_ID: "--id qemu" + BUILDMAN: "^zynq_zc702$" + <<: *buildman_and_testpy_dfn + +xilinx_versal_virt test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "xilinx_versal_virt" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "aarch64-softmmu" + TEST_PY_ID: "--id qemu" + BUILDMAN: "^xilinx_versal_virt$" + <<: *buildman_and_testpy_dfn + +xtfpga test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "xtfpga" + TEST_PY_TEST_SPEC: "not sleep" + QEMU_TARGET: "xtensa-softmmu" + TEST_PY_ID: "--id qemu" + BUILDMAN: "^xtfpga$" + TOOLCHAIN: "xtensa-dc233c-elf" + <<: *buildman_and_testpy_dfn diff --git a/.travis.yml b/.travis.yml index 6662ca126ab..f20268bde35 100644 --- a/.travis.yml +++ b/.travis.yml @@ -384,6 +384,13 @@ matrix: - TEST_PY_BD="sandbox_flattree" BUILDMAN="^sandbox_flattree$" TOOLCHAIN="i386" + - name: "test/py evb-ast2500" + env: + - TEST_PY_BD="evb-ast2500" + TEST_PY_ID="--id qemu" + QEMU_TARGET="arm-softmmu" + QEMU_VERSION="506179e42112be77bfd071f050b15762d3b2cd43" + BUILDMAN="^evb-ast2500$" - name: "test/py vexpress_ca15_tc2" env: - TEST_PY_BD="vexpress_ca15_tc2" diff --git a/arch/arm/dts/k3-am65-main.dtsi b/arch/arm/dts/k3-am65-main.dtsi index adcd6341e40..39fec03b4a9 100644 --- a/arch/arm/dts/k3-am65-main.dtsi +++ b/arch/arm/dts/k3-am65-main.dtsi @@ -69,4 +69,78 @@ clock-frequency = <48000000>; current-speed = <115200>; }; + + main_pmx0: pinmux@11c000 { + compatible = "pinctrl-single"; + reg = <0x0 0x11c000 0x0 0x2e4>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + main_pmx1: pinmux@11c2e8 { + compatible = "pinctrl-single"; + reg = <0x0 0x11c2e8 0x0 0x24>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + sdhci0: sdhci@4f80000 { + compatible = "ti,am654-sdhci-5.1"; + reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>; + power-domains = <&k3_pds 47>; + clocks = <&k3_clks 47 0>, <&k3_clks 47 1>; + clock-names = "clk_ahb", "clk_xin"; + interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + ti,otap-del-sel = <0x2>; + ti,trm-icp = <0x8>; + dma-coherent; + }; + + main_i2c0: i2c@2000000 { + compatible = "ti,am654-i2c", "ti,omap4-i2c"; + reg = <0x0 0x2000000 0x0 0x100>; + interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "fck"; + clocks = <&k3_clks 110 1>; + power-domains = <&k3_pds 110>; + }; + + main_i2c1: i2c@2010000 { + compatible = "ti,am654-i2c", "ti,omap4-i2c"; + reg = <0x0 0x2010000 0x0 0x100>; + interrupts = <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "fck"; + clocks = <&k3_clks 111 1>; + power-domains = <&k3_pds 111>; + }; + + main_i2c2: i2c@2020000 { + compatible = "ti,am654-i2c", "ti,omap4-i2c"; + reg = <0x0 0x2020000 0x0 0x100>; + interrupts = <GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "fck"; + clocks = <&k3_clks 112 1>; + power-domains = <&k3_pds 112>; + }; + + main_i2c3: i2c@2030000 { + compatible = "ti,am654-i2c", "ti,omap4-i2c"; + reg = <0x0 0x2030000 0x0 0x100>; + interrupts = <GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "fck"; + clocks = <&k3_clks 113 1>; + power-domains = <&k3_pds 113>; + }; }; diff --git a/arch/arm/dts/k3-am65-mcu.dtsi b/arch/arm/dts/k3-am65-mcu.dtsi index 8c611d16df4..1fd027748e1 100644 --- a/arch/arm/dts/k3-am65-mcu.dtsi +++ b/arch/arm/dts/k3-am65-mcu.dtsi @@ -15,4 +15,15 @@ clock-frequency = <96000000>; current-speed = <115200>; }; + + mcu_i2c0: i2c@40b00000 { + compatible = "ti,am654-i2c", "ti,omap4-i2c"; + reg = <0x0 0x40b00000 0x0 0x100>; + interrupts = <GIC_SPI 564 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "fck"; + clocks = <&k3_clks 114 1>; + power-domains = <&k3_pds 114>; + }; }; diff --git a/arch/arm/dts/k3-am65-wakeup.dtsi b/arch/arm/dts/k3-am65-wakeup.dtsi index 1f591ef8bb9..1f85006f557 100644 --- a/arch/arm/dts/k3-am65-wakeup.dtsi +++ b/arch/arm/dts/k3-am65-wakeup.dtsi @@ -34,6 +34,14 @@ }; }; + wkup_pmx0: pinmux@4301c000 { + compatible = "pinctrl-single"; + reg = <0x4301c000 0x118>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + wkup_uart0: serial@42300000 { compatible = "ti,am654-uart"; reg = <0x42300000 0x100>; @@ -43,4 +51,15 @@ clock-frequency = <48000000>; current-speed = <115200>; }; + + wkup_i2c0: i2c@42120000 { + compatible = "ti,am654-i2c", "ti,omap4-i2c"; + reg = <0x42120000 0x100>; + interrupts = <GIC_SPI 696 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "fck"; + clocks = <&k3_clks 115 1>; + power-domains = <&k3_pds 115>; + }; }; diff --git a/arch/arm/dts/k3-am65.dtsi b/arch/arm/dts/k3-am65.dtsi index 9d1ed497532..47271938b38 100644 --- a/arch/arm/dts/k3-am65.dtsi +++ b/arch/arm/dts/k3-am65.dtsi @@ -8,6 +8,7 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/pinctrl/k3.h> / { model = "Texas Instruments K3 AM654 SoC"; @@ -22,6 +23,12 @@ serial2 = &main_uart0; serial3 = &main_uart1; serial4 = &main_uart2; + i2c0 = &wkup_i2c0; + i2c1 = &mcu_i2c0; + i2c2 = &main_i2c0; + i2c3 = &main_i2c1; + i2c4 = &main_i2c2; + i2c5 = &main_i2c3; }; chosen { }; diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi index 844a5cd96ad..449b1ddd792 100644 --- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi +++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi @@ -21,51 +21,21 @@ &cbass_main{ u-boot,dm-spl; - main_pmx0: pinmux@11c000 { - compatible = "pinctrl-single"; - reg = <0x0 0x11c000 0x0 0x2e4>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0xffffffff>; - }; - - main_pmx1: pinmux@11c2e8 { - compatible = "pinctrl-single"; - reg = <0x0 0x11c2e8 0x0 0x24>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0xffffffff>; - }; - - sdhci0: sdhci@04F80000 { - compatible = "arasan,sdhci-5.1"; - reg = <0x0 0x4F80000 0x0 0x1000>, - <0x0 0x4F90000 0x0 0x400>; - clocks = <&k3_clks 47 1>; - power-domains = <&k3_pds 47>; - max-frequency = <25000000>; - }; - sdhci1: sdhci@04FA0000 { - compatible = "arasan,sdhci-5.1"; + compatible = "ti,am654-sdhci-5.1"; reg = <0x0 0x4FA0000 0x0 0x1000>, <0x0 0x4FB0000 0x0 0x400>; clocks = <&k3_clks 48 1>; power-domains = <&k3_pds 48>; max-frequency = <25000000>; + ti,otap-del-sel = <0x2>; + ti,trm-icp = <0x8>; }; }; &cbass_mcu { u-boot,dm-spl; - wkup_pmx0: pinmux@4301c000 { - compatible = "pinctrl-single"; - reg = <0x0 0x4301c000 0x0 0x118>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0xffffffff>; - }; navss_mcu: navss-mcu { compatible = "simple-bus"; @@ -252,6 +222,14 @@ u-boot,dm-spl; }; +&wkup_pmx0 { + u-boot,dm-spl; + + wkup_i2c0_pins_default { + u-boot,dm-spl; + }; +}; + &main_pmx0 { u-boot,dm-spl; main_uart0_pins_default: main_uart0_pins_default { @@ -276,7 +254,8 @@ AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */ AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */ AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */ - AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */ + AM65X_IOPAD(0x01b4, PIN_INPUT_PULLUP, 0) /* (A23) MMC0_SDCD */ + AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */ >; u-boot,dm-spl; }; @@ -336,11 +315,6 @@ &sdhci0 { u-boot,dm-spl; - status = "okay"; - non-removable; - bus-width = <8>; - pinctrl-names = "default"; - pinctrl-0 = <&main_mmc0_pins_default>; }; &sdhci1 { @@ -349,6 +323,7 @@ pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; sdhci-caps-mask = <0x7 0x0>; + ti,driver-strength-ohm = <50>; }; &mcu_cpsw { @@ -382,3 +357,7 @@ reg-names = "gmii-sel"; }; }; + +&wkup_i2c0 { + u-boot,dm-spl; +}; diff --git a/arch/arm/dts/k3-am654-base-board.dts b/arch/arm/dts/k3-am654-base-board.dts index af6956fdc13..e73b9aa6b1a 100644 --- a/arch/arm/dts/k3-am654-base-board.dts +++ b/arch/arm/dts/k3-am654-base-board.dts @@ -6,6 +6,7 @@ /dts-v1/; #include "k3-am654.dtsi" +#include <dt-bindings/pinctrl/k3.h> / { compatible = "ti,am654-evm", "ti,am654"; @@ -34,3 +35,52 @@ }; }; }; + +&main_pmx0 { + main_mmc0_pins_default: main_mmc0_pins_default { + pinctrl-single,pins = < + AM65X_IOPAD(0x01a8, PIN_INPUT_PULLDOWN, 0) /* (B25) MMC0_CLK */ + AM65X_IOPAD(0x01aC, PIN_INPUT_PULLUP, 0) /* (B27) MMC0_CMD */ + AM65X_IOPAD(0x01a4, PIN_INPUT_PULLUP, 0) /* (A26) MMC0_DAT0 */ + AM65X_IOPAD(0x01a0, PIN_INPUT_PULLUP, 0) /* (E25) MMC0_DAT1 */ + AM65X_IOPAD(0x019c, PIN_INPUT_PULLUP, 0) /* (C26) MMC0_DAT2 */ + AM65X_IOPAD(0x0198, PIN_INPUT_PULLUP, 0) /* (A25) MMC0_DAT3 */ + AM65X_IOPAD(0x0194, PIN_INPUT_PULLUP, 0) /* (E24) MMC0_DAT4 */ + AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */ + AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */ + AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */ + AM65X_IOPAD(0x01b4, PIN_INPUT_PULLUP, 0) /* (A23) MMC0_SDCD */ + AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */ + >; + }; +}; + +&wkup_pmx0 { + wkup_i2c0_pins_default: wkup-i2c0-pins-default { + pinctrl-single,pins = < + AM65X_WKUP_IOPAD(0x00e0, PIN_INPUT, 0) /* (AC7) WKUP_I2C0_SCL */ + AM65X_WKUP_IOPAD(0x00e4, PIN_INPUT, 0) /* (AD6) WKUP_I2C0_SDA */ + >; + }; +}; + +&sdhci0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc0_pins_default>; + bus-width = <8>; + non-removable; + ti,driver-strength-ohm = <50>; +}; + +&wkup_i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&wkup_i2c0_pins_default>; + clock-frequency = <400000>; + + tca9554: gpio@38 { + compatible = "nxp,pca9554"; + reg = <0x38>; + gpio-controller; + #gpio-cells = <2>; + }; +}; diff --git a/arch/arm/dts/k3-am654-r5-base-board.dts b/arch/arm/dts/k3-am654-r5-base-board.dts index a07038be709..9d9b3d58528 100644 --- a/arch/arm/dts/k3-am654-r5-base-board.dts +++ b/arch/arm/dts/k3-am654-r5-base-board.dts @@ -96,6 +96,12 @@ u-boot,dm-spl; }; + clk_200mhz: dummy_clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + u-boot,dm-spl; + }; }; &dmsc { @@ -130,6 +136,32 @@ >; u-boot,dm-spl; }; + + wkup_i2c0_pins_default: wkup-i2c0-pins-default { + pinctrl-single,pins = < + AM65X_WKUP_IOPAD(0x00e0, PIN_INPUT, 0) /* (AC7) WKUP_I2C0_SCL */ + AM65X_WKUP_IOPAD(0x00e4, PIN_INPUT, 0) /* (AD6) WKUP_I2C0_SDA */ + >; + }; +}; + +&main_pmx0 { + u-boot,dm-spl; + main_mmc0_pins_default: main_mmc0_pins_default { + pinctrl-single,pins = < + AM65X_IOPAD(0x01a8, PIN_INPUT_PULLDOWN, 0) /* (B25) MMC0_CLK */ + AM65X_IOPAD(0x01aC, PIN_INPUT_PULLUP, 0) /* (B27) MMC0_CMD */ + AM65X_IOPAD(0x01a4, PIN_INPUT_PULLUP, 0) /* (A26) MMC0_DAT0 */ + AM65X_IOPAD(0x01a0, PIN_INPUT_PULLUP, 0) /* (E25) MMC0_DAT1 */ + AM65X_IOPAD(0x019c, PIN_INPUT_PULLUP, 0) /* (C26) MMC0_DAT2 */ + AM65X_IOPAD(0x0198, PIN_INPUT_PULLUP, 0) /* (A25) MMC0_DAT3 */ + AM65X_IOPAD(0x0194, PIN_INPUT_PULLUP, 0) /* (E24) MMC0_DAT4 */ + AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */ + AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */ + AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */ + AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */ + >; + }; }; &memorycontroller { @@ -137,3 +169,23 @@ pinctrl-names = "default"; pinctrl-0 = <&wkup_vtt_pins_default>; }; + +&sdhci0 { + clock-names = "clk_xin"; + clocks = <&clk_200mhz>; + /delete-property/ power-domains; + ti,driver-strength-ohm = <50>; +}; + +&sdhci1 { + clock-names = "clk_xin"; + clocks = <&clk_200mhz>; + /delete-property/ power-domains; + ti,driver-strength-ohm = <50>; +}; + +&wkup_i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&wkup_i2c0_pins_default>; + clock-frequency = <400000>; +}; diff --git a/arch/arm/include/asm/omap_i2c.h b/arch/arm/include/asm/omap_i2c.h index c1695cbbee3..a6975401dab 100644 --- a/arch/arm/include/asm/omap_i2c.h +++ b/arch/arm/include/asm/omap_i2c.h @@ -3,8 +3,6 @@ #ifndef _OMAP_I2C_H #define _OMAP_I2C_H -#include <asm/arch/cpu.h> - #ifdef CONFIG_DM_I2C /* Information about a GPIO bank */ diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S index 30fba20e1ba..c74641dcd9b 100644 --- a/arch/arm/lib/crt0.S +++ b/arch/arm/lib/crt0.S @@ -58,6 +58,33 @@ */ /* + * Macro for clearing BSS during SPL execution. Usually called during the + * relocation process for most boards before entering board_init_r(), but + * can also be done early before entering board_init_f() on plaforms that + * can afford it due to sufficient memory being available early. + */ + +.macro SPL_CLEAR_BSS + ldr r0, =__bss_start /* this is auto-relocated! */ + +#ifdef CONFIG_USE_ARCH_MEMSET + ldr r3, =__bss_end /* this is auto-relocated! */ + mov r1, #0x00000000 /* prepare zero to clear BSS */ + + subs r2, r3, r0 /* r2 = memset len */ + bl memset +#else + ldr r1, =__bss_end /* this is auto-relocated! */ + mov r2, #0x00000000 /* prepare zero to clear BSS */ + +clbss_l:cmp r0, r1 /* while not at end of BSS */ + strlo r2, [r0] /* clear 32-bit BSS word */ + addlo r0, r0, #4 /* move to next */ + blo clbss_l +#endif +.endm + +/* * entry point of crt0 sequence */ @@ -82,6 +109,10 @@ ENTRY(_main) mov r9, r0 bl board_init_f_init_reserve +#if defined(CONFIG_SPL_EARLY_BSS) + SPL_CLEAR_BSS +#endif + mov r0, #0 bl board_init_f @@ -119,6 +150,11 @@ here: bl c_runtime_cpu_setup /* we still call old routine here */ #endif #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK) + +#if !defined(CONFIG_SPL_EARLY_BSS) + SPL_CLEAR_BSS +#endif + # ifdef CONFIG_SPL_BUILD /* Use a DRAM stack for the rest of SPL, if requested */ bl spl_relocate_stack_gd @@ -126,23 +162,6 @@ here: movne sp, r0 movne r9, r0 # endif - ldr r0, =__bss_start /* this is auto-relocated! */ - -#ifdef CONFIG_USE_ARCH_MEMSET - ldr r3, =__bss_end /* this is auto-relocated! */ - mov r1, #0x00000000 /* prepare zero to clear BSS */ - - subs r2, r3, r0 /* r2 = memset len */ - bl memset -#else - ldr r1, =__bss_end /* this is auto-relocated! */ - mov r2, #0x00000000 /* prepare zero to clear BSS */ - -clbss_l:cmp r0, r1 /* while not at end of BSS */ - strlo r2, [r0] /* clear 32-bit BSS word */ - addlo r0, r0, #4 /* move to next */ - blo clbss_l -#endif #if ! defined(CONFIG_SPL_BUILD) bl coloured_LED_init diff --git a/arch/arm/mach-k3/Kconfig b/arch/arm/mach-k3/Kconfig index e677a2e01b8..f25f8222055 100644 --- a/arch/arm/mach-k3/Kconfig +++ b/arch/arm/mach-k3/Kconfig @@ -58,6 +58,45 @@ config SYS_K3_BOOT_CORE_ID int default 16 +config K3_LOAD_SYSFW + bool + depends on SPL + +config K3_SYSFW_IMAGE_NAME + string "File name of SYSFW firmware and configuration blob" + depends on K3_LOAD_SYSFW + default "sysfw.itb" + help + Filename of the combined System Firmware and configuration image tree + blob to be loaded when booting from a filesystem. + +config K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT + hex "MMC sector to load SYSFW firmware and configuration blob from" + depends on K3_LOAD_SYSFW && SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR + default 0x3600 + help + Address on the MMC to load the combined System Firmware and + configuration image tree blob from, when the MMC is being used + in raw mode. Units: MMC sectors (1 sector = 512 bytes). + +config K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART + hex "MMC partition to load SYSFW firmware and configuration blob from" + depends on K3_LOAD_SYSFW && SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION + default 2 + help + Partition on the MMC to the combined System Firmware and configuration + image tree blob from, when the MMC is being used in raw mode. + +config K3_SYSFW_IMAGE_SIZE_MAX + int "Amount of memory dynamically allocated for loading SYSFW blob" + depends on K3_LOAD_SYSFW + default 269000 + help + Amount of memory (in bytes) reserved through dynamic allocation at + runtime for loading the combined System Firmware and configuration image + tree blob. Keep it as tight as possible, as this directly affects the + overall SPL memory footprint. + config SYS_K3_SPL_ATF bool "Start Cortex-A from SPL" depends on SPL && CPU_V7R diff --git a/arch/arm/mach-k3/Makefile b/arch/arm/mach-k3/Makefile index 0c3a4f7db17..3af7f2ec960 100644 --- a/arch/arm/mach-k3/Makefile +++ b/arch/arm/mach-k3/Makefile @@ -7,4 +7,7 @@ obj-$(CONFIG_SOC_K3_AM6) += am6_init.o obj-$(CONFIG_ARM64) += arm64-mmu.o obj-$(CONFIG_CPU_V7R) += r5_mpu.o lowlevel_init.o obj-$(CONFIG_TI_SECURE_DEVICE) += security.o +ifeq ($(CONFIG_SPL_BUILD),y) +obj-$(CONFIG_K3_LOAD_SYSFW) += sysfw-loader.o +endif obj-y += common.o diff --git a/arch/arm/mach-k3/am6_init.c b/arch/arm/mach-k3/am6_init.c index 60a580305df..cb96581bfbb 100644 --- a/arch/arm/mach-k3/am6_init.c +++ b/arch/arm/mach-k3/am6_init.c @@ -10,8 +10,12 @@ #include <asm/io.h> #include <spl.h> #include <asm/arch/hardware.h> +#include <asm/arch/sysfw-loader.h> +#include <asm/arch/sys_proto.h> #include "common.h" #include <dm.h> +#include <dm/uclass-internal.h> +#include <dm/pinctrl.h> #ifdef CONFIG_SPL_BUILD static void mmr_unlock(u32 base, u32 partition) @@ -63,7 +67,7 @@ static void store_boot_index_from_rom(void) void board_init_f(ulong dummy) { -#if defined(CONFIG_K3_AM654_DDRSS) +#if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM654_DDRSS) struct udevice *dev; int ret; #endif @@ -83,8 +87,33 @@ void board_init_f(ulong dummy) /* Init DM early in-order to invoke system controller */ spl_early_init(); +#ifdef CONFIG_K3_LOAD_SYSFW + /* + * Process pinctrl for the serial0 a.k.a. WKUP_UART0 module and continue + * regardless of the result of pinctrl. Do this without probing the + * device, but instead by searching the device that would request the + * given sequence number if probed. The UART will be used by the system + * firmware (SYSFW) image for various purposes and SYSFW depends on us + * to initialize its pin settings. + */ + ret = uclass_find_device_by_seq(UCLASS_SERIAL, 0, true, &dev); + if (!ret) + pinctrl_select_state(dev, "default"); + + /* + * Load, start up, and configure system controller firmware. Provide + * the U-Boot console init function to the SYSFW post-PM configuration + * callback hook, effectively switching on (or over) the console + * output. + */ + k3_sysfw_loader(preloader_console_init); +#else /* Prepare console output */ preloader_console_init(); +#endif + + /* Perform EEPROM-based board detection */ + do_board_detect(); #ifdef CONFIG_K3_AM654_DDRSS ret = uclass_get_device(UCLASS_RAM, 0, &dev); diff --git a/arch/arm/mach-k3/include/mach/am6_hardware.h b/arch/arm/mach-k3/include/mach/am6_hardware.h index 3343233aa3c..6df76315456 100644 --- a/arch/arm/mach-k3/include/mach/am6_hardware.h +++ b/arch/arm/mach-k3/include/mach/am6_hardware.h @@ -44,4 +44,7 @@ #define CTRLMMR_LOCK_KICK1 0x0100c #define CTRLMMR_LOCK_KICK1_UNLOCK_VAL 0xd172bc5a +/* MCU SCRATCHPAD usage */ +#define TI_SRAM_SCRATCH_BOARD_EEPROM_START CONFIG_SYS_K3_MCU_SCRATCHPAD_BASE + #endif /* __ASM_ARCH_AM6_HARDWARE_H */ diff --git a/arch/arm/mach-k3/include/mach/sys_proto.h b/arch/arm/mach-k3/include/mach/sys_proto.h index 018725b4d12..787a2744925 100644 --- a/arch/arm/mach-k3/include/mach/sys_proto.h +++ b/arch/arm/mach-k3/include/mach/sys_proto.h @@ -12,4 +12,6 @@ u32 wait_on_value(u32 read_bit_mask, u32 match_value, void *read_addr, u32 bound); struct ti_sci_handle *get_ti_sci_handle(void); int fdt_fixup_msmc_ram(void *blob, char *parent_path, char *node_name); +int do_board_detect(void); + #endif diff --git a/arch/arm/mach-k3/include/mach/sysfw-loader.h b/arch/arm/mach-k3/include/mach/sysfw-loader.h new file mode 100644 index 00000000000..36eb2653489 --- /dev/null +++ b/arch/arm/mach-k3/include/mach/sysfw-loader.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * Andreas Dannenberg <dannenberg@ti.com> + */ + +#ifndef _SYSFW_LOADER_H_ +#define _SYSFW_LOADER_H_ + +void k3_sysfw_loader(void (*config_pm_done_callback)(void)); + +#endif diff --git a/arch/arm/mach-k3/sysfw-loader.c b/arch/arm/mach-k3/sysfw-loader.c new file mode 100644 index 00000000000..2ede82004ab --- /dev/null +++ b/arch/arm/mach-k3/sysfw-loader.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * K3: System Firmware Loader + * + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * Andreas Dannenberg <dannenberg@ti.com> + */ + +#include <common.h> +#include <spl.h> +#include <malloc.h> +#include <remoteproc.h> +#include <linux/soc/ti/ti_sci_protocol.h> +#include <asm/arch/sys_proto.h> + +/* Name of the FIT image nodes for SYSFW and its config data */ +#define SYSFW_FIRMWARE "sysfw.bin" +#define SYSFW_CFG_BOARD "board-cfg.bin" +#define SYSFW_CFG_PM "pm-cfg.bin" +#define SYSFW_CFG_RM "rm-cfg.bin" +#define SYSFW_CFG_SEC "sec-cfg.bin" + +static bool sysfw_loaded; +static void *sysfw_load_address; + +/* + * Populate SPL hook to override the default load address used by the SPL + * loader function with a custom address for SYSFW loading. + */ +struct image_header *spl_get_load_buffer(ssize_t offset, size_t size) +{ + if (sysfw_loaded) + return (struct image_header *)(CONFIG_SYS_TEXT_BASE + offset); + else if (sysfw_load_address) + return sysfw_load_address; + else + panic("SYSFW load address not defined!"); +} + +/* + * Populate SPL hook to skip the default SPL loader FIT post-processing steps + * during SYSFW loading and return to the calling function so we can perform + * our own custom processing. + */ +bool spl_load_simple_fit_skip_processing(void) +{ + return !sysfw_loaded; +} + +static int fit_get_data_by_name(const void *fit, int images, const char *name, + const void **addr, size_t *size) +{ + int node_offset; + + node_offset = fdt_subnode_offset(fit, images, name); + if (node_offset < 0) + return -ENOENT; + + return fit_image_get_data(fit, node_offset, addr, size); +} + +static void k3_sysfw_load_using_fit(void *fit) +{ + int images; + const void *sysfw_addr; + size_t sysfw_size; + int ret; + + /* Find the node holding the images information */ + images = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (images < 0) + panic("Cannot find /images node (%d)\n", images); + + /* Extract System Firmware (SYSFW) image from FIT */ + ret = fit_get_data_by_name(fit, images, SYSFW_FIRMWARE, + &sysfw_addr, &sysfw_size); + if (ret < 0) + panic("Error accessing %s node in FIT (%d)\n", SYSFW_FIRMWARE, + ret); + + /* + * Start up system controller firmware + * + * It is assumed that remoteproc device 0 is the corresponding + * system-controller that runs SYSFW. Make sure DT reflects the same. + */ + ret = rproc_dev_init(0); + if (ret) + panic("rproc failed to be initialized (%d)\n", ret); + + ret = rproc_load(0, (ulong)sysfw_addr, (ulong)sysfw_size); + if (ret) + panic("Firmware failed to start on rproc (%d)\n", ret); + + ret = rproc_start(0); + if (ret) + panic("Firmware init failed on rproc (%d)\n", ret); +} + +static void k3_sysfw_configure_using_fit(void *fit, + struct ti_sci_handle *ti_sci) +{ + struct ti_sci_board_ops *board_ops = &ti_sci->ops.board_ops; + int images; + const void *cfg_fragment_addr; + size_t cfg_fragment_size; + int ret; + + /* Find the node holding the images information */ + images = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (images < 0) + panic("Cannot find /images node (%d)\n", images); + + /* Extract board configuration from FIT */ + ret = fit_get_data_by_name(fit, images, SYSFW_CFG_BOARD, + &cfg_fragment_addr, &cfg_fragment_size); + if (ret < 0) + panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_BOARD, + ret); + + /* Apply board configuration to SYSFW */ + ret = board_ops->board_config(ti_sci, + (u64)(u32)cfg_fragment_addr, + (u32)cfg_fragment_size); + if (ret) + panic("Failed to set board configuration (%d)\n", ret); + + /* Extract power/clock (PM) specific configuration from FIT */ + ret = fit_get_data_by_name(fit, images, SYSFW_CFG_PM, + &cfg_fragment_addr, &cfg_fragment_size); + if (ret < 0) + panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_PM, + ret); + + /* Apply power/clock (PM) specific configuration to SYSFW */ + ret = board_ops->board_config_pm(ti_sci, + (u64)(u32)cfg_fragment_addr, + (u32)cfg_fragment_size); + if (ret) + panic("Failed to set board PM configuration (%d)\n", ret); + + /* Extract resource management (RM) specific configuration from FIT */ + ret = fit_get_data_by_name(fit, images, SYSFW_CFG_RM, + &cfg_fragment_addr, &cfg_fragment_size); + if (ret < 0) + panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_RM, + ret); + + /* Apply resource management (RM) configuration to SYSFW */ + ret = board_ops->board_config_rm(ti_sci, + (u64)(u32)cfg_fragment_addr, + (u32)cfg_fragment_size); + if (ret) + panic("Failed to set board RM configuration (%d)\n", ret); + + /* Extract security specific configuration from FIT */ + ret = fit_get_data_by_name(fit, images, SYSFW_CFG_SEC, + &cfg_fragment_addr, &cfg_fragment_size); + if (ret < 0) + panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_SEC, + ret); + + /* Apply security configuration to SYSFW */ + ret = board_ops->board_config_security(ti_sci, + (u64)(u32)cfg_fragment_addr, + (u32)cfg_fragment_size); + if (ret) + panic("Failed to set board security configuration (%d)\n", + ret); +} + +void k3_sysfw_loader(void (*config_pm_done_callback)(void)) +{ + struct spl_image_info spl_image = { 0 }; + struct spl_boot_device bootdev = { 0 }; + struct ti_sci_handle *ti_sci; + int ret; + + /* Reserve a block of aligned memory for loading the SYSFW image */ + sysfw_load_address = memalign(ARCH_DMA_MINALIGN, + CONFIG_K3_SYSFW_IMAGE_SIZE_MAX); + if (!sysfw_load_address) + panic("Error allocating %u bytes of memory for SYSFW image\n", + CONFIG_K3_SYSFW_IMAGE_SIZE_MAX); + + debug("%s: allocated %u bytes at 0x%p\n", __func__, + CONFIG_K3_SYSFW_IMAGE_SIZE_MAX, sysfw_load_address); + + /* Set load address for legacy modes that bypass spl_get_load_buffer */ + spl_image.load_addr = (uintptr_t)sysfw_load_address; + + bootdev.boot_device = spl_boot_device(); + + /* Load combined System Controller firmware and config data image */ + switch (bootdev.boot_device) { +#if CONFIG_IS_ENABLED(MMC_SUPPORT) + case BOOT_DEVICE_MMC1: + case BOOT_DEVICE_MMC2: + case BOOT_DEVICE_MMC2_2: + ret = spl_mmc_load(&spl_image, &bootdev, +#ifdef CONFIG_K3_SYSFW_IMAGE_NAME + CONFIG_K3_SYSFW_IMAGE_NAME, +#else + NULL, +#endif +#ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART + CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART, +#else + 0, +#endif +#ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT + CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT); +#else + 0); +#endif + break; +#endif + default: + panic("Loading SYSFW image from device %u not supported!\n", + bootdev.boot_device); + } + + if (ret) + panic("Error %d occurred during loading SYSFW image!\n", ret); + + /* + * Now that SYSFW got loaded set helper flag to restore regular SPL + * loader behavior so we can later boot into the next stage as expected. + */ + sysfw_loaded = true; + + /* Ensure the SYSFW image is in FIT format */ + if (image_get_magic((const image_header_t *)sysfw_load_address) != + FDT_MAGIC) + panic("SYSFW image not in FIT format!\n"); + + /* Extract and start SYSFW */ + k3_sysfw_load_using_fit(sysfw_load_address); + + /* Get handle for accessing SYSFW services */ + ti_sci = get_ti_sci_handle(); + + /* Parse and apply the different SYSFW configuration fragments */ + k3_sysfw_configure_using_fit(sysfw_load_address, ti_sci); + + /* + * Now that all clocks and PM aspects are setup, invoke a user- + * provided callback function. Usually this callback would be used + * to setup or re-configure the U-Boot console UART. + */ + if (config_pm_done_callback) + config_pm_done_callback(); + + /* Output System Firmware version info */ + printf("SYSFW ABI: %d.%d (firmware rev 0x%04x '%.*s')\n", + ti_sci->version.abi_major, ti_sci->version.abi_minor, + ti_sci->version.firmware_revision, + sizeof(ti_sci->version.firmware_description), + ti_sci->version.firmware_description); +} diff --git a/board/ti/am65x/Kconfig b/board/ti/am65x/Kconfig index 98172c28f5d..47b41cd6afe 100644 --- a/board/ti/am65x/Kconfig +++ b/board/ti/am65x/Kconfig @@ -12,14 +12,18 @@ config TARGET_AM654_A53_EVM select ARM64 select SOC_K3_AM6 select SYS_DISABLE_DCACHE_OPS + select BOARD_LATE_INIT + imply TI_I2C_BOARD_DETECT config TARGET_AM654_R5_EVM bool "TI K3 based AM654 EVM running on R5" select CPU_V7R select SYS_THUMB_BUILD select SOC_K3_AM6 + select K3_LOAD_SYSFW select K3_AM654_DDRSS imply SYS_K3_SPL_ATF + imply TI_I2C_BOARD_DETECT endchoice @@ -34,6 +38,8 @@ config SYS_VENDOR config SYS_CONFIG_NAME default "am65x_evm" +source "board/ti/common/Kconfig" + endif if TARGET_AM654_R5_EVM @@ -50,4 +56,6 @@ config SYS_CONFIG_NAME config SPL_LDSCRIPT default "arch/arm/mach-omap2/u-boot-spl.lds" +source "board/ti/common/Kconfig" + endif diff --git a/board/ti/am65x/README b/board/ti/am65x/README index 0b82bd557b5..16384e05ea2 100644 --- a/board/ti/am65x/README +++ b/board/ti/am65x/README @@ -209,3 +209,55 @@ Image formats: | | Secure config | | | +-------------------+ | +-----------------------+ + +eMMC: +----- +ROM supports booting from eMMC from boot0 partition offset 0x0 + +Flashing images to eMMC: + +The following commands can be used to download tiboot3.bin, tispl.bin, +u-boot.img, and sysfw.itb from an SD card and write them to the eMMC boot0 +partition at respective addresses. + +=> mmc dev 0 1 +=> fatload mmc 1 ${loadaddr} tiboot3.bin +=> mmc write ${loadaddr} 0x0 0x400 +=> fatload mmc 1 ${loadaddr} tispl.bin +=> mmc write ${loadaddr} 0x400 0x1000 +=> fatload mmc 1 ${loadaddr} u-boot.img +=> mmc write ${loadaddr} 0x1400 0x2000 +=> fatload mmc 1 ${loadaddr} sysfw.itb +=> mmc write ${loadaddr} 0x3600 0x800 + +To give the ROM access to the boot partition, the following commands must be +used for the first time: +=> mmc partconf 0 1 1 1 +=> mmc bootbus 0 1 0 0 + +To create a software partition for the rootfs, the following command can be +used: +=> gpt write mmc 0 ${partitions} + +eMMC layout: + + boot0 partition (8 MB) user partition + 0x0+----------------------------------+ 0x0+-------------------------+ + | tiboot3.bin (512 KB) | | | + 0x400+----------------------------------+ | | + | tispl.bin (2 MB) | | | +0x1400+----------------------------------+ | rootfs | + | u-boot.img (4 MB) | | | +0x3400+----------------------------------+ | | + | environment (128 KB) | | | +0x3500+----------------------------------+ | | + | backup environment (128 KB) | | | +0x3600+----------------------------------+ | | + | sysfw (1 MB) | | | +0x3E00+----------------------------------+ +-------------------------+ + +Kernel image and DT are expected to be present in the /boot folder of rootfs. +To boot kernel from eMMC, use the following commands: +=> setenv mmcdev 0 +=> setenv bootpart 0 +=> boot diff --git a/board/ti/am65x/evm.c b/board/ti/am65x/evm.c index 52f5d6b11e3..7bd8c4fa665 100644 --- a/board/ti/am65x/evm.c +++ b/board/ti/am65x/evm.c @@ -8,10 +8,31 @@ */ #include <common.h> +#include <dm.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/hardware.h> +#include <asm/gpio.h> #include <asm/io.h> +#include <asm/omap_common.h> #include <spl.h> #include <asm/arch/sys_proto.h> +#include "../common/board_detect.h" + +#define board_is_am65x_base_board() board_ti_is("AM6-COMPROCEVM") + +/* Daughter card presence detection signals */ +enum { + AM65X_EVM_APP_BRD_DET, + AM65X_EVM_LCD_BRD_DET, + AM65X_EVM_SERDES_BRD_DET, + AM65X_EVM_HDMI_GPMC_BRD_DET, + AM65X_EVM_BRD_DET_COUNT, +}; + +/* Max number of MAC addresses that are parsed/processed per daughter card */ +#define DAUGHTER_CARD_NO_OF_MAC_ADDR 8 + DECLARE_GLOBAL_DATA_PTR; int board_init(void) @@ -80,3 +101,223 @@ int ft_board_setup(void *blob, bd_t *bd) return ret; } #endif + +int do_board_detect(void) +{ + int ret; + + ret = ti_i2c_eeprom_am6_get_base(CONFIG_EEPROM_BUS_ADDRESS, + CONFIG_EEPROM_CHIP_ADDRESS); + if (ret) + pr_err("Reading on-board EEPROM at 0x%02x failed %d\n", + CONFIG_EEPROM_CHIP_ADDRESS, ret); + + return ret; +} + +static void setup_board_eeprom_env(void) +{ + char *name = "am65x"; + + if (do_board_detect()) + goto invalid_eeprom; + + if (board_is_am65x_base_board()) + name = "am65x"; + else + printf("Unidentified board claims %s in eeprom header\n", + board_ti_get_name()); + +invalid_eeprom: + set_board_info_env_am6(name); +} + +static int init_daughtercard_det_gpio(char *gpio_name, struct gpio_desc *desc) +{ + int ret; + + memset(desc, 0, sizeof(*desc)); + + ret = dm_gpio_lookup_name(gpio_name, desc); + if (ret < 0) + return ret; + + /* Request GPIO, simply re-using the name as label */ + ret = dm_gpio_request(desc, gpio_name); + if (ret < 0) + return ret; + + return dm_gpio_set_dir_flags(desc, GPIOD_IS_IN); +} + +static int probe_daughtercards(void) +{ + struct ti_am6_eeprom ep; + struct gpio_desc board_det_gpios[AM65X_EVM_BRD_DET_COUNT]; + char mac_addr[DAUGHTER_CARD_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN]; + u8 mac_addr_cnt; + char name_overlays[1024] = { 0 }; + int i, j; + int ret; + + /* + * Daughter card presence detection signal name to GPIO (via I2C I/O + * expander @ address 0x38) name and EEPROM I2C address mapping. + */ + const struct { + char *gpio_name; + u8 i2c_addr; + } slot_map[AM65X_EVM_BRD_DET_COUNT] = { + { "gpio@38_0", 0x52, }, /* AM65X_EVM_APP_BRD_DET */ + { "gpio@38_1", 0x55, }, /* AM65X_EVM_LCD_BRD_DET */ + { "gpio@38_2", 0x54, }, /* AM65X_EVM_SERDES_BRD_DET */ + { "gpio@38_3", 0x53, }, /* AM65X_EVM_HDMI_GPMC_BRD_DET */ + }; + + /* Declaration of daughtercards to probe */ + const struct { + u8 slot_index; /* Slot the card is installed */ + char *card_name; /* EEPROM-programmed card name */ + char *dtbo_name; /* Device tree overlay to apply */ + u8 eth_offset; /* ethXaddr MAC address index offset */ + } cards[] = { + { + AM65X_EVM_APP_BRD_DET, + "AM6-GPAPPEVM", + "k3-am654-gp.dtbo", + 0, + }, + { + AM65X_EVM_APP_BRD_DET, + "AM6-IDKAPPEVM", + "k3-am654-idk.dtbo", + 3, + }, + { + AM65X_EVM_SERDES_BRD_DET, + "SER-PCIE2LEVM", + "k3-am654-pcie-usb2.dtbo", + 0, + }, + { + AM65X_EVM_SERDES_BRD_DET, + "SER-PCIEUSBEVM", + "k3-am654-pcie-usb3.dtbo", + 0, + }, + { + AM65X_EVM_LCD_BRD_DET, + "OLDI-LCD1EVM", + "k3-am654-evm-oldi-lcd1evm.dtbo", + 0, + }, + }; + + /* + * Initialize GPIO used for daughtercard slot presence detection and + * keep the resulting handles in local array for easier access. + */ + for (i = 0; i < AM65X_EVM_BRD_DET_COUNT; i++) { + ret = init_daughtercard_det_gpio(slot_map[i].gpio_name, + &board_det_gpios[i]); + if (ret < 0) + return ret; + } + + for (i = 0; i < ARRAY_SIZE(cards); i++) { + /* Obtain card-specific slot index and associated I2C address */ + u8 slot_index = cards[i].slot_index; + u8 i2c_addr = slot_map[slot_index].i2c_addr; + + /* + * The presence detection signal is active-low, hence skip + * over this card slot if anything other than 0 is returned. + */ + ret = dm_gpio_get_value(&board_det_gpios[slot_index]); + if (ret < 0) + return ret; + else if (ret) + continue; + + /* Get and parse the daughter card EEPROM record */ + ret = ti_i2c_eeprom_am6_get(CONFIG_EEPROM_BUS_ADDRESS, i2c_addr, + &ep, + (char **)mac_addr, + DAUGHTER_CARD_NO_OF_MAC_ADDR, + &mac_addr_cnt); + if (ret) { + pr_err("Reading daughtercard EEPROM at 0x%02x failed %d\n", + i2c_addr, ret); + /* + * Even this is pretty serious let's just skip over + * this particular daughtercard, rather than ending + * the probing process altogether. + */ + continue; + } + + /* Only process the parsed data if we found a match */ + if (strncmp(ep.name, cards[i].card_name, sizeof(ep.name))) + continue; + + printf("detected %s\n", cards[i].card_name); + + /* + * Populate any MAC addresses from daughtercard into the U-Boot + * environment, starting with a card-specific offset so we can + * have multiple cards contribute to the MAC pool in a well- + * defined manner. + */ + for (j = 0; j < mac_addr_cnt; j++) { + if (!is_valid_ethaddr((u8 *)mac_addr[j])) + continue; + + eth_env_set_enetaddr_by_index("eth", + cards[i].eth_offset + j, + (uchar *)mac_addr[j]); + } + + /* Skip if no overlays are to be added */ + if (!strlen(cards[i].dtbo_name)) + continue; + + /* + * Make sure we are not running out of buffer space by checking + * if we can fit the new overlay, a trailing space to be used + * as a separator, plus the terminating zero. + */ + if (strlen(name_overlays) + strlen(cards[i].dtbo_name) + 2 > + sizeof(name_overlays)) + return -ENOMEM; + + /* Append to our list of overlays */ + strcat(name_overlays, cards[i].dtbo_name); + strcat(name_overlays, " "); + } + + /* Apply device tree overlay(s) to the U-Boot environment, if any */ + if (strlen(name_overlays)) + return env_set("name_overlays", name_overlays); + + return 0; +} + +int board_late_init(void) +{ + struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA; + + setup_board_eeprom_env(); + + /* + * The first MAC address for ethernet a.k.a. ethernet0 comes from + * efuse populated via the am654 gigabit eth switch subsystem driver. + * All the other ones are populated via EEPROM, hence continue with + * an index of 1. + */ + board_ti_am6_set_ethaddr(1, ep->mac_addr_cnt); + + /* Check for and probe any plugged-in daughtercards */ + probe_daughtercards(); + + return 0; +} diff --git a/board/ti/common/board_detect.c b/board/ti/common/board_detect.c index e258e22f371..32fa10599e8 100644 --- a/board/ti/common/board_detect.c +++ b/board/ti/common/board_detect.c @@ -8,6 +8,7 @@ */ #include <common.h> +#include <asm/arch/hardware.h> #include <asm/omap_common.h> #include <dm/uclass.h> #include <i2c.h> @@ -284,6 +285,191 @@ int __maybe_unused ti_i2c_eeprom_dra7_get(int bus_addr, int dev_addr) return 0; } +static int ti_i2c_eeprom_am6_parse_record(struct ti_am6_eeprom_record *record, + struct ti_am6_eeprom *ep, + char **mac_addr, + u8 mac_addr_max_cnt, + u8 *mac_addr_cnt) +{ + switch (record->header.id) { + case TI_AM6_EEPROM_RECORD_BOARD_INFO: + if (record->header.len != sizeof(record->data.board_info)) + return -EINVAL; + + if (!ep) + break; + + /* Populate (and clean, if needed) the board name */ + strlcpy(ep->name, record->data.board_info.name, + sizeof(ep->name)); + ti_eeprom_string_cleanup(ep->name); + + /* Populate selected other fields from the board info record */ + strlcpy(ep->version, record->data.board_info.version, + sizeof(ep->version)); + strlcpy(ep->software_revision, + record->data.board_info.software_revision, + sizeof(ep->software_revision)); + strlcpy(ep->serial, record->data.board_info.serial, + sizeof(ep->serial)); + break; + case TI_AM6_EEPROM_RECORD_MAC_INFO: + if (record->header.len != sizeof(record->data.mac_info)) + return -EINVAL; + + if (!mac_addr || !mac_addr_max_cnt) + break; + + *mac_addr_cnt = ((record->data.mac_info.mac_control & + TI_AM6_EEPROM_MAC_ADDR_COUNT_MASK) >> + TI_AM6_EEPROM_MAC_ADDR_COUNT_SHIFT) + 1; + + /* + * The EEPROM can (but may not) hold a very large amount + * of MAC addresses, by far exceeding what we want/can store + * in the common memory array, so only grab what we can fit. + * Note that a value of 0 means 1 MAC address, and so on. + */ + *mac_addr_cnt = min(*mac_addr_cnt, mac_addr_max_cnt); + + memcpy(mac_addr, record->data.mac_info.mac_addr, + *mac_addr_cnt * TI_EEPROM_HDR_ETH_ALEN); + break; + case 0x00: + /* Illegal value... Fall through... */ + case 0xFF: + /* Illegal value... Something went horribly wrong... */ + return -EINVAL; + default: + pr_warn("%s: Ignoring record id %u\n", __func__, + record->header.id); + } + + return 0; +} + +int __maybe_unused ti_i2c_eeprom_am6_get(int bus_addr, int dev_addr, + struct ti_am6_eeprom *ep, + char **mac_addr, + u8 mac_addr_max_cnt, + u8 *mac_addr_cnt) +{ + struct udevice *dev; + struct udevice *bus; + unsigned int eeprom_addr; + struct ti_am6_eeprom_record_board_id board_id; + struct ti_am6_eeprom_record record; + int rc; + + /* Initialize with a known bad marker for i2c fails.. */ + memset(ep, 0, sizeof(*ep)); + ep->header = TI_DEAD_EEPROM_MAGIC; + + /* Read the board ID record which is always the first EEPROM record */ + rc = ti_i2c_eeprom_get(bus_addr, dev_addr, TI_EEPROM_HEADER_MAGIC, + sizeof(board_id), (uint8_t *)&board_id); + if (rc) + return rc; + + if (board_id.header.id != TI_AM6_EEPROM_RECORD_BOARD_ID) { + pr_err("%s: Invalid board ID record!\n", __func__); + return -EINVAL; + } + + /* Establish DM handle to board config EEPROM */ + rc = uclass_get_device_by_seq(UCLASS_I2C, bus_addr, &bus); + if (rc) + return rc; + rc = i2c_get_chip(bus, dev_addr, 1, &dev); + if (rc) + return rc; + + ep->header = TI_EEPROM_HEADER_MAGIC; + + /* Ready to parse TLV structure. Initialize variables... */ + *mac_addr_cnt = 0; + + /* + * After the all-encompassing board ID record all other records follow + * a TLV-type scheme. Point to the first such record and then start + * parsing those one by one. + */ + eeprom_addr = sizeof(board_id); + + while (true) { + rc = dm_i2c_read(dev, eeprom_addr, (uint8_t *)&record.header, + sizeof(record.header)); + if (rc) + return rc; + + /* + * Check for end of list marker. If we reached it don't go + * any further and stop parsing right here. + */ + if (record.header.id == TI_AM6_EEPROM_RECORD_END_LIST) + break; + + eeprom_addr += sizeof(record.header); + + debug("%s: dev_addr=0x%02x header.id=%u header.len=%u\n", + __func__, dev_addr, record.header.id, + record.header.len); + + /* Read record into memory if it fits */ + if (record.header.len <= sizeof(record.data)) { + rc = dm_i2c_read(dev, eeprom_addr, + (uint8_t *)&record.data, + record.header.len); + if (rc) + return rc; + + /* Process record */ + rc = ti_i2c_eeprom_am6_parse_record(&record, ep, + mac_addr, + mac_addr_max_cnt, + mac_addr_cnt); + if (rc) { + pr_err("%s: EEPROM parsing error!\n", __func__); + return rc; + } + } else { + /* + * We may get here in case of larger records which + * are not yet understood. + */ + pr_err("%s: Ignoring record id %u\n", __func__, + record.header.id); + } + + eeprom_addr += record.header.len; + } + + return 0; +} + +int __maybe_unused ti_i2c_eeprom_am6_get_base(int bus_addr, int dev_addr) +{ + struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA; + int ret; + + /* + * Always execute EEPROM read by not allowing to bypass it during the + * first invocation of SPL which happens on the R5 core. + */ +#if !(defined(CONFIG_SPL_BUILD) && defined(CONFIG_CPU_V7R)) + if (ep->header == TI_EEPROM_HEADER_MAGIC) { + debug("%s: EEPROM has already been read\n", __func__); + return 0; + } +#endif + + ret = ti_i2c_eeprom_am6_get(bus_addr, dev_addr, ep, + (char **)ep->mac_addr, + AM6_EEPROM_HDR_NO_OF_MAC_ADDR, + &ep->mac_addr_cnt); + return ret; +} + bool __maybe_unused board_ti_is(char *name_tag) { struct ti_common_eeprom *ep = TI_EEPROM_DATA; @@ -348,6 +534,25 @@ fail: memset(mac_addr, 0, TI_EEPROM_HDR_ETH_ALEN); } +void __maybe_unused +board_ti_am6_get_eth_mac_addr(int index, + u8 mac_addr[TI_EEPROM_HDR_ETH_ALEN]) +{ + struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA; + + if (ep->header == TI_DEAD_EEPROM_MAGIC) + goto fail; + + if (index < 0 || index >= ep->mac_addr_cnt) + goto fail; + + memcpy(mac_addr, ep->mac_addr[index], TI_EEPROM_HDR_ETH_ALEN); + return; + +fail: + memset(mac_addr, 0, TI_EEPROM_HDR_ETH_ALEN); +} + u64 __maybe_unused board_ti_get_emif1_size(void) { struct ti_common_eeprom *ep = TI_EEPROM_DATA; @@ -391,6 +596,34 @@ void __maybe_unused set_board_info_env(char *name) env_set("board_serial", unknown); } +void __maybe_unused set_board_info_env_am6(char *name) +{ + char *unknown = "unknown"; + struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA; + + if (name) + env_set("board_name", name); + else if (ep->name) + env_set("board_name", ep->name); + else + env_set("board_name", unknown); + + if (ep->version) + env_set("board_rev", ep->version); + else + env_set("board_rev", unknown); + + if (ep->software_revision) + env_set("board_software_revision", ep->software_revision); + else + env_set("board_software_revision", unknown); + + if (ep->serial) + env_set("board_serial", ep->serial); + else + env_set("board_serial", unknown); +} + static u64 mac_to_u64(u8 mac[6]) { int i; @@ -453,6 +686,19 @@ void board_ti_set_ethaddr(int index) } } +void board_ti_am6_set_ethaddr(int index, int count) +{ + u8 mac_addr[6]; + int i; + + for (i = 0; i < count; i++) { + board_ti_am6_get_eth_mac_addr(i, mac_addr); + if (is_valid_ethaddr(mac_addr)) + eth_env_set_enetaddr_by_index("eth", i + index, + mac_addr); + } +} + bool __maybe_unused board_ti_was_eeprom_read(void) { struct ti_common_eeprom *ep = TI_EEPROM_DATA; diff --git a/board/ti/common/board_detect.h b/board/ti/common/board_detect.h index f8495a7a7cf..a45d8961b9a 100644 --- a/board/ti/common/board_detect.h +++ b/board/ti/common/board_detect.h @@ -43,6 +43,133 @@ struct ti_am_eeprom { char mac_addr[TI_EEPROM_HDR_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN]; } __attribute__ ((__packed__)); +/* AM6x TI EVM EEPROM Definitions */ +#define TI_AM6_EEPROM_RECORD_BOARD_ID 0x01 +#define TI_AM6_EEPROM_RECORD_BOARD_INFO 0x10 +#define TI_AM6_EEPROM_RECORD_DDR_INFO 0x11 +#define TI_AM6_EEPROM_RECORD_DDR_SPD 0x12 +#define TI_AM6_EEPROM_RECORD_MAC_INFO 0x13 +#define TI_AM6_EEPROM_RECORD_END_LIST 0xFE + +/* + * Common header for AM6x TI EVM EEPROM records. Used to encapsulate the config + * EEPROM in its entirety as well as for individual records contained within. + */ +struct ti_am6_eeprom_record_header { + u8 id; + u16 len; +} __attribute__ ((__packed__)); + +/* AM6x TI EVM EEPROM board ID structure */ +struct ti_am6_eeprom_record_board_id { + u32 magic_number; + struct ti_am6_eeprom_record_header header; +} __attribute__ ((__packed__)); + +/* AM6x TI EVM EEPROM board info structure */ +#define AM6_EEPROM_HDR_NAME_LEN 16 +#define AM6_EEPROM_HDR_VERSION_LEN 2 +#define AM6_EEPROM_HDR_PROC_NR_LEN 4 +#define AM6_EEPROM_HDR_VARIANT_LEN 2 +#define AM6_EEPROM_HDR_PCB_REV_LEN 2 +#define AM6_EEPROM_HDR_SCH_BOM_REV_LEN 2 +#define AM6_EEPROM_HDR_SW_REV_LEN 2 +#define AM6_EEPROM_HDR_VID_LEN 2 +#define AM6_EEPROM_HDR_BLD_WK_LEN 2 +#define AM6_EEPROM_HDR_BLD_YR_LEN 2 +#define AM6_EEPROM_HDR_4P_NR_LEN 6 +#define AM6_EEPROM_HDR_SERIAL_LEN 4 + +struct ti_am6_eeprom_record_board_info { + char name[AM6_EEPROM_HDR_NAME_LEN]; + char version[AM6_EEPROM_HDR_VERSION_LEN]; + char proc_number[AM6_EEPROM_HDR_PROC_NR_LEN]; + char variant[AM6_EEPROM_HDR_VARIANT_LEN]; + char pcb_revision[AM6_EEPROM_HDR_PCB_REV_LEN]; + char schematic_bom_revision[AM6_EEPROM_HDR_SCH_BOM_REV_LEN]; + char software_revision[AM6_EEPROM_HDR_SW_REV_LEN]; + char vendor_id[AM6_EEPROM_HDR_VID_LEN]; + char build_week[AM6_EEPROM_HDR_BLD_WK_LEN]; + char build_year[AM6_EEPROM_HDR_BLD_YR_LEN]; + char board_4p_number[AM6_EEPROM_HDR_4P_NR_LEN]; + char serial[AM6_EEPROM_HDR_SERIAL_LEN]; +} __attribute__ ((__packed__)); + +/* Memory location to keep a copy of the AM6 board info record */ +#define TI_AM6_EEPROM_BD_INFO_DATA ((struct ti_am6_eeprom_record_board_info *) \ + TI_SRAM_SCRATCH_BOARD_EEPROM_START) + +/* AM6x TI EVM EEPROM DDR info structure */ +#define TI_AM6_EEPROM_DDR_CTRL_INSTANCE_MASK GENMASK(1, 0) +#define TI_AM6_EEPROM_DDR_CTRL_INSTANCE_SHIFT 0 +#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_MASK GENMASK(3, 2) +#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_NA (0 << 2) +#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_BOARDID (2 << 2) +#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_I2C51 (3 << 2) +#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_MASK GENMASK(5, 4) +#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_DDR3 (0 << 4) +#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_DDR4 (1 << 4) +#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_LPDDR4 (2 << 4) +#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_MASK GENMASK(7, 6) +#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_16 (0 << 6) +#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_32 (1 << 6) +#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_64 (2 << 6) +#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_MASK GENMASK(9, 8) +#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_8 (0 << 8) +#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_16 (1 << 8) +#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_32 (2 << 8) +#define TI_AM6_EEPROM_DDR_CTRL_RANKS_2 BIT(10) +#define TI_AM6_EEPROM_DDR_CTRL_DENS_MASK GENMASK(13, 11) +#define TI_AM6_EEPROM_DDR_CTRL_DENS_1GB (0 << 11) +#define TI_AM6_EEPROM_DDR_CTRL_DENS_2GB (1 << 11) +#define TI_AM6_EEPROM_DDR_CTRL_DENS_4GB (2 << 11) +#define TI_AM6_EEPROM_DDR_CTRL_DENS_8GB (3 << 11) +#define TI_AM6_EEPROM_DDR_CTRL_DENS_12GB (4 << 11) +#define TI_AM6_EEPROM_DDR_CTRL_DENS_16GB (5 << 11) +#define TI_AM6_EEPROM_DDR_CTRL_DENS_24GB (6 << 11) +#define TI_AM6_EEPROM_DDR_CTRL_DENS_32GB (7 << 11) +#define TI_AM6_EEPROM_DDR_CTRL_ECC BIT(14) + +struct ti_am6_eeprom_record_ddr_info { + u16 ddr_control; +} __attribute__ ((__packed__)); + +/* AM6x TI EVM EEPROM DDR SPD structure */ +#define TI_AM6_EEPROM_DDR_SPD_INSTANCE_MASK GENMASK(1, 0) +#define TI_AM6_EEPROM_DDR_SPD_INSTANCE_SHIFT 0 +#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_MASK GENMASK(4, 3) +#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_DDR3 (0 << 3) +#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_DDR4 (1 << 3) +#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_LPDDR4 (2 << 3) +#define TI_AM6_EEPROM_DDR_SPD_DATA_LEN 512 + +struct ti_am6_eeprom_record_ddr_spd { + u16 spd_control; + u8 data[TI_AM6_EEPROM_DDR_SPD_DATA_LEN]; +} __attribute__ ((__packed__)); + +/* AM6x TI EVM EEPROM MAC info structure */ +#define TI_AM6_EEPROM_MAC_INFO_INSTANCE_MASK GENMASK(2, 0) +#define TI_AM6_EEPROM_MAC_INFO_INSTANCE_SHIFT 0 +#define TI_AM6_EEPROM_MAC_ADDR_COUNT_MASK GENMASK(7, 3) +#define TI_AM6_EEPROM_MAC_ADDR_COUNT_SHIFT 3 +#define TI_AM6_EEPROM_MAC_ADDR_MAX_COUNT 32 + +struct ti_am6_eeprom_record_mac_info { + u16 mac_control; + u8 mac_addr[TI_AM6_EEPROM_MAC_ADDR_MAX_COUNT][TI_EEPROM_HDR_ETH_ALEN]; +} __attribute__ ((__packed__)); + +struct ti_am6_eeprom_record { + struct ti_am6_eeprom_record_header header; + union { + struct ti_am6_eeprom_record_board_info board_info; + struct ti_am6_eeprom_record_ddr_info ddr_info; + struct ti_am6_eeprom_record_ddr_spd ddr_spd; + struct ti_am6_eeprom_record_mac_info mac_info; + } data; +} __attribute__ ((__packed__)); + /* DRA7 EEPROM MAGIC Header identifier */ #define DRA7_EEPROM_HEADER_MAGIC 0xAA5533EE #define DRA7_EEPROM_HDR_NAME_LEN 16 @@ -99,6 +226,37 @@ struct ti_common_eeprom { #define TI_EEPROM_DATA ((struct ti_common_eeprom *)\ TI_SRAM_SCRATCH_BOARD_EEPROM_START) +/* + * Maximum number of Ethernet MAC addresses extracted from the AM6x on-board + * EEPROM during the initial probe and carried forward in SRAM. + */ +#define AM6_EEPROM_HDR_NO_OF_MAC_ADDR 8 + +/** + * struct ti_am6_eeprom - Null terminated, usable EEPROM contents, as extracted + * from the AM6 on-board EEPROM. Note that we only carry a subset of data + * at this time to be considerate about memory consumption. + * @header: Magic number for data validity indication + * @name: NULL terminated name + * @version: NULL terminated version + * @software_revision: NULL terminated software revision + * @serial: Board serial number + * @mac_addr_cnt: Number of MAC addresses stored in this object + * @mac_addr: MAC addresses + */ +struct ti_am6_eeprom { + u32 header; + char name[AM6_EEPROM_HDR_NAME_LEN + 1]; + char version[AM6_EEPROM_HDR_VERSION_LEN + 1]; + char software_revision[AM6_EEPROM_HDR_SW_REV_LEN + 1]; + char serial[AM6_EEPROM_HDR_SERIAL_LEN + 1]; + u8 mac_addr_cnt; + char mac_addr[AM6_EEPROM_HDR_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN]; +}; + +#define TI_AM6_EEPROM_DATA ((struct ti_am6_eeprom *) \ + TI_SRAM_SCRATCH_BOARD_EEPROM_START) + /** * ti_i2c_eeprom_am_get() - Consolidated eeprom data collection for AM* TI EVMs * @bus_addr: I2C bus address @@ -117,6 +275,33 @@ int ti_i2c_eeprom_am_get(int bus_addr, int dev_addr); int ti_i2c_eeprom_dra7_get(int bus_addr, int dev_addr); /** + * ti_i2c_eeprom_am6_get() - Consolidated eeprom data for AM6x TI EVMs and + * associated daughter cards, parsed into user- + * provided data structures + * @bus_addr: I2C bus address + * @dev_addr: I2C slave address + * @ep: Pointer to structure receiving AM6-specific header data + * @mac_addr: Pointer to memory receiving parsed MAC addresses. May be + * NULL to skip MAC parsing. + * @mac_addr_max_cnt: Maximum number of MAC addresses that can be stored into + * mac_addr. May be NULL to skip MAC parsing. + * @mac_addr_cnt: Pointer to a location returning how many MAC addressed got + * actually parsed. + */ +int __maybe_unused ti_i2c_eeprom_am6_get(int bus_addr, int dev_addr, + struct ti_am6_eeprom *ep, + char **mac_addr, + u8 mac_addr_max_cnt, + u8 *mac_addr_cnt); + +/** + * ti_i2c_eeprom_am6_get_base() - Consolidated eeprom data for AM6x TI EVMs + * @bus_addr: I2C bus address + * @dev_addr: I2C slave address + */ +int __maybe_unused ti_i2c_eeprom_am6_get_base(int bus_addr, int dev_addr); + +/** * board_ti_is() - Board detection logic for TI EVMs * @name_tag: Tag used in eeprom for the board * @@ -193,6 +378,15 @@ u64 board_ti_get_emif2_size(void); void set_board_info_env(char *name); /** + * set_board_info_env_am6() - Setup commonly used board information environment + * vars for AM6-type boards + * @name: Name of the board + * + * If name is NULL, default_name is used. + */ +void set_board_info_env_am6(char *name); + +/** * board_ti_set_ethaddr- Sets the ethaddr environment from EEPROM * @index: The first eth<index>addr environment variable to set * @@ -205,6 +399,18 @@ void set_board_info_env(char *name); void board_ti_set_ethaddr(int index); /** + * board_ti_am6_set_ethaddr- Sets the ethaddr environment from EEPROM + * @index: The first eth<index>addr environment variable to set + * @count: The number of MAC addresses to process + * + * EEPROM should be already read before calling this function. The EEPROM + * contains n dedicated MAC addresses. This function sets the ethaddr + * environment variable for all the available MAC addresses starting + * from eth<index>addr. + */ +void board_ti_am6_set_ethaddr(int index, int count); + +/** * board_ti_was_eeprom_read() - Check to see if the eeprom contents have been read * * This function is useful to determine if the eeprom has already been read and diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 7122c069b2d..5978fb29343 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -248,6 +248,16 @@ config TPL_BANNER_PRINT info. Disabling this option could be useful to reduce SPL boot time (e.g. approx. 6 ms faster, when output on i.MX6 with 115200 baud). +config SPL_EARLY_BSS + depends on ARM && !ARM64 + bool "Allows initializing BSS early before entering board_init_f" + help + On some platform we have sufficient memory available early on to + allow setting up and using a basic BSS prior to entering + board_init_f. Activating this option will also de-activate the + clearing of BSS during the SPL relocation process, thus allowing + to carry state from board_init_f to board_init_r by way of BSS. + config SPL_DISPLAY_PRINT bool "Display a board-specific message in SPL" help diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 87ecf0bb9e5..969f7775c18 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -340,6 +340,16 @@ static int spl_fit_image_get_os(const void *fit, int noffset, uint8_t *os) #endif } +/* + * Weak default function to allow customizing SPL fit loading for load-only + * use cases by allowing to skip the parsing/processing of the FIT contents + * (so that this can be done separately in a more customized fashion) + */ +__weak bool spl_load_simple_fit_skip_processing(void) +{ + return false; +} + int spl_load_simple_fit(struct spl_image_info *spl_image, struct spl_load_info *info, ulong sector, void *fit) { @@ -389,6 +399,10 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, if (count == 0) return -EIO; + /* skip further processing if requested to enable load-only use cases */ + if (spl_load_simple_fit_skip_processing()) + return 0; + /* find the node holding the images information */ images = fdt_path_offset(fit, FIT_IMAGES_PATH); if (images < 0) { diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 324d91c8840..b3619889f79 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -151,7 +151,8 @@ static int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device) #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION static int mmc_load_image_raw_partition(struct spl_image_info *spl_image, - struct mmc *mmc, int partition) + struct mmc *mmc, int partition, + unsigned long sector) { disk_partition_t info; int err; @@ -180,8 +181,7 @@ static int mmc_load_image_raw_partition(struct spl_image_info *spl_image, } #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR - return mmc_load_image_raw_sector(spl_image, mmc, - info.start + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); + return mmc_load_image_raw_sector(spl_image, mmc, info.start + sector); #else return mmc_load_image_raw_sector(spl_image, mmc, info.start); #endif @@ -234,7 +234,8 @@ static int mmc_load_image_raw_os(struct spl_image_info *spl_image, #endif #ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION -static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc) +static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc, + const char *filename) { int err = -ENOSYS; @@ -248,7 +249,7 @@ static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc) #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME err = spl_load_image_fat(spl_image, mmc_get_blk_desc(mmc), CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, - CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); + filename); if (!err) return err; #endif @@ -263,7 +264,7 @@ static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc) #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME err = spl_load_image_ext(spl_image, mmc_get_blk_desc(mmc), CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, - CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); + filename); if (!err) return err; #endif @@ -276,7 +277,8 @@ static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc) return err; } #else -static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc) +static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc, + const char *filename) { return -ENOSYS; } @@ -301,24 +303,31 @@ int spl_boot_partition(const u32 boot_device) } #endif -int spl_mmc_load_image(struct spl_image_info *spl_image, - struct spl_boot_device *bootdev) +int spl_mmc_load(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev, + const char *filename, + int raw_part, + unsigned long raw_sect) { - struct mmc *mmc = NULL; + static struct mmc *mmc; u32 boot_mode; int err = 0; __maybe_unused int part; - err = spl_mmc_find_device(&mmc, bootdev->boot_device); - if (err) - return err; + /* Perform peripheral init only once */ + if (!mmc) { + err = spl_mmc_find_device(&mmc, bootdev->boot_device); + if (err) + return err; - err = mmc_init(mmc); - if (err) { + err = mmc_init(mmc); + if (err) { + mmc = NULL; #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT - printf("spl: mmc init failed with error: %d\n", err); + printf("spl: mmc init failed with error: %d\n", err); #endif - return err; + return err; + } } boot_mode = spl_boot_mode(bootdev->boot_device); @@ -356,17 +365,13 @@ int spl_mmc_load_image(struct spl_image_info *spl_image, return err; } #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION - err = spl_boot_partition(bootdev->boot_device); - if (!err) - return err; - - err = mmc_load_image_raw_partition(spl_image, mmc, err); + err = mmc_load_image_raw_partition(spl_image, mmc, raw_part, + raw_sect); if (!err) return err; #endif #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR - err = mmc_load_image_raw_sector(spl_image, mmc, - CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); + err = mmc_load_image_raw_sector(spl_image, mmc, raw_sect); if (!err) return err; #endif @@ -374,7 +379,7 @@ int spl_mmc_load_image(struct spl_image_info *spl_image, case MMCSD_MODE_FS: debug("spl: mmc boot mode: fs\n"); - err = spl_mmc_do_fs_boot(spl_image, mmc); + err = spl_mmc_do_fs_boot(spl_image, mmc, filename); if (!err) return err; @@ -388,6 +393,27 @@ int spl_mmc_load_image(struct spl_image_info *spl_image, return err; } +int spl_mmc_load_image(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev) +{ + return spl_mmc_load(spl_image, bootdev, +#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME + CONFIG_SPL_FS_LOAD_PAYLOAD_NAME, +#else + NULL, +#endif +#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION + spl_boot_partition(bootdev->boot_device), +#else + 0, +#endif +#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); +#else + 0); +#endif +} + SPL_LOAD_IMAGE_METHOD("MMC1", 0, BOOT_DEVICE_MMC1, spl_mmc_load_image); SPL_LOAD_IMAGE_METHOD("MMC2", 0, BOOT_DEVICE_MMC2, spl_mmc_load_image); SPL_LOAD_IMAGE_METHOD("MMC2_2", 0, BOOT_DEVICE_MMC2_2, spl_mmc_load_image); diff --git a/configs/am335x_boneblack_vboot_defconfig b/configs/am335x_boneblack_vboot_defconfig index ffe013fa2df..9ccbd682412 100644 --- a/configs/am335x_boneblack_vboot_defconfig +++ b/configs/am335x_boneblack_vboot_defconfig @@ -1,4 +1,8 @@ CONFIG_ARM=y +# CONFIG_SPL_USE_ARCH_MEMCPY is not set +# CONFIG_TPL_USE_ARCH_MEMCPY is not set +# CONFIG_SPL_USE_ARCH_MEMSET is not set +# CONFIG_TPL_USE_ARCH_MEMSET is not set CONFIG_ARCH_OMAP2PLUS=y CONFIG_TI_COMMON_CMD_OPTIONS=y CONFIG_AM33XX=y diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig index b940af3f561..9d4c6a205ce 100644 --- a/configs/am65x_evm_a53_defconfig +++ b/configs/am65x_evm_a53_defconfig @@ -2,7 +2,7 @@ CONFIG_ARM=y CONFIG_ARCH_K3=y CONFIG_SPL_LIBCOMMON_SUPPORT=y CONFIG_SPL_LIBGENERIC_SUPPORT=y -CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SOC_K3_AM6=y CONFIG_TARGET_AM654_A53_EVM=y CONFIG_SPL_MMC_SUPPORT=y @@ -16,12 +16,14 @@ CONFIG_DISTRO_DEFAULTS=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_SPL_LOAD_FIT=y CONFIG_OF_BOARD_SETUP=y -CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run run_kern" +CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run get_overlay_${boot}; run run_kern" # CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_TEXT_BASE=0x80080000 CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_STACK_R=y CONFIG_SPL_SEPARATE_BSS=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1400 CONFIG_SPL_I2C_SUPPORT=y CONFIG_SPL_DM_MAILBOX=y CONFIG_SPL_DM_RESET=y @@ -30,35 +32,41 @@ CONFIG_SPL_REMOTEPROC=y CONFIG_SPL_YMODEM_SUPPORT=y CONFIG_CMD_ASKENV=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_GPT=y +CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_REMOTEPROC=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_TIME=y # CONFIG_ISO_PARTITION is not set -# CONFIG_EFI_PARTITION is not set CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="k3-am654-base-board" CONFIG_SPL_MULTI_DTB_FIT=y CONFIG_SPL_MULTI_DTB_FIT_NO_COMPRESSION=y -CONFIG_ENV_IS_IN_FAT=y -CONFIG_ENV_FAT_INTERFACE="mmc" -CONFIG_ENV_FAT_DEVICE_AND_PART="1:1" +CONFIG_ENV_IS_IN_MMC=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_REGMAP=y +CONFIG_SPL_REGMAP=y CONFIG_CLK=y CONFIG_SPL_CLK=y CONFIG_CLK_TI_SCI=y CONFIG_DMA_CHANNELS=y CONFIG_TI_K3_NAVSS_UDMA=y CONFIG_TI_SCI_PROTOCOL=y +CONFIG_DM_GPIO=y +CONFIG_DM_PCA953X=y +CONFIG_DM_I2C=y +CONFIG_I2C_SET_DEFAULT_BUS_NUM=y +CONFIG_SYS_I2C_OMAP24XX=y CONFIG_DM_MAILBOX=y CONFIG_K3_SEC_PROXY=y CONFIG_DM_MMC=y CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_K3_ARASAN=y +CONFIG_MMC_SDHCI_AM654=y CONFIG_PHY_TI=y CONFIG_PHY_FIXED=y CONFIG_DM_ETH=y @@ -80,3 +88,5 @@ CONFIG_SOC_TI=y CONFIG_SYSRESET=y CONFIG_SPL_SYSRESET=y CONFIG_SYSRESET_TI_SCI=y +CONFIG_FAT_WRITE=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/am65x_evm_r5_defconfig b/configs/am65x_evm_r5_defconfig index 3814872ec7a..7e81a98454d 100644 --- a/configs/am65x_evm_r5_defconfig +++ b/configs/am65x_evm_r5_defconfig @@ -3,7 +3,7 @@ CONFIG_ARCH_K3=y CONFIG_SPL_GPIO_SUPPORT=y CONFIG_SPL_LIBCOMMON_SUPPORT=y CONFIG_SPL_LIBGENERIC_SUPPORT=y -CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SYS_MALLOC_F_LEN=0x55000 CONFIG_SOC_K3_AM6=y CONFIG_TARGET_AM654_R5_EVM=y CONFIG_SPL_MMC_SUPPORT=y @@ -18,9 +18,11 @@ CONFIG_SPL_LOAD_FIT=y CONFIG_USE_BOOTCOMMAND=y # CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_TEXT_BASE=0x41c00000 -CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_STACK_R=y CONFIG_SPL_SEPARATE_BSS=y +CONFIG_SPL_EARLY_BSS=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x400 CONFIG_SPL_I2C_SUPPORT=y CONFIG_SPL_DM_MAILBOX=y CONFIG_SPL_DM_RESET=y @@ -35,6 +37,7 @@ CONFIG_CMD_BOOTZ=y CONFIG_CMD_ASKENV=y # CONFIG_CMD_FLASH is not set CONFIG_CMD_GPT=y +CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_REMOTEPROC=y # CONFIG_CMD_SETEXPR is not set @@ -51,6 +54,8 @@ CONFIG_ENV_FAT_DEVICE_AND_PART="1:1" CONFIG_DM=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_REGMAP=y +CONFIG_SPL_REGMAP=y CONFIG_SPL_OF_TRANSLATE=y CONFIG_CLK=y CONFIG_SPL_CLK=y @@ -58,12 +63,15 @@ CONFIG_CLK_TI_SCI=y CONFIG_TI_SCI_PROTOCOL=y CONFIG_DM_GPIO=y CONFIG_DA8XX_GPIO=y +CONFIG_DM_I2C=y +CONFIG_I2C_SET_DEFAULT_BUS_NUM=y +CONFIG_SYS_I2C_OMAP24XX=y CONFIG_DM_MAILBOX=y CONFIG_K3_SEC_PROXY=y CONFIG_MISC=y CONFIG_DM_MMC=y CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_K3_ARASAN=y +CONFIG_MMC_SDHCI_AM654=y CONFIG_PINCTRL=y # CONFIG_PINCTRL_GENERIC is not set CONFIG_SPL_PINCTRL=y @@ -88,3 +96,4 @@ CONFIG_SYSRESET_TI_SCI=y CONFIG_TIMER=y CONFIG_SPL_TIMER=y CONFIG_OMAP_TIMER=y +CONFIG_FS_FAT_MAX_CLUSTSIZE=16384 diff --git a/configs/am65x_hs_evm_a53_defconfig b/configs/am65x_hs_evm_a53_defconfig index 9c55cd37f65..56052f73f38 100644 --- a/configs/am65x_hs_evm_a53_defconfig +++ b/configs/am65x_hs_evm_a53_defconfig @@ -3,7 +3,7 @@ CONFIG_ARCH_K3=y CONFIG_TI_SECURE_DEVICE=y CONFIG_SPL_LIBCOMMON_SUPPORT=y CONFIG_SPL_LIBGENERIC_SUPPORT=y -CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SOC_K3_AM6=y CONFIG_TARGET_AM654_A53_EVM=y CONFIG_SPL_MMC_SUPPORT=y @@ -19,12 +19,14 @@ CONFIG_FIT_IMAGE_POST_PROCESS=y CONFIG_SPL_LOAD_FIT=y CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y CONFIG_OF_BOARD_SETUP=y -CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run run_kern" +CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run get_overlay_${boot}; run run_kern" # CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_TEXT_BASE=0x80080000 CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_STACK_R=y CONFIG_SPL_SEPARATE_BSS=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1400 CONFIG_SPL_I2C_SUPPORT=y CONFIG_SPL_DM_MAILBOX=y CONFIG_SPL_DM_RESET=y @@ -33,6 +35,7 @@ CONFIG_SPL_REMOTEPROC=y CONFIG_SPL_YMODEM_SUPPORT=y CONFIG_CMD_ASKENV=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_REMOTEPROC=y # CONFIG_CMD_SETEXPR is not set @@ -56,6 +59,11 @@ CONFIG_CLK_TI_SCI=y CONFIG_DMA_CHANNELS=y CONFIG_TI_K3_NAVSS_UDMA=y CONFIG_TI_SCI_PROTOCOL=y +CONFIG_DM_GPIO=y +CONFIG_DM_PCA953X=y +CONFIG_DM_I2C=y +CONFIG_I2C_SET_DEFAULT_BUS_NUM=y +CONFIG_SYS_I2C_OMAP24XX=y CONFIG_DM_MAILBOX=y CONFIG_K3_SEC_PROXY=y CONFIG_DM_MMC=y @@ -77,3 +85,4 @@ CONFIG_SOC_TI=y CONFIG_SYSRESET=y CONFIG_SPL_SYSRESET=y CONFIG_SYSRESET_TI_SCI=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/configs/am65x_hs_evm_r5_defconfig b/configs/am65x_hs_evm_r5_defconfig index 0b12f15782e..d378d1e9ee8 100644 --- a/configs/am65x_hs_evm_r5_defconfig +++ b/configs/am65x_hs_evm_r5_defconfig @@ -4,7 +4,7 @@ CONFIG_TI_SECURE_DEVICE=y CONFIG_SPL_GPIO_SUPPORT=y CONFIG_SPL_LIBCOMMON_SUPPORT=y CONFIG_SPL_LIBGENERIC_SUPPORT=y -CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SYS_MALLOC_F_LEN=0x55000 CONFIG_SOC_K3_AM6=y CONFIG_TARGET_AM654_R5_EVM=y CONFIG_SPL_MMC_SUPPORT=y @@ -20,9 +20,11 @@ CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y CONFIG_USE_BOOTCOMMAND=y # CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_TEXT_BASE=0x41c00000 -CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_STACK_R=y CONFIG_SPL_SEPARATE_BSS=y +CONFIG_SPL_EARLY_BSS=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x400 CONFIG_SPL_I2C_SUPPORT=y CONFIG_SPL_DM_MAILBOX=y CONFIG_SPL_DM_RESET=y @@ -37,6 +39,7 @@ CONFIG_CMD_BOOTZ=y CONFIG_CMD_ASKENV=y # CONFIG_CMD_FLASH is not set CONFIG_CMD_GPT=y +CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_REMOTEPROC=y # CONFIG_CMD_SETEXPR is not set @@ -60,6 +63,9 @@ CONFIG_CLK_TI_SCI=y CONFIG_TI_SCI_PROTOCOL=y CONFIG_DM_GPIO=y CONFIG_DA8XX_GPIO=y +CONFIG_DM_I2C=y +CONFIG_I2C_SET_DEFAULT_BUS_NUM=y +CONFIG_SYS_I2C_OMAP24XX=y CONFIG_DM_MAILBOX=y CONFIG_K3_SEC_PROXY=y CONFIG_MISC=y @@ -90,3 +96,4 @@ CONFIG_SYSRESET_TI_SCI=y CONFIG_TIMER=y CONFIG_SPL_TIMER=y CONFIG_OMAP_TIMER=y +CONFIG_FS_FAT_MAX_CLUSTSIZE=16384 diff --git a/configs/evb-ast2500_defconfig b/configs/evb-ast2500_defconfig index b73da72b165..59d41cb5687 100644 --- a/configs/evb-ast2500_defconfig +++ b/configs/evb-ast2500_defconfig @@ -11,16 +11,19 @@ CONFIG_BOOTARGS="console=ttyS4,115200n8 root=/dev/ram rw" CONFIG_PRE_CONSOLE_BUFFER=y CONFIG_PRE_CON_BUF_ADDR=0x1e720000 # CONFIG_DISPLAY_CPUINFO is not set +CONFIG_HUSH_PARSER=y # CONFIG_AUTO_COMPLETE is not set CONFIG_CMD_I2C=y CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y CONFIG_DEFAULT_DEVICE_TREE="ast2500-evb" +CONFIG_NET_RANDOM_ETHADDR=y CONFIG_REGMAP=y CONFIG_CLK=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_ASPEED=y +# CONFIG_MMC is not set CONFIG_PHY_REALTEK=y CONFIG_DM_ETH=y CONFIG_FTGMAC100=y diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 5ef0f71c8b7..d1d12eef385 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -108,6 +108,48 @@ static int init_range(ofnode node, struct regmap_range *range, int addr_len, return 0; } +int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index) +{ + struct regmap *map; + int addr_len, size_len; + int ret; + + addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node)); + if (addr_len < 0) { + debug("%s: Error while reading the addr length (ret = %d)\n", + ofnode_get_name(node), addr_len); + return addr_len; + } + + size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node)); + if (size_len < 0) { + debug("%s: Error while reading the size length: (ret = %d)\n", + ofnode_get_name(node), size_len); + return size_len; + } + + map = regmap_alloc(1); + if (!map) + return -ENOMEM; + + ret = init_range(node, map->ranges, addr_len, size_len, index); + if (ret) + return ret; + + if (ofnode_read_bool(node, "little-endian")) + map->endianness = REGMAP_LITTLE_ENDIAN; + else if (ofnode_read_bool(node, "big-endian")) + map->endianness = REGMAP_BIG_ENDIAN; + else if (ofnode_read_bool(node, "native-endian")) + map->endianness = REGMAP_NATIVE_ENDIAN; + else /* Default: native endianness */ + map->endianness = REGMAP_NATIVE_ENDIAN; + + *mapp = map; + + return ret; +} + int regmap_init_mem(ofnode node, struct regmap **mapp) { struct regmap_range *range; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 095a9bc6a4d..4772db38372 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -330,7 +330,7 @@ endif config SYS_I2C_OMAP24XX bool "TI OMAP2+ I2C driver" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS || ARCH_K3 help Add support for the OMAP2+ I2C driver. diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 890ef358a00..4cdae41b59a 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -468,14 +468,15 @@ config MMC_SDHCI_CADENCE If unsure, say N. -config MMC_SDHCI_K3_ARASAN - bool "Arasan SDHCI controller for TI's K3 based SoCs" +config MMC_SDHCI_AM654 + bool "SDHCI Controller on TI's Am654 devices" depends on ARCH_K3 depends on MMC_SDHCI depends on DM_MMC && OF_CONTROL && BLK + depends on REGMAP help - Support for Arasan SDHCI host controller on Texas Instruments' - K3 family based SoC platforms + Support for Secure Digital Host Controller Interface (SDHCI) + controllers present on TI's AM654 SOCs. config MMC_SDHCI_KONA bool "SDHCI support on Broadcom KONA platform" diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 3c8c53a9e16..6cc018bb672 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -50,7 +50,7 @@ obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o -obj-$(CONFIG_MMC_SDHCI_K3_ARASAN) += k3_arsan_sdhci.o +obj-$(CONFIG_MMC_SDHCI_AM654) += am654_sdhci.o obj-$(CONFIG_MMC_SDHCI_KONA) += kona_sdhci.o obj-$(CONFIG_MMC_SDHCI_MSM) += msm_sdhci.o obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c new file mode 100644 index 00000000000..fb0fb580706 --- /dev/null +++ b/drivers/mmc/am654_sdhci.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * + * Texas Instruments' K3 SD Host Controller Interface + */ + +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <power-domain.h> +#include <regmap.h> +#include <sdhci.h> + +/* CTL_CFG Registers */ +#define CTL_CFG_2 0x14 + +#define SLOTTYPE_MASK GENMASK(31, 30) +#define SLOTTYPE_EMBEDDED BIT(30) + +/* PHY Registers */ +#define PHY_CTRL1 0x100 +#define PHY_CTRL2 0x104 +#define PHY_CTRL3 0x108 +#define PHY_CTRL4 0x10C +#define PHY_CTRL5 0x110 +#define PHY_CTRL6 0x114 +#define PHY_STAT1 0x130 +#define PHY_STAT2 0x134 + +#define IOMUX_ENABLE_SHIFT 31 +#define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT) +#define OTAPDLYENA_SHIFT 20 +#define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT) +#define OTAPDLYSEL_SHIFT 12 +#define OTAPDLYSEL_MASK GENMASK(15, 12) +#define STRBSEL_SHIFT 24 +#define STRBSEL_MASK GENMASK(27, 24) +#define SEL50_SHIFT 8 +#define SEL50_MASK BIT(SEL50_SHIFT) +#define SEL100_SHIFT 9 +#define SEL100_MASK BIT(SEL100_SHIFT) +#define DLL_TRIM_ICP_SHIFT 4 +#define DLL_TRIM_ICP_MASK GENMASK(7, 4) +#define DR_TY_SHIFT 20 +#define DR_TY_MASK GENMASK(22, 20) +#define ENDLL_SHIFT 1 +#define ENDLL_MASK BIT(ENDLL_SHIFT) +#define DLLRDY_SHIFT 0 +#define DLLRDY_MASK BIT(DLLRDY_SHIFT) +#define PDB_SHIFT 0 +#define PDB_MASK BIT(PDB_SHIFT) +#define CALDONE_SHIFT 1 +#define CALDONE_MASK BIT(CALDONE_SHIFT) +#define RETRIM_SHIFT 17 +#define RETRIM_MASK BIT(RETRIM_SHIFT) + +#define DRIVER_STRENGTH_50_OHM 0x0 +#define DRIVER_STRENGTH_33_OHM 0x1 +#define DRIVER_STRENGTH_66_OHM 0x2 +#define DRIVER_STRENGTH_100_OHM 0x3 +#define DRIVER_STRENGTH_40_OHM 0x4 + +#define AM654_SDHCI_MIN_FREQ 400000 + +struct am654_sdhci_plat { + struct mmc_config cfg; + struct mmc mmc; + struct regmap *base; + bool non_removable; + u32 otap_del_sel; + u32 trm_icp; + u32 drv_strength; + bool dll_on; +}; + +static void am654_sdhci_set_control_reg(struct sdhci_host *host) +{ + struct mmc *mmc = (struct mmc *)host->mmc; + u32 reg; + + if (IS_SD(host->mmc) && + mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); + } + + sdhci_set_uhs_timing(host); +} + +static int am654_sdhci_set_ios_post(struct sdhci_host *host) +{ + struct udevice *dev = host->mmc->dev; + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + unsigned int speed = host->mmc->clock; + int sel50, sel100; + u32 mask, val; + int ret; + + /* Reset SD Clock Enable */ + val = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + val &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, val, SDHCI_CLOCK_CONTROL); + + /* power off phy */ + if (plat->dll_on) { + regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0); + + plat->dll_on = false; + } + + /* restart clock */ + sdhci_set_clock(host->mmc, speed); + + /* switch phy back on */ + if (speed > AM654_SDHCI_MIN_FREQ) { + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + val = (1 << OTAPDLYENA_SHIFT) | + (plat->otap_del_sel << OTAPDLYSEL_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL4, mask, val); + switch (speed) { + case 200000000: + sel50 = 0; + sel100 = 0; + break; + case 100000000: + sel50 = 0; + sel100 = 1; + break; + default: + sel50 = 1; + sel100 = 0; + } + + /* Configure PHY DLL frequency */ + mask = SEL50_MASK | SEL100_MASK; + val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL5, mask, val); + + /* Enable DLL */ + regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, + 0x1 << ENDLL_SHIFT); + /* + * Poll for DLL ready. Use a one second timeout. + * Works in all experiments done so far + */ + ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val, + val & DLLRDY_MASK, 1000, 1000000); + if (ret) + return ret; + + plat->dll_on = true; + } + + return 0; +} + +const struct sdhci_ops am654_sdhci_ops = { + .set_ios_post = &am654_sdhci_set_ios_post, + .set_control_reg = &am654_sdhci_set_control_reg, +}; + +int am654_sdhci_init(struct am654_sdhci_plat *plat) +{ + u32 ctl_cfg_2 = 0; + u32 mask, val; + int ret; + + /* Reset OTAP to default value */ + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0); + + regmap_read(plat->base, PHY_STAT1, &val); + if (~val & CALDONE_MASK) { + /* Calibrate IO lines */ + regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK, PDB_MASK); + ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val, + val & CALDONE_MASK, 1, 20); + if (ret) + return ret; + } + + /* Configure DLL TRIM */ + mask = DLL_TRIM_ICP_MASK; + val = plat->trm_icp << DLL_TRIM_ICP_SHIFT; + + /* Configure DLL driver strength */ + mask |= DR_TY_MASK; + val |= plat->drv_strength << DR_TY_SHIFT; + regmap_update_bits(plat->base, PHY_CTRL1, mask, val); + + /* Enable pins by setting IO mux to 0 */ + regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0); + + /* Set slot type based on SD or eMMC */ + if (plat->non_removable) + ctl_cfg_2 = SLOTTYPE_EMBEDDED; + + regmap_update_bits(plat->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2); + + return 0; +} + +static int am654_sdhci_probe(struct udevice *dev) +{ + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct sdhci_host *host = dev_get_priv(dev); + struct mmc_config *cfg = &plat->cfg; + struct power_domain sdhci_pwrdmn; + struct clk clk; + unsigned long clock; + int ret; + + ret = power_domain_get_by_index(dev, &sdhci_pwrdmn, 0); + if (!ret) { + ret = power_domain_on(&sdhci_pwrdmn); + if (ret) { + dev_err(dev, "Power domain on failed (%d)\n", ret); + return ret; + } + } else if (ret != -ENOENT && ret != -ENODEV && ret != -ENOSYS) { + dev_err(dev, "failed to get power domain (%d)\n", ret); + return ret; + } + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) { + dev_err(dev, "failed to get clock\n"); + return ret; + } + + clock = clk_get_rate(&clk); + if (IS_ERR_VALUE(clock)) { + dev_err(dev, "failed to get rate\n"); + return clock; + } + + host->max_clk = clock; + host->mmc = &plat->mmc; + host->mmc->dev = dev; + ret = sdhci_setup_cfg(cfg, host, cfg->f_max, + AM654_SDHCI_MIN_FREQ); + if (ret) + return ret; + host->ops = &am654_sdhci_ops; + host->mmc->priv = host; + upriv->mmc = host->mmc; + + regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1); + + am654_sdhci_init(plat); + + return sdhci_probe(dev); +} + +static int am654_sdhci_ofdata_to_platdata(struct udevice *dev) +{ + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + struct sdhci_host *host = dev_get_priv(dev); + struct mmc_config *cfg = &plat->cfg; + u32 drv_strength; + int ret; + + host->name = dev->name; + host->ioaddr = (void *)dev_read_addr(dev); + plat->non_removable = dev_read_bool(dev, "non-removable"); + + ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp); + if (ret) + return ret; + + ret = dev_read_u32(dev, "ti,otap-del-sel", &plat->otap_del_sel); + if (ret) + return ret; + + ret = dev_read_u32(dev, "ti,driver-strength-ohm", &drv_strength); + if (ret) + return ret; + + switch (drv_strength) { + case 50: + plat->drv_strength = DRIVER_STRENGTH_50_OHM; + break; + case 33: + plat->drv_strength = DRIVER_STRENGTH_33_OHM; + break; + case 66: + plat->drv_strength = DRIVER_STRENGTH_66_OHM; + break; + case 100: + plat->drv_strength = DRIVER_STRENGTH_100_OHM; + break; + case 40: + plat->drv_strength = DRIVER_STRENGTH_40_OHM; + break; + default: + dev_err(dev, "Invalid driver strength\n"); + return -EINVAL; + } + + ret = mmc_of_parse(dev, cfg); + if (ret) + return ret; + + return 0; +} + +static int am654_sdhci_bind(struct udevice *dev) +{ + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + + return sdhci_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id am654_sdhci_ids[] = { + { .compatible = "ti,am654-sdhci-5.1" }, + { } +}; + +U_BOOT_DRIVER(am654_sdhci_drv) = { + .name = "am654_sdhci", + .id = UCLASS_MMC, + .of_match = am654_sdhci_ids, + .ofdata_to_platdata = am654_sdhci_ofdata_to_platdata, + .ops = &sdhci_ops, + .bind = am654_sdhci_bind, + .probe = am654_sdhci_probe, + .priv_auto_alloc_size = sizeof(struct sdhci_host), + .platdata_auto_alloc_size = sizeof(struct am654_sdhci_plat), +}; diff --git a/drivers/mmc/k3_arsan_sdhci.c b/drivers/mmc/k3_arsan_sdhci.c deleted file mode 100644 index d5f28573825..00000000000 --- a/drivers/mmc/k3_arsan_sdhci.c +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ - * - * Texas Instruments' K3 SD Host Controller Interface - */ - -#include <clk.h> -#include <common.h> -#include <dm.h> -#include <malloc.h> -#include <power-domain.h> -#include <sdhci.h> - -#define K3_ARASAN_SDHCI_MIN_FREQ 0 - -struct k3_arasan_sdhci_plat { - struct mmc_config cfg; - struct mmc mmc; - unsigned int f_max; -}; - -static int k3_arasan_sdhci_probe(struct udevice *dev) -{ - struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev); - struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); - struct sdhci_host *host = dev_get_priv(dev); - struct power_domain sdhci_pwrdmn; - struct clk clk; - unsigned long clock; - int ret; - - ret = power_domain_get_by_index(dev, &sdhci_pwrdmn, 0); - if (ret) { - dev_err(dev, "failed to get power domain\n"); - return ret; - } - - ret = power_domain_on(&sdhci_pwrdmn); - if (ret) { - dev_err(dev, "Power domain on failed\n"); - return ret; - } - - ret = clk_get_by_index(dev, 0, &clk); - if (ret) { - dev_err(dev, "failed to get clock\n"); - return ret; - } - - clock = clk_get_rate(&clk); - if (IS_ERR_VALUE(clock)) { - dev_err(dev, "failed to get rate\n"); - return clock; - } - - host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | - SDHCI_QUIRK_BROKEN_R1B; - - host->max_clk = clock; - - ret = sdhci_setup_cfg(&plat->cfg, host, plat->f_max, - K3_ARASAN_SDHCI_MIN_FREQ); - host->mmc = &plat->mmc; - if (ret) - return ret; - host->mmc->priv = host; - host->mmc->dev = dev; - upriv->mmc = host->mmc; - - return sdhci_probe(dev); -} - -static int k3_arasan_sdhci_ofdata_to_platdata(struct udevice *dev) -{ - struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev); - struct sdhci_host *host = dev_get_priv(dev); - - host->name = dev->name; - host->ioaddr = (void *)dev_read_addr(dev); - host->bus_width = dev_read_u32_default(dev, "bus-width", 4); - plat->f_max = dev_read_u32_default(dev, "max-frequency", 0); - - return 0; -} - -static int k3_arasan_sdhci_bind(struct udevice *dev) -{ - struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev); - - return sdhci_bind(dev, &plat->mmc, &plat->cfg); -} - -static const struct udevice_id k3_arasan_sdhci_ids[] = { - { .compatible = "arasan,sdhci-5.1" }, - { } -}; - -U_BOOT_DRIVER(k3_arasan_sdhci_drv) = { - .name = "k3_arasan_sdhci", - .id = UCLASS_MMC, - .of_match = k3_arasan_sdhci_ids, - .ofdata_to_platdata = k3_arasan_sdhci_ofdata_to_platdata, - .ops = &sdhci_ops, - .bind = k3_arasan_sdhci_bind, - .probe = k3_arasan_sdhci_probe, - .priv_auto_alloc_size = sizeof(struct sdhci_host), - .platdata_auto_alloc_size = sizeof(struct k3_arasan_sdhci_plat), -}; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index c4e88790bc6..0a0770cc203 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -8,6 +8,7 @@ */ #include <common.h> +#include <dm.h> #include <errno.h> #include <malloc.h> #include <mmc.h> @@ -409,7 +410,7 @@ static int sdhci_execute_tuning(struct udevice *dev, uint opcode) return 0; } #endif -static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) +int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv; unsigned int div, clk = 0, timeout; @@ -533,6 +534,34 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); } +void sdhci_set_uhs_timing(struct sdhci_host *host) +{ + struct mmc *mmc = (struct mmc *)host->mmc; + u32 reg; + + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg &= ~SDHCI_CTRL_UHS_MASK; + + switch (mmc->selected_mode) { + case UHS_SDR50: + case MMC_HS_52: + reg |= SDHCI_CTRL_UHS_SDR50; + break; + case UHS_DDR50: + case MMC_DDR_52: + reg |= SDHCI_CTRL_UHS_DDR50; + break; + case UHS_SDR104: + case MMC_HS_200: + reg |= SDHCI_CTRL_UHS_SDR104; + break; + default: + reg |= SDHCI_CTRL_UHS_SDR12; + } + + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); +} + #ifdef CONFIG_DM_MMC static int sdhci_set_ios(struct udevice *dev) { @@ -583,7 +612,7 @@ static int sdhci_set_ios(struct mmc *mmc) /* If available, call the driver specific "post" set_ios() function */ if (host->ops && host->ops->set_ios_post) - host->ops->set_ios_post(host); + return host->ops->set_ios_post(host); return 0; } @@ -681,8 +710,18 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, u32 f_max, u32 f_min) { u32 caps, caps_1 = 0; +#if CONFIG_IS_ENABLED(DM_MMC) + u32 mask[2] = {0}; + int ret; + ret = dev_read_u32_array(host->mmc->dev, "sdhci-caps-mask", + mask, 2); + if (ret && ret != -1) + return ret; + caps = ~mask[1] & sdhci_readl(host, SDHCI_CAPABILITIES); +#else caps = sdhci_readl(host, SDHCI_CAPABILITIES); +#endif #ifdef CONFIG_MMC_SDHCI_SDMA if (!(caps & SDHCI_CAN_DO_SDMA)) { @@ -722,7 +761,11 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, /* Check whether the clock multiplier is supported or not */ if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { +#if CONFIG_IS_ENABLED(DM_MMC) + caps_1 = ~mask[0] & sdhci_readl(host, SDHCI_CAPABILITIES_1); +#else caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); +#endif host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; } @@ -779,9 +822,6 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, cfg->host_caps &= ~MMC_MODE_HS_52MHz; } - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); - if (!(cfg->voltages & MMC_VDD_165_195) || (host->quirks & SDHCI_QUIRK_NO_1_8_V)) caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c index b5765113380..829b75683b2 100644 --- a/drivers/mmc/xenon_sdhci.c +++ b/drivers/mmc/xenon_sdhci.c @@ -326,7 +326,7 @@ static void xenon_mask_cmd_conflict_err(struct sdhci_host *host) } /* Platform specific function for post set_ios configuration */ -static void xenon_sdhci_set_ios_post(struct sdhci_host *host) +static int xenon_sdhci_set_ios_post(struct sdhci_host *host) { struct xenon_sdhci_priv *priv = host->mmc->priv; uint speed = host->mmc->tran_speed; @@ -364,6 +364,8 @@ static void xenon_sdhci_set_ios_post(struct sdhci_host *host) /* Re-init the PHY */ xenon_mmc_phy_set(host); + + return 0; } /* Install a driver specific handler for post set_ios configuration */ diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 08023783de4..c525084250c 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -48,11 +48,6 @@ static const u8 mode2timing[] = { [MMC_HS_200] = MMC_HS200_BUS_SPEED, }; -#define SDHCI_HOST_CTRL2 0x3E -#define SDHCI_CTRL2_MODE_MASK 0x7 -#define SDHCI_18V_SIGNAL 0x8 -#define SDHCI_CTRL_EXEC_TUNING 0x0040 -#define SDHCI_CTRL_TUNED_CLK 0x80 #define SDHCI_TUNING_LOOP_COUNT 40 static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid) @@ -99,9 +94,9 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) host = priv->host; deviceid = priv->deviceid; - ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2); + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ctrl |= SDHCI_CTRL_EXEC_TUNING; - sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2); + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); mdelay(1); @@ -133,7 +128,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); mmc_send_cmd(mmc, &cmd, NULL); - ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2); + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK) udelay(1); @@ -142,7 +137,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) if (tuning_loop_counter < 0) { ctrl &= ~SDHCI_CTRL_TUNED_CLK; - sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2); + sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL2); } if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { @@ -184,36 +179,14 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host) return; if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { - reg = sdhci_readw(host, SDHCI_HOST_CTRL2); - reg |= SDHCI_18V_SIGNAL; - sdhci_writew(host, reg, SDHCI_HOST_CTRL2); + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); } if (mmc->selected_mode > SD_HS && - mmc->selected_mode <= UHS_DDR50) { - reg = sdhci_readw(host, SDHCI_HOST_CTRL2); - reg &= ~SDHCI_CTRL2_MODE_MASK; - switch (mmc->selected_mode) { - case UHS_SDR12: - reg |= UHS_SDR12_BUS_SPEED; - break; - case UHS_SDR25: - reg |= UHS_SDR25_BUS_SPEED; - break; - case UHS_SDR50: - reg |= UHS_SDR50_BUS_SPEED; - break; - case UHS_SDR104: - reg |= UHS_SDR104_BUS_SPEED; - break; - case UHS_DDR50: - reg |= UHS_DDR50_BUS_SPEED; - break; - default: - break; - } - sdhci_writew(host, reg, SDHCI_HOST_CTRL2); - } + mmc->selected_mode <= UHS_DDR50) + sdhci_set_uhs_timing(host); } #endif diff --git a/include/configs/am65x_evm.h b/include/configs/am65x_evm.h index b043bf886bf..1415bb1b153 100644 --- a/include/configs/am65x_evm.h +++ b/include/configs/am65x_evm.h @@ -19,6 +19,32 @@ #define CONFIG_SYS_SDRAM_BASE1 0x880000000 /* SPL Loader Configuration */ +#ifdef CONFIG_TARGET_AM654_A53_EVM +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SPL_TEXT_BASE + \ + CONFIG_SYS_K3_NON_SECURE_MSRAM_SIZE) +#else +/* + * Maximum size in memory allocated to the SPL BSS. Keep it as tight as + * possible (to allow the build to go through), as this directly affects + * our memory footprint. The less we use for BSS the more we have available + * for everything else. + */ +#define CONFIG_SPL_BSS_MAX_SIZE 0x5000 +/* + * Link BSS to be within SPL in a dedicated region located near the top of + * the MCU SRAM, this way making it available also before relocation. Note + * that we are not using the actual top of the MCU SRAM as there is a memory + * location filled in by the boot ROM that we want to read out without any + * interference from the C context. + */ +#define CONFIG_SPL_BSS_START_ADDR (CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX -\ + CONFIG_SPL_BSS_MAX_SIZE) +/* Set the stack right below the SPL BSS section */ +#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SPL_BSS_START_ADDR +/* Configure R5 SPL post-relocation malloc pool in DDR */ +#define CONFIG_SYS_SPL_MALLOC_START 0x84000000 +#define CONFIG_SYS_SPL_MALLOC_SIZE SZ_16M +#endif #ifdef CONFIG_SYS_K3_SPL_ATF #define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "tispl.bin" @@ -29,26 +55,26 @@ #endif #define CONFIG_SPL_MAX_SIZE CONFIG_SYS_K3_MAX_DOWNLODABLE_IMAGE_SIZE -#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SPL_TEXT_BASE + \ - CONFIG_SYS_K3_NON_SECURE_MSRAM_SIZE - 4) #define CONFIG_SYS_BOOTM_LEN SZ_64M +#define PARTS_DEFAULT \ + /* Linux partitions */ \ + "name=rootfs,start=0,size=-,uuid=${uuid_gpt_rootfs}\0" + /* U-Boot general configuration */ #define EXTRA_ENV_AM65X_BOARD_SETTINGS \ "findfdt=" \ - "if test $board_name = am65x; then " \ - "setenv name_fdt k3-am654-base-board.dtb; " \ - "else if test $name_fdt = undefined; then " \ - "echo WARNING: Could not determine device tree to use;"\ - "fi; fi; " \ - "setenv fdtfile ${name_fdt}\0" \ + "setenv name_fdt k3-am654-base-board.dtb;" \ + "setenv fdtfile ${name_fdt};" \ + "setenv overlay_files ${name_overlays}\0" \ "loadaddr=0x80080000\0" \ "fdtaddr=0x82000000\0" \ + "overlayaddr=0x83000000\0" \ "name_kern=Image\0" \ "console=ttyS2,115200n8\0" \ "args_all=setenv optargs earlycon=ns16550a,mmio32,0x02800000\0" \ - "run_kern=booti ${loadaddr} ${rd_spec} ${fdtaddr}\0" + "run_kern=booti ${loadaddr} ${rd_spec} ${fdtaddr}\0" \ /* U-Boot MMC-specific configuration */ #define EXTRA_ENV_AM65X_BOARD_SETTINGS_MMC \ @@ -59,8 +85,17 @@ "rd_spec=-\0" \ "init_mmc=run args_all args_mmc\0" \ "get_fdt_mmc=load mmc ${bootpart} ${fdtaddr} ${bootdir}/${name_fdt}\0" \ + "get_overlay_mmc=" \ + "fdt address ${fdtaddr};" \ + "fdt resize 0x100000;" \ + "for overlay in $overlay_files;" \ + "do;" \ + "load mmc ${bootpart} ${overlayaddr} ${bootdir}/${overlay};" \ + "fdt apply ${overlayaddr};" \ + "done;\0" \ "get_kern_mmc=load mmc ${bootpart} ${loadaddr} " \ - "${bootdir}/${name_kern}\0" + "${bootdir}/${name_kern}\0" \ + "partitions=" PARTS_DEFAULT /* Incorporate settings into the U-Boot environment */ #define CONFIG_EXTRA_ENV_SETTINGS \ @@ -68,6 +103,18 @@ EXTRA_ENV_AM65X_BOARD_SETTINGS \ EXTRA_ENV_AM65X_BOARD_SETTINGS_MMC +/* MMC ENV related defines */ +#ifdef CONFIG_ENV_IS_IN_MMC +#define CONFIG_SYS_MMC_ENV_DEV 0 +#define CONFIG_SYS_MMC_ENV_PART 1 +#define CONFIG_ENV_SIZE (128 << 10) +#define CONFIG_ENV_OFFSET 0x680000 +#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) +#define CONFIG_SYS_REDUNDAND_ENVIRONMENT +#endif + +#define CONFIG_SUPPORT_EMMC_BOOT + /* Now for the remaining common defines */ #include <configs/ti_armv7_common.h> diff --git a/include/regmap.h b/include/regmap.h index 3cd7a66cea7..0854200a9c1 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -330,6 +330,8 @@ int regmap_init_mem(ofnode node, struct regmap **mapp); int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count, struct regmap **mapp); +int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index); + /** * regmap_get_range() - Obtain the base memory address of a regmap range * diff --git a/include/sdhci.h b/include/sdhci.h index eee493ab5f5..01addb7a603 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -144,7 +144,23 @@ #define SDHCI_ACMD12_ERR 0x3C -/* 3E-3F reserved */ +#define SDHCI_HOST_CONTROL2 0x3E +#define SDHCI_CTRL_UHS_MASK 0x0007 +#define SDHCI_CTRL_UHS_SDR12 0x0000 +#define SDHCI_CTRL_UHS_SDR25 0x0001 +#define SDHCI_CTRL_UHS_SDR50 0x0002 +#define SDHCI_CTRL_UHS_SDR104 0x0003 +#define SDHCI_CTRL_UHS_DDR50 0x0004 +#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */ +#define SDHCI_CTRL_VDD_180 0x0008 +#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 +#define SDHCI_CTRL_DRV_TYPE_B 0x0000 +#define SDHCI_CTRL_DRV_TYPE_A 0x0010 +#define SDHCI_CTRL_DRV_TYPE_C 0x0020 +#define SDHCI_CTRL_DRV_TYPE_D 0x0030 +#define SDHCI_CTRL_EXEC_TUNING 0x0040 +#define SDHCI_CTRL_TUNED_CLK 0x0080 +#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 #define SDHCI_CAPABILITIES 0x40 #define SDHCI_TIMEOUT_CLK_MASK 0x0000003F @@ -247,7 +263,7 @@ struct sdhci_ops { #endif int (*get_cd)(struct sdhci_host *host); void (*set_control_reg)(struct sdhci_host *host); - void (*set_ios_post)(struct sdhci_host *host); + int (*set_ios_post)(struct sdhci_host *host); void (*set_clock)(struct sdhci_host *host, u32 div); int (*platform_execute_tuning)(struct mmc *host, u8 opcode); void (*set_delay)(struct sdhci_host *host); @@ -467,9 +483,11 @@ int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg); int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min); #endif /* !CONFIG_BLK */ +void sdhci_set_uhs_timing(struct sdhci_host *host); #ifdef CONFIG_DM_MMC /* Export the operations to drivers */ int sdhci_probe(struct udevice *dev); +int sdhci_set_clock(struct mmc *mmc, unsigned int clock); extern const struct dm_mmc_ops sdhci_ops; #else #endif diff --git a/include/spl.h b/include/spl.h index a9aaef345fa..a90f971a239 100644 --- a/include/spl.h +++ b/include/spl.h @@ -109,6 +109,15 @@ struct spl_load_info { binman_sym_extern(ulong, u_boot_any, image_pos); /** + * spl_load_simple_fit_skip_processing() - Hook to allow skipping the FIT + * image processing during spl_load_simple_fit(). + * + * Return true to skip FIT processing, false to preserve the full code flow + * of spl_load_simple_fit(). + */ +bool spl_load_simple_fit_skip_processing(void); + +/** * spl_load_simple_fit() - Loads a fit image from a device. * @spl_image: Image description to set up * @info: Structure containing the information required to load data. @@ -331,6 +340,23 @@ int spl_mmc_load_image(struct spl_image_info *spl_image, struct spl_boot_device *bootdev); /** + * spl_mmc_load() - Load an image file from MMC/SD media + * + * @param spl_image Image data filled in by loading process + * @param bootdev Describes which device to load from + * @param filename Name of file to load (in FS mode) + * @param raw_part Partition to load from (in RAW mode) + * @param raw_sect Sector to load from (in RAW mode) + * + * @return 0 on success, otherwise error code + */ +int spl_mmc_load(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev, + const char *filename, + int raw_part, + unsigned long raw_sect); + +/** * spl_invoke_atf - boot using an ARM trusted firmware image */ void spl_invoke_atf(struct spl_image_info *spl_image); |