Merge branch '2019-07-17-master-imports'

- Various FS/disk related fixes with security implications.
- Proper fix for the pci_ep test.
- Assorted bugfixes
- Some MediaTek updates.
- 'env erase' support.
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..e27d86f
--- /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 6662ca1..f20268b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -384,6 +384,13 @@
         - 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 adcd634..39fec03 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 8c611d1..1fd0277 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 1f591ef..1f85006 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 9d1ed49..4727193 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 844a5cd..449b1dd 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";
@@ -250,6 +220,14 @@
 
 &k3_reset {
 	u-boot,dm-spl;
+};
+
+&wkup_pmx0 {
+	u-boot,dm-spl;
+
+	wkup_i2c0_pins_default {
+		u-boot,dm-spl;
+	};
 };
 
 &main_pmx0 {
@@ -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 af6956f..e73b9aa 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 a07038b..9d9b3d5 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,10 +136,56 @@
 		>;
 		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 {
 	vtt-supply = <&vtt_supply>;
 	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 c1695cb..a697540 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 30fba20..c74641d 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 @@
 	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 @@
 	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 @@
 	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 e677a2e..f25f822 100644
--- a/arch/arm/mach-k3/Kconfig
+++ b/arch/arm/mach-k3/Kconfig
@@ -58,6 +58,45 @@
 	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 0c3a4f7..3af7f2e 100644
--- a/arch/arm/mach-k3/Makefile
+++ b/arch/arm/mach-k3/Makefile
@@ -7,4 +7,7 @@
 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 60a5803..cb96581 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 @@
 
 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 @@
 	/* 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 3343233..6df7631 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 018725b..787a274 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 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 0000000..36eb265
--- /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 0000000..2ede820
--- /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 98172c2..47b41cd 100644
--- a/board/ti/am65x/Kconfig
+++ b/board/ti/am65x/Kconfig
@@ -12,14 +12,18 @@
 	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_CONFIG_NAME
        default "am65x_evm"
 
+source "board/ti/common/Kconfig"
+
 endif
 
 if TARGET_AM654_R5_EVM
@@ -50,4 +56,6 @@
 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 0b82bd5..16384e0 100644
--- a/board/ti/am65x/README
+++ b/board/ti/am65x/README
@@ -209,3 +209,55 @@
                 | |    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 52f5d6b..7bd8c4f 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 @@
 	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 e258e22..32fa105 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 @@
 	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 @@
 	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;
@@ -385,6 +590,34 @@
 	else
 		env_set("board_rev", unknown);
 
+	if (ep->serial)
+		env_set("board_serial", ep->serial);
+	else
+		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
@@ -453,6 +686,19 @@
 	}
 }
 
+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 f8495a7..a45d896 100644
--- a/board/ti/common/board_detect.h
+++ b/board/ti/common/board_detect.h
@@ -43,6 +43,133 @@
 	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,7 +226,38 @@
 #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
  * @dev_addr:	I2C slave address
@@ -117,6 +275,33 @@
 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 @@
 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 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 7122c06..5978fb2 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -248,6 +248,16 @@
 	  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 87ecf0b..969f777 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -340,6 +340,16 @@
 #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 @@
 	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 324d91c..b361988 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -151,7 +151,8 @@
 
 #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 @@
 	}
 
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 	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 @@
 }
 #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 @@
 				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 @@
 	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 @@
 	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 ffe013f..9ccbd68 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 b940af3..9d4c6a2 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -2,7 +2,7 @@
 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_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_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_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 3814872..7e81a98 100644
--- a/configs/am65x_evm_r5_defconfig
+++ b/configs/am65x_evm_r5_defconfig
@@ -3,7 +3,7 @@
 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_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_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_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_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_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 9c55cd3..56052f7 100644
--- a/configs/am65x_hs_evm_a53_defconfig
+++ b/configs/am65x_hs_evm_a53_defconfig
@@ -3,7 +3,7 @@
 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_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_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_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_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 0b12f15..d378d1e 100644
--- a/configs/am65x_hs_evm_r5_defconfig
+++ b/configs/am65x_hs_evm_r5_defconfig
@@ -4,7 +4,7 @@
 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_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_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_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_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 b73da72..59d41cb 100644
--- a/configs/evb-ast2500_defconfig
+++ b/configs/evb-ast2500_defconfig
@@ -11,16 +11,19 @@
 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 5ef0f71..d1d12ee 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -108,6 +108,48 @@
 	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 095a9bc..4772db3 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -330,7 +330,7 @@
 
 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 890ef35..4cdae41 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -468,14 +468,15 @@
 
 	  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 3c8c53a..6cc018b 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -50,7 +50,7 @@
 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 0000000..fb0fb58
--- /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 d5f2857..0000000
--- 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 c4e8879..0a0770c 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 @@
 	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 @@
 	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 @@
 
 	/* 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 @@
 		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 @@
 
 	/* 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 @@
 		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 b576511..829b756 100644
--- a/drivers/mmc/xenon_sdhci.c
+++ b/drivers/mmc/xenon_sdhci.c
@@ -326,7 +326,7 @@
 }
 
 /* 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 @@
 
 	/* 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 0802378..c525084 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -48,11 +48,6 @@
 	[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 @@
 	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 @@
 		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 @@
 
 	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 @@
 		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 b043bf8..1415bb1 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 3cd7a66..0854200 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -330,6 +330,8 @@
 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 eee493a..01addb7 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 @@
 #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 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 a9aaef3..a90f971 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -109,6 +109,15 @@
 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 @@
 		       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);