Merge tag 'efi-2020-01-rc2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

Pull request for UEFI sub-system for efi-2020-01-rc2

Provide a better user interface for setting UEFI variables.

Bug fixes:
- ext4 file system not discovered on UEFI block device
- 'make tests' build error on 32bit systems
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml
new file mode 100644
index 0000000..11d5a61
--- /dev/null
+++ b/.azure-pipelines.yml
@@ -0,0 +1,418 @@
+variables:
+  windows_vm: vs2015-win2012r2
+  ubuntu_vm: ubuntu-18.04
+  ci_runner_image: trini/u-boot-gitlab-ci-runner:bionic-20191010-20Oct2019
+  # Add '-u 0' options for Azure pipelines, otherwise we get "permission
+  # denied" error when it tries to "useradd -m -u 1001 vsts_azpcontainer",
+  # since our $(ci_runner_image) user is not root.
+  container_option: -u 0
+  work_dir: /u
+
+jobs:
+  - job: tools_only_windows
+    displayName: 'Ensure host tools build for Windows'
+    pool:
+      vmImage: $(windows_vm)
+    strategy:
+      matrix:
+        i686:
+          MSYS_DIR: msys32
+          BASE_REPO: msys2-ci-base-i686
+        x86_64:
+          MSYS_DIR: msys64
+          BASE_REPO: msys2-ci-base
+    steps:
+      - script: |
+          git clone https://github.com/msys2/$(BASE_REPO).git %CD:~0,2%\$(MSYS_DIR)
+        displayName: 'Install MSYS2'
+      - script: |
+          set PATH=%CD:~0,2%\$(MSYS_DIR)\usr\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem
+          %CD:~0,2%\$(MSYS_DIR)\usr\bin\pacman --noconfirm -Syyuu
+        displayName: 'Update MSYS2'
+      - script: |
+          set PATH=%CD:~0,2%\$(MSYS_DIR)\usr\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem
+          %CD:~0,2%\$(MSYS_DIR)\usr\bin\pacman --noconfirm --needed -S make gcc bison diffutils openssl-devel
+        displayName: 'Install Toolchain'
+      - script: |
+          set PATH=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem
+          echo make tools-only_defconfig tools-only NO_SDL=1 > build-tools.sh
+          %CD:~0,2%\$(MSYS_DIR)\usr\bin\bash -lc "bash build-tools.sh"
+        displayName: 'Build Host Tools'
+        env:
+          # Tell MSYS2 we need a POSIX emulation layer
+          MSYSTEM: MSYS
+          # Tell MSYS2 not to ‘cd’ our startup directory to HOME
+          CHERE_INVOKING: yes
+
+  - job: cppcheck
+    displayName: 'Static code analysis with cppcheck'
+    pool:
+      vmImage: $(ubuntu_vm)
+    container:
+      image: $(ci_runner_image)
+      options: $(container_option)
+    steps:
+      - script: cppcheck --force --quiet --inline-suppr .
+
+  - job: todo
+    displayName: 'Search for TODO within source tree'
+    pool:
+      vmImage: $(ubuntu_vm)
+    container:
+      image: $(ci_runner_image)
+      options: $(container_option)
+    steps:
+      - script: grep -r TODO .
+      - script: grep -r FIXME .
+      - script: grep -r HACK . | grep -v HACKKIT
+
+  - job: sloccount
+    displayName: 'Some statistics about the code base'
+    pool:
+      vmImage: $(ubuntu_vm)
+    container:
+      image: $(ci_runner_image)
+      options: $(container_option)
+    steps:
+      - script: sloccount .
+
+  - job: maintainers
+    displayName: 'Ensure all configs have MAINTAINERS entries'
+    pool:
+      vmImage: $(ubuntu_vm)
+    container:
+      image: $(ci_runner_image)
+      options: $(container_option)
+    steps:
+      - script: |
+          if [ `./tools/genboardscfg.py -f 2>&1 | wc -l` -ne 0 ]; then exit 1; fi
+
+  - job: tools_only
+    displayName: 'Ensure host tools build'
+    pool:
+      vmImage: $(ubuntu_vm)
+    container:
+      image: $(ci_runner_image)
+      options: $(container_option)
+    steps:
+      - script: |
+          make tools-only_config tools-only -j$(nproc)
+
+  - job: envtools
+    displayName: 'Ensure env tools build'
+    pool:
+      vmImage: $(ubuntu_vm)
+    container:
+      image: $(ci_runner_image)
+      options: $(container_option)
+    steps:
+      - script: |
+          make tools-only_config envtools -j$(nproc)
+
+  - job: utils
+    displayName: 'Run binman, buildman, dtoc and patman testsuites'
+    pool:
+      vmImage: $(ubuntu_vm)
+    steps:
+      - script: |
+          cat << EOF > build.sh
+          set -ex
+          cd ${WORK_DIR}
+          EOF
+          cat << "EOF" >> build.sh
+          git config --global user.name "Azure Pipelines"
+          git config --global user.email bmeng.cn@gmail.com
+          export USER=azure
+          virtualenv /tmp/venv
+          . /tmp/venv/bin/activate
+          pip install pyelftools
+          export UBOOT_TRAVIS_BUILD_DIR=/tmp/.bm-work/sandbox_spl
+          export PYTHONPATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt
+          export PATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}
+          ./tools/buildman/buildman -o /tmp -P sandbox_spl
+          ./tools/binman/binman --toolpath ${UBOOT_TRAVIS_BUILD_DIR}/tools test
+          ./tools/buildman/buildman -t
+          ./tools/dtoc/dtoc -t
+          ./tools/patman/patman --test
+          EOF
+          cat build.sh
+          # We cannot use "container" like other jobs above, as buildman
+          # seems to hang forever with pre-configured "container" environment
+          docker run -v $PWD:$(work_dir) $(ci_runner_image) /bin/bash $(work_dir)/build.sh
+
+  - job: test_py
+    displayName: 'test.py'
+    pool:
+      vmImage: $(ubuntu_vm)
+    strategy:
+      matrix:
+        sandbox:
+          TEST_PY_BD: "sandbox"
+          BUILDMAN: "^sandbox$"
+        sandbox_spl:
+          TEST_PY_BD: "sandbox_spl"
+          TEST_PY_TEST_SPEC: "test_ofplatdata"
+          BUILDMAN: "^sandbox_spl$"
+        sandbox_flattree:
+          TEST_PY_BD: "sandbox_flattree"
+          BUILDMAN: "^sandbox_flattree$"
+        evb_ast2500:
+          TEST_PY_BD: "evb-ast2500"
+          TEST_PY_ID: "--id qemu"
+          BUILDMAN: "^evb-ast2500$"
+        vexpress_ca15_tc2:
+          TEST_PY_BD: "vexpress_ca15_tc2"
+          TEST_PY_ID: "--id qemu"
+          BUILDMAN: "^vexpress_ca15_tc2$"
+        vexpress_ca9x4:
+          TEST_PY_BD: "vexpress_ca9x4"
+          TEST_PY_ID: "--id qemu"
+          BUILDMAN: "^vexpress_ca9x4$"
+        integratorcp_cm926ejs:
+          TEST_PY_BD: "integratorcp_cm926ejs"
+          TEST_PY_ID: "--id qemu"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^integratorcp_cm926ejs$"
+        qemu_arm:
+          TEST_PY_BD: "qemu_arm"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^qemu_arm$"
+        qemu_arm64:
+          TEST_PY_BD: "qemu_arm64"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^qemu_arm64$"
+        qemu_mips:
+          TEST_PY_BD: "qemu_mips"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^qemu_mips$"
+        qemu_mipsel:
+          TEST_PY_BD: "qemu_mipsel"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^qemu_mipsel$"
+        qemu_mips64:
+          TEST_PY_BD: "qemu_mips64"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^qemu_mips64$"
+        qemu_mips64el:
+          TEST_PY_BD: "qemu_mips64el"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^qemu_mips64el$"
+        qemu_ppce500:
+          TEST_PY_BD: "qemu-ppce500"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^qemu-ppce500$"
+        qemu_riscv64:
+          TEST_PY_BD: "qemu-riscv64"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^qemu-riscv64$"
+        qemu_x86:
+          TEST_PY_BD: "qemu-x86"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^qemu-x86$"
+        qemu_x86_64:
+          TEST_PY_BD: "qemu-x86_64"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^qemu-x86_64$"
+        zynq_zc702:
+          TEST_PY_BD: "zynq_zc702"
+          TEST_PY_ID: "--id qemu"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^zynq_zc702$"
+        xilinx_versal_virt:
+          TEST_PY_BD: "xilinx_versal_virt"
+          TEST_PY_ID: "--id qemu"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^xilinx_versal_virt$"
+        xtfpga:
+          TEST_PY_BD: "xtfpga"
+          TEST_PY_ID: "--id qemu"
+          TEST_PY_TEST_SPEC: "not sleep"
+          BUILDMAN: "^xtfpga$"
+    steps:
+      - script: |
+          cat << EOF > test.sh
+          set -ex
+          # make environment variables available as tests are running inside a container
+          export WORK_DIR="${WORK_DIR}"
+          export TEST_PY_BD="${TEST_PY_BD}"
+          export TEST_PY_ID="${TEST_PY_ID}"
+          export TEST_PY_TEST_SPEC="${TEST_PY_TEST_SPEC}"
+          export BUILDMAN="${BUILDMAN}"
+          EOF
+          cat << "EOF" >> test.sh
+          # the below corresponds to .gitlab-ci.yml "before_script"
+          cd ${WORK_DIR}
+          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`
+          grub-mkimage --prefix=\"\" -o ~/grub_x86.efi -O i386-efi normal  echo lsefimmap lsefi lsefisystab efinet tftp minicmd
+          grub-mkimage --prefix=\"\" -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
+          # the below corresponds to .gitlab-ci.yml "script"
+          cd ${WORK_DIR}
+          if [[ "${BUILDMAN}" != "" ]]; then
+              ret=0;
+              tools/buildman/buildman -o /tmp -P -E ${BUILDMAN} ${OVERRIDE} || ret=$?;
+              if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+                  tools/buildman/buildman -o /tmp -sdeP ${BUILDMAN};
+                  exit $ret;
+              fi;
+          fi
+          virtualenv -p /usr/bin/python3 /tmp/venv
+          . /tmp/venv/bin/activate
+          pip install -r test/py/requirements.txt
+          export UBOOT_TRAVIS_BUILD_DIR=/tmp/.bm-work/${TEST_PY_BD};
+          export PATH=/opt/qemu/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
+          # the below corresponds to .gitlab-ci.yml "after_script"
+          rm -rf ~/grub2* /tmp/uboot-test-hooks /tmp/venv
+          EOF
+          cat test.sh
+          # make current directory writeable to uboot user inside the container
+          # as sandbox testing need create files like spi flash images, etc.
+          # (TODO: clean up this in the future)
+          chmod 777 .
+          docker run -v $PWD:$(work_dir) $(ci_runner_image) /bin/bash $(work_dir)/test.sh
+
+  - job: build_the_world
+    displayName: 'Build the World'
+    pool:
+      vmImage: $(ubuntu_vm)
+    strategy:
+      # Use almost the same target division in .travis.yml, only merged
+      # 4 small build jobs (arc/microblaze/nds32/xtensa) into one.
+      matrix:
+        arc_microblaze_nds32_xtensa:
+          BUILDMAN: "arc microblaze nds32 xtensa"
+        arm11_arm7_arm920t_arm946es:
+          BUILDMAN: "arm11 arm7 arm920t arm946es"
+        arm926ejs:
+          BUILDMAN: "arm926ejs -x freescale,siemens,at91,kirkwood,spear,omap"
+        at91_non_armv7:
+          BUILDMAN: "at91 -x armv7"
+        at91_non_arm926ejs:
+          BUILDMAN: "at91 -x arm926ejs"
+        boundary_engicam_toradex:
+          BUILDMAN: "boundary engicam toradex"
+        arm_bcm:
+          BUILDMAN: "bcm -x mips"
+        nxp_arm32:
+          BUILDMAN: "freescale -x powerpc,m68k,aarch64"
+        nxp_aarch64_ls101x:
+          BUILDMAN: "freescale&aarch64&ls101"
+        nxp_aarch64_ls102x:
+          BUILDMAN: "freescale&aarch64&ls102"
+        nxp_aarch64_ls104x:
+          BUILDMAN: "freescale&aarch64&ls104"
+        nxp_aarch64_ls108x:
+          BUILDMAN: "freescale&aarch64&ls108"
+        nxp_aarch64_ls20xx:
+          BUILDMAN: "freescale&aarch64&ls20"
+        nxp_aarch64_lx216x:
+          BUILDMAN: "freescale&aarch64&lx216"
+        imx6:
+          BUILDMAN: "mx6 -x boundary,engicam,freescale,technexion,toradex"
+        imx:
+          BUILDMAN: "mx -x mx6,freescale,technexion,toradex"
+        keystone2_keystone3:
+          BUILDMAN: "k2 k3"
+        samsung_socfpga:
+          BUILDMAN: "samsung socfpga"
+        spear:
+          BUILDMAN: "spear"
+        sun4i:
+          BUILDMAN: "sun4i"
+        sun5i:
+          BUILDMAN: "sun5i"
+        sun6i:
+          BUILDMAN: "sun6i"
+        sun7i:
+          BUILDMAN: "sun7i"
+        sun8i_32bit:
+          BUILDMAN: "sun8i&armv7"
+        sun8i_64bit:
+          BUILDMAN: "sun8i&aarch64"
+        sun9i:
+          BUILDMAN: "sun9i"
+        sun50i:
+          BUILDMAN: "sun50i"
+        arm_catch_all:
+          BUILDMAN: "arm -x arm11,arm7,arm9,aarch64,at91,bcm,freescale,kirkwood,mvebu,siemens,tegra,uniphier,mx,samsung,sunxi,am33xx,omap,rockchip,toradex,socfpga,k2,k3,zynq"
+        sandbox_x86:
+          BUILDMAN: "sandbox x86"
+        technexion:
+          BUILDMAN: "technexion"
+        kirkwood:
+          BUILDMAN: "kirkwood"
+        mvebu:
+          BUILDMAN: "mvebu"
+        m68k:
+          BUILDMAN: "m68k"
+        mips:
+          BUILDMAN: "mips"
+        non_fsl_ppc:
+          BUILDMAN: "powerpc -x freescale"
+        mpc85xx_freescale:
+          BUILDMAN: "mpc85xx&freescale -x t208xrdb -x t4qds -x t102* -x p1_p2_rdb_pc -x p1010rdb -x corenet_ds -x b4860qds -x bsc91*"
+        t208xrdb_corenet_ds:
+          BUILDMAN: "t208xrdb corenet_ds"
+        fsl_ppc:
+          BUILDMAN: "t4qds b4860qds mpc83xx&freescale mpc86xx&freescale"
+        t102x:
+          BUILDMAN: "t102*"
+        p1_p2_rdb_pc:
+          BUILDMAN: "p1_p2_rdb_pc"
+        p1010rdb_bsc91:
+          BUILDMAN: "p1010rdb bsc91"
+        siemens:
+          BUILDMAN: "siemens"
+        tegra:
+          BUILDMAN: "tegra -x toradex"
+        am33xx_no_siemens:
+          BUILDMAN: "am33xx -x siemens"
+        omap:
+          BUILDMAN: "omap"
+        uniphier:
+          BUILDMAN: "uniphier"
+        aarch64_catch_all:
+          BUILDMAN: "aarch64 -x bcm,k3,tegra,ls1,ls2,mvebu,uniphier,sunxi,samsung,rockchip,versal,zynq"
+        rockchip:
+          BUILDMAN: "rockchip"
+        sh:
+          BUILDMAN: "sh -x arm"
+        zynq:
+          BUILDMAN: "zynq&armv7"
+        zynqmp_versal:
+          BUILDMAN: "versal|zynqmp&aarch64"
+        riscv:
+          BUILDMAN: "riscv"
+    steps:
+      - script: |
+          cat << EOF > build.sh
+          set -ex
+          cd ${WORK_DIR}
+          # make environment variables available as tests are running inside a container
+          export BUILDMAN="${BUILDMAN}"
+          EOF
+          cat << "EOF" >> build.sh
+          if [[ "${BUILDMAN}" != "" ]]; then
+              ret=0;
+              tools/buildman/buildman -o /tmp -P -E ${BUILDMAN} ${OVERRIDE} || ret=$?;
+              if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+                  tools/buildman/buildman -o /tmp -sdeP ${BUILDMAN};
+                  exit $ret;
+              fi;
+          fi
+          EOF
+          cat build.sh
+          docker run -v $PWD:$(work_dir) $(ci_runner_image) /bin/bash $(work_dir)/build.sh
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..8560b79
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Declare files that always have LF line endings on checkout
+* text eol=lf
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 967abed..9b295ac 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,7 +2,7 @@
 
 # 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:bionic-20190912.1-03Oct2019
+image: trini/u-boot-gitlab-ci-runner:bionic-20191010-20Oct2019
 
 # We run some tests in different order, to catch some failures quicker.
 stages:
@@ -18,11 +18,6 @@
     - 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
-    - pip install coverage
     - grub-mkimage --prefix="" -o ~/grub_x86.efi -O i386-efi normal  echo lsefimmap lsefi lsefisystab efinet tftp minicmd
     - grub-mkimage --prefix="" -o ~/grub_x64.efi -O x86_64-efi normal  echo lsefimmap lsefi lsefisystab efinet tftp minicmd
     - mkdir ~/grub2-arm
@@ -47,8 +42,11 @@
     # 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.
+    - virtualenv -p /usr/bin/python3 /tmp/venv
+    - . /tmp/venv/bin/activate
+    - pip install -r test/py/requirements.txt
     - export UBOOT_TRAVIS_BUILD_DIR=/tmp/.bm-work/${TEST_PY_BD};
-      export PATH=/opt/qemu/bin:/tmp/uboot-test-hooks/bin:/usr/bin:/bin;
+      export PATH=/opt/qemu/bin:/tmp/uboot-test-hooks/bin:${PATH};
       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}
@@ -65,11 +63,11 @@
   stage: world build
   script:
     - ret=0;
-     ./tools/buildman/buildman -o /tmp -P -E arm -x aarch64 || ret=$?;
-     if [[ $ret -ne 0 && $ret -ne 129 ]]; then
-       ./tools/buildman/buildman -o /tmp -sdeP;
-       exit $ret;
-     fi;
+      ./tools/buildman/buildman -o /tmp -P -E arm -x aarch64 || ret=$?;
+      if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+        ./tools/buildman/buildman -o /tmp -sdeP;
+        exit $ret;
+      fi;
 
 build all 64bit ARM platforms:
   tags: [ 'all' ]
@@ -79,33 +77,33 @@
     - . /tmp/venv/bin/activate
     - pip install pyelftools
     - ret=0;
-     ./tools/buildman/buildman -o /tmp -P -E aarch64 || ret=$?;
-     if [[ $ret -ne 0 && $ret -ne 129 ]]; then
-       ./tools/buildman/buildman -o /tmp -sdeP;
-       exit $ret;
-     fi;
+      ./tools/buildman/buildman -o /tmp -P -E aarch64 || ret=$?;
+      if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+        ./tools/buildman/buildman -o /tmp -sdeP;
+        exit $ret;
+      fi;
 
 build all PowerPC platforms:
   tags: [ 'all' ]
   stage: world build
   script:
     - ret=0;
-     ./tools/buildman/buildman -o /tmp -P -E powerpc || ret=$?;
-     if [[ $ret -ne 0 && $ret -ne 129 ]]; then
-       ./tools/buildman/buildman -o /tmp -sdeP;
-       exit $ret;
-     fi;
+      ./tools/buildman/buildman -o /tmp -P -E powerpc || ret=$?;
+      if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+        ./tools/buildman/buildman -o /tmp -sdeP;
+        exit $ret;
+      fi;
 
 build all other platforms:
   tags: [ 'all' ]
   stage: world build
   script:
     - ret=0;
-     ./tools/buildman/buildman -o /tmp -P -E -x arm,powerpc || ret=$?;
-     if [[ $ret -ne 0 && $ret -ne 129 ]]; then
-       ./tools/buildman/buildman -o /tmp -sdeP;
-       exit $ret;
-     fi;
+      ./tools/buildman/buildman -o /tmp -P -E -x arm,powerpc || ret=$?;
+      if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+        ./tools/buildman/buildman -o /tmp -sdeP;
+        exit $ret;
+      fi;
 
 # QA jobs for code analytics
 # static code analysis with cppcheck (we can add --enable=all later)
diff --git a/.travis.yml b/.travis.yml
index a3e7451..2369da9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,7 +21,9 @@
     - build-essential
     - libsdl1.2-dev
     - python
-    - python-virtualenv
+    - python-pyelftools
+    - python3-virtualenv
+    - python3-pip
     - swig
     - libpython-dev
     - iasl
@@ -47,11 +49,6 @@
  - echo -e "arc = /tmp/arc_gnu_2018.09_prebuilt_uclibc_le_archs_linux_install" >> ~/.buildman
  - echo -e "\n[toolchain-alias]\nsh = sh2\n" >> ~/.buildman
  - cat ~/.buildman
- - virtualenv /tmp/venv
- - . /tmp/venv/bin/activate
- - pip install pytest==2.8.7
- - pip install python-subunit
- - pip install pyelftools
  - grub-mkimage --prefix="" -o ~/grub_x86.efi -O i386-efi normal  echo lsefimmap lsefi lsefisystab efinet tftp minicmd
  - grub-mkimage --prefix="" -o ~/grub_x64.efi -O x86_64-efi normal  echo lsefimmap lsefi lsefisystab efinet tftp minicmd
  - mkdir ~/grub2-arm
@@ -136,15 +133,6 @@
    cp ~/grub_x64.efi $UBOOT_TRAVIS_BUILD_DIR/;
    cp ~/grub2-arm/usr/lib/grub2/arm-efi/grub.efi $UBOOT_TRAVIS_BUILD_DIR/grub_arm.efi;
    cp ~/grub2-arm64/usr/lib/grub2/arm64-efi/grub.efi $UBOOT_TRAVIS_BUILD_DIR/grub_arm64.efi;
-   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;
    if [[ -n "${TEST_PY_TOOLS}" ]]; then
      PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt"
      PATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}"
@@ -154,6 +142,18 @@
      PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt"
      PATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}"
      ./tools/dtoc/dtoc -t;
+   fi;
+   if [[ "${TEST_PY_BD}" != "" ]]; then
+     virtualenv -p /usr/bin/python3 /tmp/venv;
+     . /tmp/venv/bin/activate;
+     pip install -r test/py/requirements.txt;
+     ./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
 
 matrix:
@@ -200,7 +200,7 @@
         - BUILDMAN="freescale&aarch64&ls108"
     - name: "buildman NXP AArch64 LS20xx"
       env:
-        - BUILDMAN="freescale&aarch64&&ls20"
+        - BUILDMAN="freescale&aarch64&ls20"
     - name: "buildman NXP AArch64 LX216x"
       env:
         - BUILDMAN="freescale&aarch64&lx216"
diff --git a/Makefile b/Makefile
index cbacf1c..a96c6ce 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0+
 
-VERSION = 2019
-PATCHLEVEL = 10
+VERSION = 2020
+PATCHLEVEL = 01
 SUBLEVEL =
-EXTRAVERSION =
+EXTRAVERSION = -rc1
 NAME =
 
 # *DOCUMENTATION*
@@ -346,7 +346,7 @@
 	limit=$$( printf "%d" $2 ); \
 	if test $$actual -gt $$limit; then \
 		echo "$1 exceeds file size limit:" >&2; \
-		echo "  limit:  $$(printf %#x bytes $$limit) bytes" >&2; \
+		echo "  limit:  $$(printf %#x $$limit) bytes" >&2; \
 		echo "  actual: $$(printf %#x $$actual) bytes" >&2; \
 		echo "  excess: $$(printf %#x $$((actual - limit))) bytes" >&2;\
 		exit 1; \
@@ -1276,10 +1276,21 @@
 
 MKIMAGEFLAGS_u-boot-dtb.img = $(MKIMAGEFLAGS_u-boot.img)
 
-MKIMAGEFLAGS_u-boot.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \
+# Some boards have the kwbimage.cfg file written in advance, while some
+# other boards generate it on the fly during the build in the build tree.
+# Let's check if the file exists in the build tree first, otherwise we
+# fall back to use the one in the source tree.
+KWD_CONFIG_FILE = $(shell \
+	if [ -f $(objtree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) ]; then \
+		echo -n $(objtree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%); \
+	else \
+		echo -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%); \
+	fi)
+
+MKIMAGEFLAGS_u-boot.kwb = -n $(KWD_CONFIG_FILE) \
 	-T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE)
 
-MKIMAGEFLAGS_u-boot-spl.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \
+MKIMAGEFLAGS_u-boot-spl.kwb = -n $(KWD_CONFIG_FILE) \
 	-T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) \
 	$(if $(KEYDIR),-k $(KEYDIR))
 
@@ -1837,11 +1848,14 @@
 		false; \
 	fi
 
-envtools: scripts_basic $(version_h) $(timestamp_h)
+tools/version.h: include/version.h
+	$(call if_changed,copy)
+
+envtools: scripts_basic $(version_h) $(timestamp_h) tools/version.h
 	$(Q)$(MAKE) $(build)=tools/env
 
 tools-only: export TOOLS_ONLY=y
-tools-only: scripts_basic $(version_h) $(timestamp_h)
+tools-only: scripts_basic $(version_h) $(timestamp_h) tools/version.h
 	$(Q)$(MAKE) $(build)=tools
 
 tools-all: export HOST_TOOLS_ALL=y
@@ -1869,7 +1883,7 @@
 	       $(foreach d, spl tpl, $(patsubst %,$d/%, \
 			$(filter-out include, $(shell ls -1 $d 2>/dev/null))))
 
-CLEAN_FILES += include/bmp_logo.h include/bmp_logo_data.h \
+CLEAN_FILES += include/bmp_logo.h include/bmp_logo_data.h tools/version.h \
 	       boot* u-boot* MLO* SPL System.map fit-dtb.blob*
 
 # Directories & files removed with 'make mrproper'
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 6a7dbb6..47978e7 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -540,6 +540,7 @@
 	sun50i-a64-nanopi-a64.dtb \
 	sun50i-a64-oceanic-5205-5inmfd.dtb \
 	sun50i-a64-olinuxino.dtb \
+	sun50i-a64-olinuxino-emmc.dtb \
 	sun50i-a64-orangepi-win.dtb \
 	sun50i-a64-pine64-lts.dtb \
 	sun50i-a64-pine64-plus.dtb \
diff --git a/arch/arm/dts/sun50i-a64-olinuxino-emmc.dts b/arch/arm/dts/sun50i-a64-olinuxino-emmc.dts
new file mode 100644
index 0000000..96ab022
--- /dev/null
+++ b/arch/arm/dts/sun50i-a64-olinuxino-emmc.dts
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Martin Ayotte <martinayotte@gmail.com>
+ * Copyright (C) 2019 Sunil Mohan Adapa <sunil@medhas.org>
+ */
+
+#include "sun50i-a64-olinuxino.dts"
+
+/ {
+	model = "Olimex A64-Olinuxino-eMMC";
+	compatible = "olimex,a64-olinuxino-emmc", "allwinner,sun50i-a64";
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_pins>;
+	vmmc-supply = <&reg_dcdc1>;
+	vqmmc-supply = <&reg_dcdc1>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	status = "okay";
+};
diff --git a/arch/arm/dts/sun50i-a64-sopine-baseboard-u-boot.dtsi b/arch/arm/dts/sun50i-a64-sopine-baseboard-u-boot.dtsi
new file mode 100644
index 0000000..02b1ae0
--- /dev/null
+++ b/arch/arm/dts/sun50i-a64-sopine-baseboard-u-boot.dtsi
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include "sunxi-u-boot.dtsi"
+
+/ {
+	aliases {
+		spi0 = &spi0;
+	};
+};
diff --git a/arch/arm/dts/sun50i-h6-beelink-gs1.dts b/arch/arm/dts/sun50i-h6-beelink-gs1.dts
index 54b0882..0dc33c9 100644
--- a/arch/arm/dts/sun50i-h6-beelink-gs1.dts
+++ b/arch/arm/dts/sun50i-h6-beelink-gs1.dts
@@ -14,6 +14,7 @@
 	compatible = "azw,beelink-gs1", "allwinner,sun50i-h6";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 	};
 
@@ -21,6 +22,17 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 
@@ -41,6 +53,40 @@
 	};
 };
 
+&de {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ext_rgmii_pins>;
+	phy-mode = "rgmii";
+	phy-handle = <&ext_rgmii_phy>;
+	phy-supply = <&reg_aldo2>;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
 &mmc0 {
 	vmmc-supply = <&reg_cldo1>;
 	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
@@ -57,6 +103,15 @@
 	status = "okay";
 };
 
+&ohci0 {
+	status = "okay";
+};
+
+&pio {
+	vcc-pd-supply = <&reg_cldo1>;
+	vcc-pg-supply = <&reg_aldo1>;
+};
+
 &r_i2c {
 	status = "okay";
 
@@ -177,8 +232,29 @@
 	};
 };
 
+&r_pio {
+	/*
+	 * PL0 and PL1 are used for PMIC I2C
+	 * don't enable the pl-supply else
+	 * it will fail at boot
+	 *
+	 * vcc-pl-supply = <&reg_aldo1>;
+	 */
+	vcc-pm-supply = <&reg_aldo1>;
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_ph_pins>;
 	status = "okay";
 };
+
+&usb2otg {
+	dr_mode = "host";
+	status = "okay";
+};
+
+&usb2phy {
+	usb0_vbus-supply = <&reg_vcc5v>;
+	status = "okay";
+};
diff --git a/arch/arm/dts/sun50i-h6-pine-h64.dts b/arch/arm/dts/sun50i-h6-pine-h64.dts
index 4802902..1898345 100644
--- a/arch/arm/dts/sun50i-h6-pine-h64.dts
+++ b/arch/arm/dts/sun50i-h6-pine-h64.dts
@@ -127,6 +127,12 @@
 	status = "okay";
 };
 
+&pio {
+	vcc-pc-supply = <&reg_bldo2>;
+	vcc-pd-supply = <&reg_cldo1>;
+	vcc-pg-supply = <&reg_aldo1>;
+};
+
 &r_i2c {
 	status = "okay";
 
@@ -243,10 +249,16 @@
 	pcf8563: rtc@51 {
 		compatible = "nxp,pcf8563";
 		reg = <0x51>;
+		interrupt-parent = <&r_intc>;
+		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		#clock-cells = <0>;
 	};
 };
 
+&r_pio {
+	vcc-pm-supply = <&reg_aldo1>;
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_ph_pins>;
diff --git a/arch/arm/dts/sun50i-h6.dtsi b/arch/arm/dts/sun50i-h6.dtsi
index e0dc4a0..a117f47 100644
--- a/arch/arm/dts/sun50i-h6.dtsi
+++ b/arch/arm/dts/sun50i-h6.dtsi
@@ -101,7 +101,7 @@
 		#size-cells = <1>;
 		ranges;
 
-		display-engine@1000000 {
+		bus@1000000 {
 			compatible = "allwinner,sun50i-h6-de3",
 				     "allwinner,sun50i-a64-de2";
 			reg = <0x1000000 0x400000>;
@@ -203,11 +203,32 @@
 			#reset-cells = <1>;
 		};
 
+		dma: dma-controller@3002000 {
+			compatible = "allwinner,sun50i-h6-dma";
+			reg = <0x03002000 0x1000>;
+			interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_DMA>, <&ccu CLK_MBUS_DMA>;
+			clock-names = "bus", "mbus";
+			dma-channels = <16>;
+			dma-requests = <46>;
+			resets = <&ccu RST_BUS_DMA>;
+			#dma-cells = <1>;
+		};
+
 		sid: sid@3006000 {
 			compatible = "allwinner,sun50i-h6-sid";
 			reg = <0x03006000 0x400>;
 		};
 
+		watchdog: watchdog@30090a0 {
+			compatible = "allwinner,sun50i-h6-wdt",
+				     "allwinner,sun6i-a31-wdt";
+			reg = <0x030090a0 0x20>;
+			interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+			/* Broken on some H6 boards */
+			status = "disabled";
+		};
+
 		pio: pinctrl@300b000 {
 			compatible = "allwinner,sun50i-h6-pinctrl";
 			reg = <0x0300b000 0x400>;
@@ -243,6 +264,18 @@
 				bias-pull-up;
 			};
 
+			/*
+			 * /omit-if-no-ref/ isn't supported by U-boot
+			 * keep this comment to avoid bad sync with Linux
+			 */
+			mmc1_pins: mmc1-pins {
+				pins = "PG0", "PG1", "PG2", "PG3",
+				       "PG4", "PG5";
+				function = "mmc1";
+				drive-strength = <30>;
+				bias-pull-up;
+			};
+
 			mmc2_pins: mmc2-pins {
 				pins = "PC1", "PC4", "PC5", "PC6",
 				       "PC7", "PC8", "PC9", "PC10",
@@ -294,6 +327,8 @@
 			resets = <&ccu RST_BUS_MMC1>;
 			reset-names = "ahb";
 			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc1_pins>;
 			status = "disabled";
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -445,7 +480,6 @@
 			resets = <&ccu RST_BUS_OHCI3>,
 				 <&ccu RST_BUS_EHCI3>;
 			phys = <&usb2phy 3>;
-			phy-names = "usb";
 			status = "disabled";
 		};
 
@@ -457,7 +491,6 @@
 				 <&ccu CLK_USB_OHCI3>;
 			resets = <&ccu RST_BUS_OHCI3>;
 			phys = <&usb2phy 3>;
-			phy-names = "usb";
 			status = "disabled";
 		};
 
@@ -613,6 +646,13 @@
 			#reset-cells = <1>;
 		};
 
+		r_watchdog: watchdog@7020400 {
+			compatible = "allwinner,sun50i-h6-wdt",
+				     "allwinner,sun6i-a31-wdt";
+			reg = <0x07020400 0x20>;
+			interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
 		r_intc: interrupt-controller@7021000 {
 			compatible = "allwinner,sun50i-h6-r-intc",
 				     "allwinner,sun6i-a31-r-intc";
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
index 0a1da02..49a8a66 100644
--- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
+++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
@@ -315,6 +315,7 @@
 	u8 cols;
 	u8 rows;
 	u8 ranks;
+	u8 bus_full_width;
 	const u8 dx_read_delays[NR_OF_BYTE_LANES][RD_LINES_PER_BYTE_LANE];
 	const u8 dx_write_delays[NR_OF_BYTE_LANES][WR_LINES_PER_BYTE_LANE];
 };
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
index 40a3f84..a646ea6 100644
--- a/arch/arm/include/asm/arch-sunxi/gpio.h
+++ b/arch/arm/include/asm/arch-sunxi/gpio.h
@@ -73,6 +73,9 @@
 	struct sunxi_gpio_int gpio_int;
 };
 
+#define SUN50I_H6_GPIO_POW_MOD_SEL	0x340
+#define SUN50I_H6_GPIO_POW_MOD_VAL	0x348
+
 #define BANK_TO_GPIO(bank)	(((bank) < SUNXI_GPIO_L) ? \
 	&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank] : \
 	&((struct sunxi_gpio_reg *)SUNXI_R_PIO_BASE)->gpio_bank[(bank) - SUNXI_GPIO_L])
diff --git a/arch/arm/mach-bcm283x/include/mach/timer.h b/arch/arm/mach-bcm283x/include/mach/timer.h
index 014355e..61beb1a 100644
--- a/arch/arm/mach-bcm283x/include/mach/timer.h
+++ b/arch/arm/mach-bcm283x/include/mach/timer.h
@@ -25,9 +25,6 @@
 	u32 c2;
 	u32 c3;
 };
-
-extern ulong get_timer_us(ulong base);
-
 #endif
 
 #endif
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 8228a17..b739520 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -58,10 +58,10 @@
 KWB_CFG_SEC_FUSE_DUMP = a38x
 endif
 
-$(src)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
+$(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
 		include/config/auto.conf
 	$(Q)sed -ne '$(foreach V,$(KWB_REPLACE),s/^#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \
-	<$< >$(dir $<)$(@F)
+	<$< >$(dir $@)$(@F)
 
 endif # CONFIG_SPL_BUILD
 obj-y	+= gpio.o
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index ffdf09f..16d41b8 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -275,7 +275,10 @@
 config MACH_SUN50I
 	bool "sun50i (Allwinner A64)"
 	select ARM64
+	select SPI
 	select DM_I2C
+	select DM_SPI if SPI
+	select DM_SPI_FLASH
 	select PHY_SUN4I_USB
 	select SUN6I_PRCM
 	select SUNXI_DE2
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 8e9bb63..db50636 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -65,6 +65,7 @@
 
 static int gpio_init(void)
 {
+	__maybe_unused uint val;
 #if CONFIG_CONS_INDEX == 1 && defined(CONFIG_UART0_PORT_F)
 #if defined(CONFIG_MACH_SUN4I) || \
     defined(CONFIG_MACH_SUN7I) || \
@@ -139,6 +140,14 @@
 #error Unsupported console port number. Please fix pin mux settings in board.c
 #endif
 
+#ifdef CONFIG_MACH_SUN50I_H6
+	/* Update PIO power bias configuration by copy hardware detected value */
+	val = readl(SUNXI_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_VAL);
+	writel(val, SUNXI_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_SEL);
+	val = readl(SUNXI_R_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_VAL);
+	writel(val, SUNXI_R_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_SEL);
+#endif
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-sunxi/clock_sun6i.c b/arch/arm/mach-sunxi/clock_sun6i.c
index 1628f3a..6ca38f7 100644
--- a/arch/arm/mach-sunxi/clock_sun6i.c
+++ b/arch/arm/mach-sunxi/clock_sun6i.c
@@ -118,7 +118,7 @@
 	if (clk > 1152000000) {
 		k = 2;
 	} else if (clk > 768000000) {
-		k = 3;
+		k = 4;
 		m = 2;
 	}
 
diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c
index 2a8275d..9375db7 100644
--- a/arch/arm/mach-sunxi/dram_sun50i_h6.c
+++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c
@@ -201,6 +201,9 @@
 	u8 rows = para->rows;
 	u8 ranks = para->ranks;
 
+	if (!para->bus_full_width)
+		cols -= 1;
+
 	/* Ranks */
 	if (ranks == 2)
 		mctl_ctl->addrmap[0] = rows + cols - 3;
@@ -213,6 +216,10 @@
 	/* Columns */
 	mctl_ctl->addrmap[2] = 0;
 	switch (cols) {
+	case 7:
+		mctl_ctl->addrmap[3] = 0x1F1F1F00;
+		mctl_ctl->addrmap[4] = 0x1F1F;
+		break;
 	case 8:
 		mctl_ctl->addrmap[3] = 0x1F1F0000;
 		mctl_ctl->addrmap[4] = 0x1F1F;
@@ -300,13 +307,16 @@
 		reg_val = 0x3f00;
 	clrsetbits_le32(&mctl_com->unk_0x008, 0x3f00, reg_val);
 
-	/* TODO: half DQ, DDR4 */
-	reg_val = MSTR_BUSWIDTH_FULL | MSTR_BURST_LENGTH(8) |
-		  MSTR_ACTIVE_RANKS(para->ranks);
+	/* TODO: DDR4 */
+	reg_val = MSTR_BURST_LENGTH(8) | MSTR_ACTIVE_RANKS(para->ranks);
 	if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
 		reg_val |= MSTR_DEVICETYPE_LPDDR3;
 	if (para->type == SUNXI_DRAM_TYPE_DDR3)
 		reg_val |= MSTR_DEVICETYPE_DDR3 | MSTR_2TMODE;
+	if (para->bus_full_width)
+		reg_val |= MSTR_BUSWIDTH_FULL;
+	else
+		reg_val |= MSTR_BUSWIDTH_HALF;
 	writel(reg_val | BIT(31), &mctl_ctl->mstr);
 
 	if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
@@ -333,7 +343,10 @@
 	}
 	writel(reg_val, &mctl_ctl->odtcfg);
 
-	/* TODO: half DQ */
+	if (!para->bus_full_width) {
+		writel(0x0, &mctl_phy->dx[2].gcr[0]);
+		writel(0x0, &mctl_phy->dx[3].gcr[0]);
+	}
 }
 
 static void mctl_bit_delay_set(struct dram_para *para)
@@ -514,22 +527,35 @@
 
 	if (readl(&mctl_phy->pgsr[0]) & 0x400000)
 	{
-		/*
-		 * Detect single rank.
-		 * TODO: also detect half DQ.
-		 */
+		/* Check for single rank and optionally half DQ. */
 		if ((readl(&mctl_phy->dx[0].rsr[0]) & 0x3) == 2 &&
-		    (readl(&mctl_phy->dx[1].rsr[0]) & 0x3) == 2 &&
-		    (readl(&mctl_phy->dx[2].rsr[0]) & 0x3) == 2 &&
-		    (readl(&mctl_phy->dx[3].rsr[0]) & 0x3) == 2) {
+		    (readl(&mctl_phy->dx[1].rsr[0]) & 0x3) == 2) {
 			para->ranks = 1;
+
+			if ((readl(&mctl_phy->dx[2].rsr[0]) & 0x3) != 2 ||
+			    (readl(&mctl_phy->dx[3].rsr[0]) & 0x3) != 2)
+				para->bus_full_width = 0;
+
 			/* Restart DRAM initialization from scratch. */
 			mctl_core_init(para);
 			return;
 		}
-		else {
-			panic("This DRAM setup is currently not supported.\n");
+
+		/*
+		 * Check for dual rank and half DQ. NOTE: This combination
+		 * is highly unlikely and was not tested. Condition is the
+		 * same as in libdram, though.
+		 */
+		if ((readl(&mctl_phy->dx[0].rsr[0]) & 0x3) == 0 &&
+		    (readl(&mctl_phy->dx[1].rsr[0]) & 0x3) == 0) {
+			para->bus_full_width = 0;
+
+			/* Restart DRAM initialization from scratch. */
+			mctl_core_init(para);
+			return;
 		}
+
+		panic("This DRAM setup is currently not supported.\n");
 	}
 
 	if (readl(&mctl_phy->pgsr[0]) & 0xff00000) {
@@ -557,11 +583,8 @@
 
 static void mctl_auto_detect_dram_size(struct dram_para *para)
 {
-	/* TODO: non-LPDDR3, half DQ */
-	/*
-	 * Detect rank number by the code in mctl_channel_init. Furtherly
-	 * when DQ detection is available it will also be executed there.
-	 */
+	/* TODO: non-(LP)DDR3 */
+	/* Detect rank number and half DQ by the code in mctl_channel_init. */
 	mctl_core_init(para);
 
 	/* detect row address bits */
@@ -570,8 +593,9 @@
 	mctl_core_init(para);
 
 	for (para->rows = 13; para->rows < 18; para->rows++) {
-		/* 8 banks, 8 bit per byte and 32 bit width */
-		if (mctl_mem_matches((1 << (para->rows + para->cols + 5))))
+		/* 8 banks, 8 bit per byte and 16/32 bit width */
+		if (mctl_mem_matches((1 << (para->rows + para->cols +
+					    4 + para->bus_full_width))))
 			break;
 	}
 
@@ -580,18 +604,21 @@
 	mctl_core_init(para);
 
 	for (para->cols = 8; para->cols < 11; para->cols++) {
-		/* 8 bits per byte and 32 bit width */
-		if (mctl_mem_matches(1 << (para->cols + 2)))
+		/* 8 bits per byte and 16/32 bit width */
+		if (mctl_mem_matches(1 << (para->cols + 1 +
+					   para->bus_full_width)))
 			break;
 	}
 }
 
 unsigned long mctl_calc_size(struct dram_para *para)
 {
-	/* TODO: non-LPDDR3, half DQ */
+	u8 width = para->bus_full_width ? 4 : 2;
 
-	/* 8 banks, 32-bit (4 byte) data width */
-	return (1ULL << (para->cols + para->rows + 3)) * 4 * para->ranks;
+	/* TODO: non-(LP)DDR3 */
+
+	/* 8 banks */
+	return (1ULL << (para->cols + para->rows + 3)) * width * para->ranks;
 }
 
 #define SUN50I_H6_LPDDR3_DX_WRITE_DELAYS			\
@@ -625,6 +652,7 @@
 		.ranks = 2,
 		.cols = 11,
 		.rows = 14,
+		.bus_full_width = 1,
 #ifdef CONFIG_SUNXI_DRAM_H6_LPDDR3
 		.type = SUNXI_DRAM_TYPE_LPDDR3,
 		.dx_read_delays  = SUN50I_H6_LPDDR3_DX_READ_DELAYS,
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index 2046cb5..f3af88d 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -246,8 +246,7 @@
 	return 0;
 }
 
-void sandbox_write(const void *addr, unsigned int val,
-		   enum sandboxio_size_t size)
+void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size)
 {
 	struct sandbox_state *state = state_get_current();
 
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 42b41fb..fdb08f2 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -226,14 +226,18 @@
 	clk_sandbox: clk-sbox {
 		compatible = "sandbox,clk";
 		#clock-cells = <1>;
+		assigned-clocks = <&clk_sandbox 3>;
+		assigned-clock-rates = <321>;
 	};
 
 	clk-test {
 		compatible = "sandbox,clk-test";
 		clocks = <&clk_fixed>,
 			 <&clk_sandbox 1>,
-			 <&clk_sandbox 0>;
-		clock-names = "fixed", "i2c", "spi";
+			 <&clk_sandbox 0>,
+			 <&clk_sandbox 3>,
+			 <&clk_sandbox 2>;
+		clock-names = "fixed", "i2c", "spi", "uart2", "uart1";
 	};
 
 	ccf: clk-ccf {
diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h
index 2b1c49f..1573e4a 100644
--- a/arch/sandbox/include/asm/clk.h
+++ b/arch/sandbox/include/asm/clk.h
@@ -19,6 +19,8 @@
 enum sandbox_clk_id {
 	SANDBOX_CLK_ID_SPI,
 	SANDBOX_CLK_ID_I2C,
+	SANDBOX_CLK_ID_UART1,
+	SANDBOX_CLK_ID_UART2,
 
 	SANDBOX_CLK_ID_COUNT,
 };
@@ -33,10 +35,15 @@
 	SANDBOX_CLK_TEST_ID_FIXED,
 	SANDBOX_CLK_TEST_ID_SPI,
 	SANDBOX_CLK_TEST_ID_I2C,
+	SANDBOX_CLK_TEST_ID_DEVM1,
+	SANDBOX_CLK_TEST_ID_DEVM2,
+	SANDBOX_CLK_TEST_ID_DEVM_NULL,
 
 	SANDBOX_CLK_TEST_ID_COUNT,
 };
 
+#define SANDBOX_CLK_TEST_NON_DEVM_COUNT SANDBOX_CLK_TEST_ID_DEVM1
+
 /**
  * sandbox_clk_query_rate - Query the current rate of a sandbox clock.
  *
@@ -53,6 +60,14 @@
  * @return:	The rate of the clock.
  */
 int sandbox_clk_query_enable(struct udevice *dev, int id);
+/**
+ * sandbox_clk_query_requested - Query the requested state of a sandbox clock.
+ *
+ * @dev:	The sandbox clock provider device.
+ * @id:		The clock to query.
+ * @return:	The rate of the clock.
+ */
+int sandbox_clk_query_requested(struct udevice *dev, int id);
 
 /**
  * sandbox_clk_test_get - Ask the sandbox clock test device to request its
@@ -62,6 +77,16 @@
  * @return:	0 if OK, or a negative error code.
  */
 int sandbox_clk_test_get(struct udevice *dev);
+
+/**
+ * sandbox_clk_test_devm_get - Ask the sandbox clock test device to request its
+ * clocks using the managed API.
+ *
+ * @dev:	The sandbox clock test (client) devivce.
+ * @return:	0 if OK, or a negative error code.
+ */
+int sandbox_clk_test_devm_get(struct udevice *dev);
+
 /**
  * sandbox_clk_test_get_bulk - Ask the sandbox clock test device to request its
  * clocks with the bulk clk API.
@@ -146,5 +171,13 @@
  * @return:	0 if OK, or a negative error code.
  */
 int sandbox_clk_test_valid(struct udevice *dev);
+/**
+ * sandbox_clk_test_valid - Ask the sandbox clock test device to check its
+ * clocks are valid.
+ *
+ * @dev:	The sandbox clock test (client) devivce.
+ * @return:	0 if OK, or a negative error code.
+ */
+struct clk *sandbox_clk_test_get_devm_clk(struct udevice *dev, int id);
 
 #endif
diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h
index 4a35c41..ad6c29a 100644
--- a/arch/sandbox/include/asm/io.h
+++ b/arch/sandbox/include/asm/io.h
@@ -46,8 +46,7 @@
 phys_addr_t map_to_sysmem(const void *ptr);
 
 unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size);
-void sandbox_write(const void *addr, unsigned int val,
-		   enum sandboxio_size_t size);
+void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size);
 
 #define readb(addr) sandbox_read((const void *)addr, SB_SIZE_8)
 #define readw(addr) sandbox_read((const void *)addr, SB_SIZE_16)
@@ -55,11 +54,11 @@
 #ifdef CONFIG_SANDBOX64
 #define readq(addr) sandbox_read((const void *)addr, SB_SIZE_64)
 #endif
-#define writeb(v, addr) sandbox_write((const void *)addr, v, SB_SIZE_8)
-#define writew(v, addr) sandbox_write((const void *)addr, v, SB_SIZE_16)
-#define writel(v, addr) sandbox_write((const void *)addr, v, SB_SIZE_32)
+#define writeb(v, addr) sandbox_write((void *)addr, v, SB_SIZE_8)
+#define writew(v, addr) sandbox_write((void *)addr, v, SB_SIZE_16)
+#define writel(v, addr) sandbox_write((void *)addr, v, SB_SIZE_32)
 #ifdef CONFIG_SANDBOX64
-#define writeq(v, addr) sandbox_write((const void *)addr, v, SB_SIZE_64)
+#define writeq(v, addr) sandbox_write((void *)addr, v, SB_SIZE_64)
 #endif
 
 /*
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index cd2b9e3..b885e1a 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -213,4 +213,15 @@
  */
 uint sandbox_pci_read_bar(u32 barval, int type, uint size);
 
+/**
+ * sandbox_set_enable_memio() - Enable readl/writel() for sandbox
+ *
+ * Normally these I/O functions do nothing with sandbox. Certain tests need them
+ * to work as for other architectures, so this function can be used to enable
+ * them.
+ *
+ * @enable: true to enable, false to disable
+ */
+void sandbox_set_enable_memio(bool enable);
+
 #endif
diff --git a/board/Marvell/db-88f6281-bp/Makefile b/board/Marvell/db-88f6281-bp/Makefile
index e6aa7e3..003e9f6 100644
--- a/board/Marvell/db-88f6281-bp/Makefile
+++ b/board/Marvell/db-88f6281-bp/Makefile
@@ -4,9 +4,9 @@
 extra-y := kwbimage.cfg
 
 quiet_cmd_sed = SED     $@
-      cmd_sed = sed $(SEDFLAGS_$(@F)) $< >$(dir $<)$(@F)
+      cmd_sed = sed $(SEDFLAGS_$(@F)) $< >$(dir $@)$(@F)
 
 SEDFLAGS_kwbimage.cfg = -e "s/^\#@BOOT_FROM.*/BOOT_FROM	$(if $(CONFIG_CMD_NAND),nand,spi)/"
-$(src)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
+$(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
 		include/config/auto.conf
 	$(call if_changed,sed)
diff --git a/board/Marvell/db-xc3-24g4xg/Makefile b/board/Marvell/db-xc3-24g4xg/Makefile
index 4dd5790..24e8200 100644
--- a/board/Marvell/db-xc3-24g4xg/Makefile
+++ b/board/Marvell/db-xc3-24g4xg/Makefile
@@ -6,9 +6,9 @@
 extra-y	:= kwbimage.cfg
 
 quiet_cmd_sed = SED     $@
-      cmd_sed = sed $(SEDFLAGS_$(@F)) $< >$(dir $<)$(@F)
+      cmd_sed = sed $(SEDFLAGS_$(@F)) $< >$(dir $@)$(@F)
 
 SEDFLAGS_kwbimage.cfg =-e "s|^BINARY.*|BINARY $(srctree)/$(@D)/binary.0 0000005b 00000068|"
-$(src)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
+$(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
 		include/config/auto.conf
 	  $(call if_changed,sed)
diff --git a/board/mikrotik/crs305-1g-4s/Makefile b/board/mikrotik/crs305-1g-4s/Makefile
index 895331b..c03f534 100644
--- a/board/mikrotik/crs305-1g-4s/Makefile
+++ b/board/mikrotik/crs305-1g-4s/Makefile
@@ -6,9 +6,9 @@
 extra-y	:= kwbimage.cfg
 
 quiet_cmd_sed = SED     $@
-      cmd_sed = sed $(SEDFLAGS_$(@F)) $< >$(dir $<)$(@F)
+      cmd_sed = sed $(SEDFLAGS_$(@F)) $< >$(dir $@)$(@F)
 
 SEDFLAGS_kwbimage.cfg =-e "s|^BINARY.*|BINARY $(srctree)/$(@D)/binary.0 0000005b 00000068|"
-$(src)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
+$(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
 		include/config/auto.conf
 	  $(call if_changed,sed)
diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS
index 88f1353..a2adf89 100644
--- a/board/sunxi/MAINTAINERS
+++ b/board/sunxi/MAINTAINERS
@@ -106,6 +106,11 @@
 S:	Maintained
 F:	configs/a64-olinuxino_defconfig
 
+A64-OLINUXINO-EMMC BOARD
+M:	Sunil Mohan Adapa <sunil@medhas.org>
+S:	Maintained
+F:	configs/a64-olinuxino-emmc_defconfig
+
 A80 OPTIMUS BOARD
 M:	Chen-Yu Tsai <wens@csie.org>
 S:	Maintained
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 82b5d30..b08a709 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1168,6 +1168,7 @@
 config CMD_SF
 	bool "sf"
 	depends on DM_SPI_FLASH || SPI_FLASH
+	default y if DM_SPI_FLASH
 	help
 	  SPI Flash support
 
diff --git a/cmd/avb.c b/cmd/avb.c
index 5bc1582..a4de5c4 100644
--- a/cmd/avb.c
+++ b/cmd/avb.c
@@ -15,11 +15,6 @@
 #define AVB_BOOTARGS	"avb_bootargs"
 static struct AvbOps *avb_ops;
 
-static const char * const requested_partitions[] = {"boot",
-					     "system",
-					     "vendor",
-					     NULL};
-
 int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	unsigned long mmc_dev;
@@ -232,10 +227,12 @@
 int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
 		       int argc, char *const argv[])
 {
+	const char * const requested_partitions[] = {"boot", NULL};
 	AvbSlotVerifyResult slot_result;
 	AvbSlotVerifyData *out_data;
 	char *cmdline;
 	char *extra_args;
+	char *slot_suffix = "";
 
 	bool unlocked = false;
 	int res = CMD_RET_FAILURE;
@@ -245,9 +242,12 @@
 		return CMD_RET_FAILURE;
 	}
 
-	if (argc != 1)
+	if (argc < 1 || argc > 2)
 		return CMD_RET_USAGE;
 
+	if (argc == 2)
+		slot_suffix = argv[1];
+
 	printf("## Android Verified Boot 2.0 version %s\n",
 	       avb_version_string());
 
@@ -260,7 +260,7 @@
 	slot_result =
 		avb_slot_verify(avb_ops,
 				requested_partitions,
-				"",
+				slot_suffix,
 				unlocked,
 				AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
 				&out_data);
@@ -420,7 +420,7 @@
 	U_BOOT_CMD_MKENT(read_part, 5, 0, do_avb_read_part, "", ""),
 	U_BOOT_CMD_MKENT(read_part_hex, 4, 0, do_avb_read_part_hex, "", ""),
 	U_BOOT_CMD_MKENT(write_part, 5, 0, do_avb_write_part, "", ""),
-	U_BOOT_CMD_MKENT(verify, 1, 0, do_avb_verify_part, "", ""),
+	U_BOOT_CMD_MKENT(verify, 2, 0, do_avb_verify_part, "", ""),
 #ifdef CONFIG_OPTEE_TA_AVB
 	U_BOOT_CMD_MKENT(read_pvalue, 3, 0, do_avb_read_pvalue, "", ""),
 	U_BOOT_CMD_MKENT(write_pvalue, 3, 0, do_avb_write_pvalue, "", ""),
@@ -463,6 +463,7 @@
 	"avb read_pvalue <name> <bytes> - read a persistent value <name>\n"
 	"avb write_pvalue <name> <value> - write a persistent value <name>\n"
 #endif
-	"avb verify - run verification process using hash data\n"
+	"avb verify [slot_suffix] - run verification process using hash data\n"
 	"    from vbmeta structure\n"
+	"    [slot_suffix] - _a, _b, etc (if vbmeta partition is slotted)\n"
 	);
diff --git a/common/Kconfig b/common/Kconfig
index 28d5e9a..d9ecf79 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -764,7 +764,7 @@
 	  line number are omitted.
 
 config TPL_LOG_CONSOLE
-	bool "Allow log output to the console in SPL"
+	bool "Allow log output to the console in TPL"
 	depends on TPL_LOG
 	default y
 	help
diff --git a/common/board_f.c b/common/board_f.c
index 591f18f..e3591cb 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -588,6 +588,7 @@
 static int reserve_bloblist(void)
 {
 #ifdef CONFIG_BLOBLIST
+	gd->start_addr_sp &= ~0xf;
 	gd->start_addr_sp -= CONFIG_BLOBLIST_SIZE;
 	gd->new_bloblist = map_sysmem(gd->start_addr_sp, CONFIG_BLOBLIST_SIZE);
 #endif
@@ -695,6 +696,7 @@
 		      gd->bootstage, gd->new_bootstage, size);
 		memcpy(gd->new_bootstage, gd->bootstage, size);
 		gd->bootstage = gd->new_bootstage;
+		bootstage_relocate();
 	}
 #endif
 
diff --git a/common/board_r.c b/common/board_r.c
index d6fb504..c1ecb06 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -670,7 +670,6 @@
 #ifdef CONFIG_SYS_NONCACHED_MEMORY
 	initr_noncached,
 #endif
-	bootstage_relocate,
 #ifdef CONFIG_OF_LIVE
 	initr_of_live,
 #endif
diff --git a/common/bootstage.c b/common/bootstage.c
index 56ef91a..e8b7bbf 100644
--- a/common/bootstage.c
+++ b/common/bootstage.c
@@ -10,9 +10,10 @@
  */
 
 #include <common.h>
-#include <linux/libfdt.h>
 #include <malloc.h>
+#include <spl.h>
 #include <linux/compiler.h>
+#include <linux/libfdt.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -41,24 +42,34 @@
 };
 
 struct bootstage_hdr {
-	uint32_t version;	/* BOOTSTAGE_VERSION */
-	uint32_t count;		/* Number of records */
-	uint32_t size;		/* Total data size (non-zero if valid) */
-	uint32_t magic;		/* Unused */
+	u32 version;		/* BOOTSTAGE_VERSION */
+	u32 count;		/* Number of records */
+	u32 size;		/* Total data size (non-zero if valid) */
+	u32 magic;		/* Magic number */
+	u32 next_id;		/* Next ID to use for bootstage */
 };
 
 int bootstage_relocate(void)
 {
 	struct bootstage_data *data = gd->bootstage;
 	int i;
+	char *ptr;
+
+	/* Figure out where to relocate the strings to */
+	ptr = (char *)(data + 1);
 
 	/*
 	 * Duplicate all strings.  They may point to an old location in the
 	 * program .text section that can eventually get trashed.
 	 */
 	debug("Relocating %d records\n", data->rec_count);
-	for (i = 0; i < data->rec_count; i++)
-		data->record[i].name = strdup(data->record[i].name);
+	for (i = 0; i < data->rec_count; i++) {
+		const char *from = data->record[i].name;
+
+		strcpy(ptr, from);
+		data->record[i].name = ptr;
+		ptr += strlen(ptr) + 1;
+	}
 
 	return 0;
 }
@@ -372,7 +383,6 @@
 	const struct bootstage_record *rec;
 	char buf[20];
 	char *ptr = base, *end = ptr + size;
-	uint32_t count;
 	int i;
 
 	if (hdr + 1 > (struct bootstage_hdr *)end) {
@@ -383,21 +393,15 @@
 	/* Write an arbitrary version number */
 	hdr->version = BOOTSTAGE_VERSION;
 
-	/* Count the number of records, and write that value first */
-	for (rec = data->record, i = count = 0; i < data->rec_count;
-	     i++, rec++) {
-		if (rec->id != 0)
-			count++;
-	}
-	hdr->count = count;
+	hdr->count = data->rec_count;
 	hdr->size = 0;
 	hdr->magic = BOOTSTAGE_MAGIC;
+	hdr->next_id = data->next_id;
 	ptr += sizeof(*hdr);
 
 	/* Write the records, silently stopping when we run out of space */
-	for (rec = data->record, i = 0; i < data->rec_count; i++, rec++) {
+	for (rec = data->record, i = 0; i < data->rec_count; i++, rec++)
 		append_data(&ptr, end, rec, sizeof(*rec));
-	}
 
 	/* Write the name strings */
 	for (rec = data->record, i = 0; i < data->rec_count; i++, rec++) {
@@ -478,6 +482,8 @@
 	for (rec = data->record + data->next_id, i = 0; i < hdr->count;
 	     i++, rec++) {
 		rec->name = ptr;
+		if (spl_phase() == PHASE_SPL)
+			rec->name = strdup(ptr);
 
 		/* Assume no data corruption here */
 		ptr += strlen(ptr) + 1;
@@ -485,6 +491,7 @@
 
 	/* Mark the records as read */
 	data->rec_count += hdr->count;
+	data->next_id = hdr->next_id;
 	debug("Unstashed %d records\n", hdr->count);
 
 	return 0;
@@ -492,7 +499,17 @@
 
 int bootstage_get_size(void)
 {
-	return sizeof(struct bootstage_data);
+	struct bootstage_data *data = gd->bootstage;
+	struct bootstage_record *rec;
+	int size;
+	int i;
+
+	size = sizeof(struct bootstage_data);
+	for (rec = data->record, i = 0; i < data->rec_count;
+	     i++, rec++)
+		size += strlen(rec->name) + 1;
+
+	return size;
 }
 
 int bootstage_init(bool first)
diff --git a/common/fdt_support.c b/common/fdt_support.c
index baf7924..6834399 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -1566,7 +1566,7 @@
 			 uint64_t *val, int cells)
 {
 	const fdt32_t *prop32 = &prop[cell_off];
-	const fdt64_t *prop64 = (const fdt64_t *)&prop[cell_off];
+	const unaligned_fdt64_t *prop64 = (const fdt64_t *)&prop[cell_off];
 
 	if ((cell_off + cells) > prop_len)
 		return -FDT_ERR_NOSPACE;
diff --git a/common/spl/spl.c b/common/spl/spl.c
index a9d3e84..f1ad8dc 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -18,6 +18,7 @@
 #include <version.h>
 #include <image.h>
 #include <malloc.h>
+#include <mapmem.h>
 #include <dm/root.h>
 #include <linux/compiler.h>
 #include <fdt_support.h>
@@ -396,13 +397,25 @@
 		gd->malloc_ptr = 0;
 	}
 #endif
-	ret = bootstage_init(true);
+	ret = bootstage_init(u_boot_first_phase());
 	if (ret) {
 		debug("%s: Failed to set up bootstage: ret=%d\n", __func__,
 		      ret);
 		return ret;
 	}
-	bootstage_mark_name(BOOTSTAGE_ID_START_SPL, "spl");
+#ifdef CONFIG_BOOTSTAGE_STASH
+	if (!u_boot_first_phase()) {
+		const void *stash = map_sysmem(CONFIG_BOOTSTAGE_STASH_ADDR,
+					       CONFIG_BOOTSTAGE_STASH_SIZE);
+
+		ret = bootstage_unstash(stash, CONFIG_BOOTSTAGE_STASH_SIZE);
+		if (ret)
+			debug("%s: Failed to unstash bootstage: ret=%d\n",
+			      __func__, ret);
+	}
+#endif /* CONFIG_BOOTSTAGE_STASH */
+	bootstage_mark_name(spl_phase() == PHASE_TPL ? BOOTSTAGE_ID_START_TPL :
+			    BOOTSTAGE_ID_START_SPL, SPL_TPL_NAME);
 #if CONFIG_IS_ENABLED(LOG)
 	ret = log_init();
 	if (ret) {
@@ -418,7 +431,8 @@
 		}
 	}
 	if (CONFIG_IS_ENABLED(DM)) {
-		bootstage_start(BOOTSTATE_ID_ACCUM_DM_SPL, "dm_spl");
+		bootstage_start(BOOTSTATE_ID_ACCUM_DM_SPL,
+				spl_phase() == PHASE_TPL ? "dm tpl" : "dm_spl");
 		/* With CONFIG_SPL_OF_PLATDATA, bring in all devices */
 		ret = dm_init_and_scan(!CONFIG_IS_ENABLED(OF_PLATDATA));
 		bootstage_accum(BOOTSTATE_ID_ACCUM_DM_SPL);
@@ -704,8 +718,9 @@
 	debug("SPL malloc() used 0x%lx bytes (%ld KB)\n", gd->malloc_ptr,
 	      gd->malloc_ptr / 1024);
 #endif
+	bootstage_mark_name(spl_phase() == PHASE_TPL ? BOOTSTAGE_ID_END_TPL :
+			    BOOTSTAGE_ID_END_SPL, "end " SPL_TPL_NAME);
 #ifdef CONFIG_BOOTSTAGE_STASH
-	bootstage_mark_name(BOOTSTAGE_ID_END_SPL, "end_spl");
 	ret = bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR,
 			      CONFIG_BOOTSTAGE_STASH_SIZE);
 	if (ret)
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index 34e1e73..2ede096 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -343,8 +343,6 @@
 		}
 	}
 
-	raw_sect = spl_mmc_get_uboot_raw_sector(mmc);
-
 	boot_mode = spl_boot_mode(bootdev->boot_device);
 	err = -EINVAL;
 	switch (boot_mode) {
@@ -383,6 +381,9 @@
 			if (!err)
 				return err;
 		}
+
+		raw_sect = spl_mmc_get_uboot_raw_sector(mmc);
+
 #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
 		err = mmc_load_image_raw_partition(spl_image, mmc, raw_part,
 						   raw_sect);
diff --git a/common/splash.c b/common/splash.c
index 0bcedbb..e7d8477 100644
--- a/common/splash.c
+++ b/common/splash.c
@@ -144,8 +144,6 @@
 	vidconsole_put_string(dev, buf);
 	vidconsole_position_cursor(dev, 0, row);
 }
-#else
-static inline void splash_display_banner(void) { }
 #endif /* CONFIG_DM_VIDEO && !CONFIG_HIDE_LOGO_VERSION */
 
 /*
@@ -177,7 +175,9 @@
 	if (x || y)
 		goto end;
 
+#if defined(CONFIG_DM_VIDEO) && !defined(CONFIG_HIDE_LOGO_VERSION)
 	splash_display_banner();
+#endif
 end:
 	return ret;
 }
diff --git a/configs/a64-olinuxino-emmc_defconfig b/configs/a64-olinuxino-emmc_defconfig
new file mode 100644
index 0000000..56153e3
--- /dev/null
+++ b/configs/a64-olinuxino-emmc_defconfig
@@ -0,0 +1,17 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_SPL=y
+CONFIG_MACH_SUN50I=y
+CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y
+CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_USE_PREBOOT=y
+# CONFIG_CMD_FLASH is not set
+# CONFIG_SPL_DOS_PARTITION is not set
+# CONFIG_SPL_EFI_PARTITION is not set
+CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-olinuxino-emmc"
+CONFIG_SUN8I_EMAC=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y
diff --git a/configs/aristainetos2_defconfig b/configs/aristainetos2_defconfig
index 18ef5d2..0bfc117 100644
--- a/configs/aristainetos2_defconfig
+++ b/configs/aristainetos2_defconfig
@@ -44,6 +44,7 @@
 CONFIG_SF_DEFAULT_MODE=0
 CONFIG_SF_DEFAULT_SPEED=20000000
 CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_MTD_UBI_FASTMAP=y
 CONFIG_MTD_UBI_FASTMAP_AUTOCONVERT=1
 CONFIG_PHYLIB=y
diff --git a/configs/aristainetos2b_defconfig b/configs/aristainetos2b_defconfig
index 1054c05..e2da747 100644
--- a/configs/aristainetos2b_defconfig
+++ b/configs/aristainetos2b_defconfig
@@ -42,6 +42,7 @@
 CONFIG_SF_DEFAULT_MODE=0
 CONFIG_SF_DEFAULT_SPEED=20000000
 CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_MTD_UBI_FASTMAP=y
 CONFIG_MTD_UBI_FASTMAP_AUTOCONVERT=1
 CONFIG_PHYLIB=y
diff --git a/configs/aristainetos_defconfig b/configs/aristainetos_defconfig
index 4080a7b..5caf95c 100644
--- a/configs/aristainetos_defconfig
+++ b/configs/aristainetos_defconfig
@@ -43,6 +43,7 @@
 CONFIG_SF_DEFAULT_MODE=0
 CONFIG_SF_DEFAULT_SPEED=20000000
 CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_MTD_UBI_FASTMAP=y
 CONFIG_MTD_UBI_FASTMAP_AUTOCONVERT=1
 CONFIG_PHYLIB=y
diff --git a/configs/cm_fx6_defconfig b/configs/cm_fx6_defconfig
index eed0558..fbaf79d 100644
--- a/configs/cm_fx6_defconfig
+++ b/configs/cm_fx6_defconfig
@@ -72,6 +72,7 @@
 CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_SPI_FLASH_SST=y
 CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHYLIB=y
 CONFIG_MII=y
 CONFIG_DM_PMIC=y
diff --git a/configs/socfpga_arria5_defconfig b/configs/socfpga_arria5_defconfig
index 9325467..51f559c 100644
--- a/configs/socfpga_arria5_defconfig
+++ b/configs/socfpga_arria5_defconfig
@@ -47,6 +47,7 @@
 CONFIG_SPI_FLASH_SPANSION=y
 CONFIG_SPI_FLASH_STMICRO=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
 CONFIG_DM_ETH=y
diff --git a/configs/socfpga_cyclone5_defconfig b/configs/socfpga_cyclone5_defconfig
index 8e5b2e2..c648113 100644
--- a/configs/socfpga_cyclone5_defconfig
+++ b/configs/socfpga_cyclone5_defconfig
@@ -48,6 +48,7 @@
 CONFIG_SPI_FLASH_SPANSION=y
 CONFIG_SPI_FLASH_STMICRO=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
 CONFIG_DM_ETH=y
diff --git a/configs/socfpga_dbm_soc1_defconfig b/configs/socfpga_dbm_soc1_defconfig
index c73f382..414f131 100644
--- a/configs/socfpga_dbm_soc1_defconfig
+++ b/configs/socfpga_dbm_soc1_defconfig
@@ -46,6 +46,7 @@
 CONFIG_DM_MMC=y
 CONFIG_MMC_DW=y
 CONFIG_MTD_DEVICE=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_DM_ETH=y
 CONFIG_PHY_GIGE=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/socfpga_de0_nano_soc_defconfig b/configs/socfpga_de0_nano_soc_defconfig
index 80ccb33..6eb052e 100644
--- a/configs/socfpga_de0_nano_soc_defconfig
+++ b/configs/socfpga_de0_nano_soc_defconfig
@@ -43,6 +43,7 @@
 CONFIG_DM_MMC=y
 CONFIG_MMC_DW=y
 CONFIG_MTD_DEVICE=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
 CONFIG_DM_ETH=y
diff --git a/configs/socfpga_de10_nano_defconfig b/configs/socfpga_de10_nano_defconfig
index 98e80b7..6b8b5b4 100644
--- a/configs/socfpga_de10_nano_defconfig
+++ b/configs/socfpga_de10_nano_defconfig
@@ -39,6 +39,7 @@
 CONFIG_DM_MMC=y
 CONFIG_MMC_DW=y
 CONFIG_MTD_DEVICE=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
 CONFIG_DM_ETH=y
diff --git a/configs/socfpga_is1_defconfig b/configs/socfpga_is1_defconfig
index 99cdb26..38b9f6c 100644
--- a/configs/socfpga_is1_defconfig
+++ b/configs/socfpga_is1_defconfig
@@ -43,6 +43,7 @@
 CONFIG_MTD_DEVICE=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
 CONFIG_DM_ETH=y
diff --git a/configs/socfpga_mcvevk_defconfig b/configs/socfpga_mcvevk_defconfig
index e977cd7..605ffd7 100644
--- a/configs/socfpga_mcvevk_defconfig
+++ b/configs/socfpga_mcvevk_defconfig
@@ -42,6 +42,7 @@
 CONFIG_SYS_I2C_DW=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_DW=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_DM_ETH=y
 CONFIG_PHY_GIGE=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/socfpga_sockit_defconfig b/configs/socfpga_sockit_defconfig
index b570b9d..cae6f7b 100644
--- a/configs/socfpga_sockit_defconfig
+++ b/configs/socfpga_sockit_defconfig
@@ -48,6 +48,7 @@
 CONFIG_SPI_FLASH_SPANSION=y
 CONFIG_SPI_FLASH_STMICRO=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
 CONFIG_DM_ETH=y
diff --git a/configs/socfpga_socrates_defconfig b/configs/socfpga_socrates_defconfig
index 9eac00e..9cb1daa 100644
--- a/configs/socfpga_socrates_defconfig
+++ b/configs/socfpga_socrates_defconfig
@@ -48,6 +48,7 @@
 CONFIG_SPI_FLASH_MACRONIX=y
 CONFIG_SPI_FLASH_SPANSION=y
 CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
 CONFIG_DM_ETH=y
diff --git a/configs/socfpga_sr1500_defconfig b/configs/socfpga_sr1500_defconfig
index 092347a..c48bbb0 100644
--- a/configs/socfpga_sr1500_defconfig
+++ b/configs/socfpga_sr1500_defconfig
@@ -49,6 +49,7 @@
 CONFIG_SF_DEFAULT_SPEED=100000000
 CONFIG_SPI_FLASH_STMICRO=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHY_MARVELL=y
 CONFIG_DM_ETH=y
 CONFIG_PHY_GIGE=y
diff --git a/configs/socfpga_vining_fpga_defconfig b/configs/socfpga_vining_fpga_defconfig
index a9c594e..80733ba 100644
--- a/configs/socfpga_vining_fpga_defconfig
+++ b/configs/socfpga_vining_fpga_defconfig
@@ -72,6 +72,7 @@
 CONFIG_SPI_FLASH_SPANSION=y
 CONFIG_SPI_FLASH_STMICRO=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_MTD_UBI_FASTMAP=y
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
diff --git a/configs/sopine_baseboard_defconfig b/configs/sopine_baseboard_defconfig
index 5833234..c9123fd 100644
--- a/configs/sopine_baseboard_defconfig
+++ b/configs/sopine_baseboard_defconfig
@@ -10,6 +10,7 @@
 CONFIG_MMC0_CD_PIN=""
 CONFIG_MMC_SUNXI_SLOT_EXTRA=2
 CONFIG_SPL_SPI_SUNXI=y
+CONFIG_SPI_FLASH_WINBOND=y
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
 CONFIG_USE_PREBOOT=y
 CONFIG_SYS_SPI_U_BOOT_OFFS=0x8000
diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
index c54feb0..2a54e71 100644
--- a/configs/stm32mp15_basic_defconfig
+++ b/configs/stm32mp15_basic_defconfig
@@ -90,6 +90,7 @@
 CONFIG_SPI_FLASH_WINBOND=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
 CONFIG_SPI_FLASH_MTD=y
+CONFIG_SPL_SPI_FLASH_MTD=y
 CONFIG_DM_ETH=y
 CONFIG_DWC_ETH_QOS=y
 CONFIG_PHY=y
diff --git a/disk/part_dos.c b/disk/part_dos.c
index 8ddc13b..83ff40d 100644
--- a/disk/part_dos.c
+++ b/disk/part_dos.c
@@ -67,28 +67,39 @@
 {
 	int slot;
 	struct dos_partition *p;
+	int part_count = 0;
 
 	if((buffer[DOS_PART_MAGIC_OFFSET + 0] != 0x55) ||
 	    (buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) ) {
 		return (-1);
 	} /* no DOS Signature at all */
 	p = (struct dos_partition *)&buffer[DOS_PART_TBL_OFFSET];
-	for (slot = 0; slot < 3; slot++) {
-		if (p->boot_ind != 0 && p->boot_ind != 0x80) {
-			if (!slot &&
-			    (strncmp((char *)&buffer[DOS_PBR_FSTYPE_OFFSET],
-				     "FAT", 3) == 0 ||
-			     strncmp((char *)&buffer[DOS_PBR32_FSTYPE_OFFSET],
-				     "FAT32", 5) == 0)) {
-				return DOS_PBR; /* is PBR */
-			} else {
-				return -1;
-			}
-		}
+
+	/* Check that the boot indicators are valid and count the partitions. */
+	for (slot = 0; slot < 4; ++slot, ++p) {
+		if (p->boot_ind != 0 && p->boot_ind != 0x80)
+			break;
+		if (p->sys_ind)
+			++part_count;
 	}
-	return DOS_MBR;	    /* Is MBR */
-}
 
+	/*
+	 * If the partition table is invalid or empty,
+	 * check if this is a DOS PBR
+	 */
+	if (slot != 4 || !part_count) {
+		if (!strncmp((char *)&buffer[DOS_PBR_FSTYPE_OFFSET],
+			     "FAT", 3) ||
+		    !strncmp((char *)&buffer[DOS_PBR32_FSTYPE_OFFSET],
+			     "FAT32", 5))
+			return DOS_PBR; /* This is a DOS PBR and not an MBR */
+	}
+	if (slot == 4)
+		return DOS_MBR;	/* This is an DOS MBR */
+
+	/* This is neither a DOS MBR nor a DOS PBR */
+	return -1;
+}
 
 static int part_test_dos(struct blk_desc *dev_desc)
 {
diff --git a/doc/android/avb2.txt b/doc/android/avb2.txt
index a29cee1..48e9297 100644
--- a/doc/android/avb2.txt
+++ b/doc/android/avb2.txt
@@ -95,6 +95,10 @@
        mmc read ${loadaddr} ${boot_start} ${boot_size}; \
        bootm $loadaddr $loadaddr $fdtaddr;              \
 
+If partitions you want to verify are slotted (have A/B suffixes), then current
+slot suffix should be passed to 'avb verify' sub-command, e.g.:
+
+=> avb verify _a
 
 To switch on automatic generation of vbmeta partition in AOSP build, add these
 lines to device configuration mk file:
diff --git a/doc/build/index.rst b/doc/build/index.rst
new file mode 100644
index 0000000..e4e3411
--- /dev/null
+++ b/doc/build/index.rst
@@ -0,0 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Build U-Boot
+============
+
+.. toctree::
+   :maxdepth: 2
+
+   tools
diff --git a/doc/build/tools.rst b/doc/build/tools.rst
new file mode 100644
index 0000000..c06f915
--- /dev/null
+++ b/doc/build/tools.rst
@@ -0,0 +1,47 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Bin Meng <bmeng.cn@gmail.com>
+
+Host tools
+==========
+
+Building tools for Linux
+------------------------
+
+To allow distributions to distribute all possible tools in a generic way,
+avoiding the need of specific tools building for each machine, a tools only
+defconfig file is provided.
+
+Using this, we can build the tools by doing::
+
+   $ make tools-only_defconfig
+   $ make tools-only
+
+Building tools for Windows
+--------------------------
+If you wish to generate Windows versions of the utilities in the tools directory
+you can use MSYS2, a software distro and building platform for Windows.
+
+Download the MSYS2 installer from https://www.msys2.org. Make sure you have
+installed all required packages below in order to build these host tools::
+
+   * gcc (9.1.0)
+   * make (4.2.1)
+   * bison (3.4.2)
+   * diffutils (3.7)
+   * openssl-devel (1.1.1.d)
+
+Note the version numbers in these parentheses above are the package versions
+at the time being when writing this document. The MSYS2 installer tested is
+http://repo.msys2.org/distrib/x86_64/msys2-x86_64-20190524.exe.
+
+There are 3 MSYS subsystems installed: MSYS2, MinGW32 and MinGW64. Each
+subsystem provides an environment to build Windows applications. The MSYS2
+environment is for building POSIX compliant software on Windows using an
+emulation layer. The MinGW32/64 subsystems are for building native Windows
+applications using a linux toolchain (gcc, bash, etc), targeting respectively
+32 and 64 bit Windows.
+
+Launch the MSYS2 shell of the MSYS2 environment, and do the following::
+
+   $ make tools-only_defconfig
+   $ make tools-only NO_SDL=1
diff --git a/doc/driver-model/spi-howto.rst b/doc/driver-model/spi-howto.rst
index 5540eb7..9631a50 100644
--- a/doc/driver-model/spi-howto.rst
+++ b/doc/driver-model/spi-howto.rst
@@ -116,7 +116,7 @@
 	static int exynos_cs_info(struct udevice *bus, uint cs,
 				  struct spi_cs_info *info)
 	{
-		return -ENODEV;
+		return -EINVAL;
 	}
 
 	static const struct dm_spi_ops exynos_spi_ops = {
@@ -633,9 +633,9 @@
 method for cs_info() to deal with this. If you don't provide it, then the
 device tree will be used to determine what chip selects are valid.
 
-Return -ENODEV if the supplied chip select is invalid, or 0 if it is valid.
-If you don't provide the cs_info() method, -ENODEV is assumed for all
-chip selects that do not appear in the device tree.
+Return -EINVAL if the supplied chip select is invalid, or 0 if it is valid.
+If you don't provide the cs_info() method, 0 is assumed for all chip selects
+that do not appear in the device tree.
 
 
 Test it
diff --git a/doc/index.rst b/doc/index.rst
index 458f0d2..206a045 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -15,6 +15,17 @@
 .. toctree::
    :maxdepth: 2
 
+User-oriented documentation
+---------------------------
+
+The following manuals are written for *users* of the U-Boot - those who are
+trying to get it to work optimally on a given system.
+
+.. toctree::
+   :maxdepth: 2
+
+   build/index
+
 Unified Extensible Firmware (UEFI)
 ----------------------------------
 
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 21a89eb..d10f9f0 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -50,6 +50,8 @@
 #define WAIT_MS_FLUSH	5000
 #define WAIT_MS_LINKUP	200
 
+#define AHCI_CAP_S64A BIT(31)
+
 __weak void __iomem *ahci_port_base(void __iomem *base, u32 port)
 {
 	return base + 0x100 + (port * 0x80);
@@ -503,9 +505,15 @@
 	}
 
 	for (i = 0; i < sg_count; i++) {
-		ahci_sg->addr =
-		    cpu_to_le32((unsigned long) buf + i * MAX_DATA_BYTE_COUNT);
-		ahci_sg->addr_hi = 0;
+		/* We assume virt=phys */
+		phys_addr_t pa = (unsigned long)buf + i * MAX_DATA_BYTE_COUNT;
+
+		ahci_sg->addr = cpu_to_le32(lower_32_bits(pa));
+		ahci_sg->addr_hi = cpu_to_le32(upper_32_bits(pa));
+		if (ahci_sg->addr_hi && !(uc_priv->cap & AHCI_CAP_S64A)) {
+			printf("Error: DMA address too high\n");
+			return -1;
+		}
 		ahci_sg->flags_size = cpu_to_le32(0x3fffff &
 					  (buf_len < MAX_DATA_BYTE_COUNT
 					   ? (buf_len - 1)
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 64c181f..9aa8537 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -178,7 +178,7 @@
 	return ret;
 }
 
-static int clk_set_default_parents(struct udevice *dev)
+static int clk_set_default_parents(struct udevice *dev, int stage)
 {
 	struct clk clk, parent_clk;
 	int index;
@@ -214,8 +214,18 @@
 			return ret;
 		}
 
-		ret = clk_set_parent(&clk, &parent_clk);
+		/* This is clk provider device trying to reparent itself
+		 * It cannot be done right now but need to wait after the
+		 * device is probed
+		 */
+		if (stage == 0 && clk.dev == dev)
+			continue;
+
+		if (stage > 0 && clk.dev != dev)
+			/* do not setup twice the parent clocks */
+			continue;
 
+		ret = clk_set_parent(&clk, &parent_clk);
 		/*
 		 * Not all drivers may support clock-reparenting (as of now).
 		 * Ignore errors due to this.
@@ -223,7 +233,7 @@
 		if (ret == -ENOSYS)
 			continue;
 
-		if (ret) {
+		if (ret < 0) {
 			debug("%s: failed to reparent clock %d for %s\n",
 			      __func__, index, dev_read_name(dev));
 			return ret;
@@ -233,7 +243,7 @@
 	return 0;
 }
 
-static int clk_set_default_rates(struct udevice *dev)
+static int clk_set_default_rates(struct udevice *dev, int stage)
 {
 	struct clk clk;
 	int index;
@@ -268,7 +278,19 @@
 			continue;
 		}
 
+		/* This is clk provider device trying to program itself
+		 * It cannot be done right now but need to wait after the
+		 * device is probed
+		 */
+		if (stage == 0 && clk.dev == dev)
+			continue;
+
+		if (stage > 0 && clk.dev != dev)
+			/* do not setup twice the parent clocks */
+			continue;
+
 		ret = clk_set_rate(&clk, rates[index]);
+
 		if (ret < 0) {
 			debug("%s: failed to set rate on clock index %d (%ld) for %s\n",
 			      __func__, index, clk.id, dev_read_name(dev));
@@ -281,7 +303,7 @@
 	return ret;
 }
 
-int clk_set_defaults(struct udevice *dev)
+int clk_set_defaults(struct udevice *dev, int stage)
 {
 	int ret;
 
@@ -294,11 +316,11 @@
 
 	debug("%s(%s)\n", __func__, dev_read_name(dev));
 
-	ret = clk_set_default_parents(dev);
+	ret = clk_set_default_parents(dev, stage);
 	if (ret)
 		return ret;
 
-	ret = clk_set_default_rates(dev);
+	ret = clk_set_default_rates(dev, stage);
 	if (ret < 0)
 		return ret;
 
@@ -349,9 +371,12 @@
 
 int clk_request(struct udevice *dev, struct clk *clk)
 {
-	const struct clk_ops *ops = clk_dev_ops(dev);
+	const struct clk_ops *ops;
 
 	debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk);
+	if (!clk)
+		return 0;
+	ops = clk_dev_ops(dev);
 
 	clk->dev = dev;
 
@@ -363,9 +388,12 @@
 
 int clk_free(struct clk *clk)
 {
-	const struct clk_ops *ops = clk_dev_ops(clk->dev);
+	const struct clk_ops *ops;
 
 	debug("%s(clk=%p)\n", __func__, clk);
+	if (!clk)
+		return 0;
+	ops = clk_dev_ops(clk->dev);
 
 	if (!ops->free)
 		return 0;
@@ -375,9 +403,12 @@
 
 ulong clk_get_rate(struct clk *clk)
 {
-	const struct clk_ops *ops = clk_dev_ops(clk->dev);
+	const struct clk_ops *ops;
 
 	debug("%s(clk=%p)\n", __func__, clk);
+	if (!clk)
+		return 0;
+	ops = clk_dev_ops(clk->dev);
 
 	if (!ops->get_rate)
 		return -ENOSYS;
@@ -391,6 +422,8 @@
 	struct clk *pclk;
 
 	debug("%s(clk=%p)\n", __func__, clk);
+	if (!clk)
+		return NULL;
 
 	pdev = dev_get_parent(clk->dev);
 	pclk = dev_get_clk_ptr(pdev);
@@ -406,6 +439,8 @@
 	struct clk *pclk;
 
 	debug("%s(clk=%p)\n", __func__, clk);
+	if (!clk)
+		return 0;
 
 	pclk = clk_get_parent(clk);
 	if (IS_ERR(pclk))
@@ -424,9 +459,12 @@
 
 ulong clk_set_rate(struct clk *clk, ulong rate)
 {
-	const struct clk_ops *ops = clk_dev_ops(clk->dev);
+	const struct clk_ops *ops;
 
 	debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
+	if (!clk)
+		return 0;
+	ops = clk_dev_ops(clk->dev);
 
 	if (!ops->set_rate)
 		return -ENOSYS;
@@ -436,9 +474,12 @@
 
 int clk_set_parent(struct clk *clk, struct clk *parent)
 {
-	const struct clk_ops *ops = clk_dev_ops(clk->dev);
+	const struct clk_ops *ops;
 
 	debug("%s(clk=%p, parent=%p)\n", __func__, clk, parent);
+	if (!clk)
+		return 0;
+	ops = clk_dev_ops(clk->dev);
 
 	if (!ops->set_parent)
 		return -ENOSYS;
@@ -448,11 +489,14 @@
 
 int clk_enable(struct clk *clk)
 {
-	const struct clk_ops *ops = clk_dev_ops(clk->dev);
+	const struct clk_ops *ops;
 	struct clk *clkp = NULL;
 	int ret;
 
 	debug("%s(clk=%p)\n", __func__, clk);
+	if (!clk)
+		return 0;
+	ops = clk_dev_ops(clk->dev);
 
 	if (CONFIG_IS_ENABLED(CLK_CCF)) {
 		/* Take id 0 as a non-valid clk, such as dummy */
@@ -505,11 +549,14 @@
 
 int clk_disable(struct clk *clk)
 {
-	const struct clk_ops *ops = clk_dev_ops(clk->dev);
+	const struct clk_ops *ops;
 	struct clk *clkp = NULL;
 	int ret;
 
 	debug("%s(clk=%p)\n", __func__, clk);
+	if (!clk)
+		return 0;
+	ops = clk_dev_ops(clk->dev);
 
 	if (CONFIG_IS_ENABLED(CLK_CCF)) {
 		if (clk->id && !clk_get_by_id(clk->id, &clkp)) {
@@ -589,6 +636,10 @@
 	if (p == q)
 		return true;
 
+	/* trivial case #2: on the clk pointer is NULL */
+	if (!p || !q)
+		return false;
+
 	/* same device, id and data */
 	if (p->dev == q->dev && p->id == q->id && p->data == q->data)
 		return true;
@@ -596,7 +647,69 @@
 	return false;
 }
 
+static void devm_clk_release(struct udevice *dev, void *res)
+{
+	clk_free(res);
+}
+
+static int devm_clk_match(struct udevice *dev, void *res, void *data)
+{
+	return res == data;
+}
+
+struct clk *devm_clk_get(struct udevice *dev, const char *id)
+{
+	int rc;
+	struct clk *clk;
+
+	clk = devres_alloc(devm_clk_release, sizeof(struct clk), __GFP_ZERO);
+	if (unlikely(!clk))
+		return ERR_PTR(-ENOMEM);
+
+	rc = clk_get_by_name(dev, id, clk);
+	if (rc)
+		return ERR_PTR(rc);
+
+	devres_add(dev, clk);
+	return clk;
+}
+
+struct clk *devm_clk_get_optional(struct udevice *dev, const char *id)
+{
+	struct clk *clk = devm_clk_get(dev, id);
+
+	if (IS_ERR(clk))
+		return NULL;
+
+	return clk;
+}
+
+void devm_clk_put(struct udevice *dev, struct clk *clk)
+{
+	int rc;
+
+	if (!clk)
+		return;
+
+	rc = devres_release(dev, devm_clk_release, devm_clk_match, clk);
+	WARN_ON(rc);
+}
+
+int clk_uclass_post_probe(struct udevice *dev)
+{
+	/*
+	 * when a clock provider is probed. Call clk_set_defaults()
+	 * also after the device is probed. This takes care of cases
+	 * where the DT is used to setup default parents and rates
+	 * using assigned-clocks
+	 */
+	clk_set_defaults(dev, 1);
+
+	return 0;
+}
+
 UCLASS_DRIVER(clk) = {
 	.id		= UCLASS_CLK,
 	.name		= "clk",
+	.post_probe	= clk_uclass_post_probe,
 };
diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c
index 1d5cbb5..de6b2f7 100644
--- a/drivers/clk/clk_sandbox.c
+++ b/drivers/clk/clk_sandbox.c
@@ -10,14 +10,19 @@
 #include <asm/clk.h>
 
 struct sandbox_clk_priv {
+	bool probed;
 	ulong rate[SANDBOX_CLK_ID_COUNT];
 	bool enabled[SANDBOX_CLK_ID_COUNT];
+	bool requested[SANDBOX_CLK_ID_COUNT];
 };
 
 static ulong sandbox_clk_get_rate(struct clk *clk)
 {
 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
 
+	if (!priv->probed)
+		return -ENODEV;
+
 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
 		return -EINVAL;
 
@@ -29,6 +34,9 @@
 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
 	ulong old_rate;
 
+	if (!priv->probed)
+		return -ENODEV;
+
 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
 		return -EINVAL;
 
@@ -45,6 +53,9 @@
 {
 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
 
+	if (!priv->probed)
+		return -ENODEV;
+
 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
 		return -EINVAL;
 
@@ -57,21 +68,56 @@
 {
 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
 
+	if (!priv->probed)
+		return -ENODEV;
+
 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
 		return -EINVAL;
 
 	priv->enabled[clk->id] = false;
 
+	return 0;
+}
+
+static int sandbox_clk_request(struct clk *clk)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+
+	if (clk->id >= SANDBOX_CLK_ID_COUNT)
+		return -EINVAL;
+
+	priv->requested[clk->id] = true;
 	return 0;
 }
 
+static int sandbox_clk_free(struct clk *clk)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+
+	if (clk->id >= SANDBOX_CLK_ID_COUNT)
+		return -EINVAL;
+
+	priv->requested[clk->id] = false;
+	return 0;
+}
+
 static struct clk_ops sandbox_clk_ops = {
 	.get_rate	= sandbox_clk_get_rate,
 	.set_rate	= sandbox_clk_set_rate,
 	.enable		= sandbox_clk_enable,
 	.disable	= sandbox_clk_disable,
+	.request	= sandbox_clk_request,
+	.free		= sandbox_clk_free,
 };
 
+static int sandbox_clk_probe(struct udevice *dev)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	priv->probed = true;
+	return 0;
+}
+
 static const struct udevice_id sandbox_clk_ids[] = {
 	{ .compatible = "sandbox,clk" },
 	{ }
@@ -82,6 +128,7 @@
 	.id		= UCLASS_CLK,
 	.of_match	= sandbox_clk_ids,
 	.ops		= &sandbox_clk_ops,
+	.probe		= sandbox_clk_probe,
 	.priv_auto_alloc_size = sizeof(struct sandbox_clk_priv),
 };
 
@@ -104,3 +151,12 @@
 
 	return priv->enabled[id];
 }
+
+int sandbox_clk_query_requested(struct udevice *dev, int id)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	if (id < 0 || id >= SANDBOX_CLK_ID_COUNT)
+		return -EINVAL;
+	return priv->requested[id];
+}
diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c
index e8465db..4195466 100644
--- a/drivers/clk/clk_sandbox_test.c
+++ b/drivers/clk/clk_sandbox_test.c
@@ -9,7 +9,8 @@
 #include <asm/clk.h>
 
 struct sandbox_clk_test {
-	struct clk clks[SANDBOX_CLK_TEST_ID_COUNT];
+	struct clk clks[SANDBOX_CLK_TEST_NON_DEVM_COUNT];
+	struct clk *clkps[SANDBOX_CLK_TEST_ID_COUNT];
 	struct clk_bulk bulk;
 };
 
@@ -24,7 +25,7 @@
 	struct sandbox_clk_test *sbct = dev_get_priv(dev);
 	int i, ret;
 
-	for (i = 0; i < SANDBOX_CLK_TEST_ID_COUNT; i++) {
+	for (i = 0; i < SANDBOX_CLK_TEST_NON_DEVM_COUNT; i++) {
 		ret = clk_get_by_name(dev, sandbox_clk_test_names[i],
 				      &sbct->clks[i]);
 		if (ret)
@@ -34,6 +35,37 @@
 	return 0;
 }
 
+int sandbox_clk_test_devm_get(struct udevice *dev)
+{
+	struct sandbox_clk_test *sbct = dev_get_priv(dev);
+	struct clk *clk;
+
+	clk = devm_clk_get(dev, "no-an-existing-clock");
+	if (!IS_ERR(clk)) {
+		dev_err(dev, "devm_clk_get() should have failed\n");
+		return -EINVAL;
+	}
+
+	clk = devm_clk_get(dev, "uart2");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+	sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM1] = clk;
+
+	clk = devm_clk_get_optional(dev, "uart1");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+	sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM2] = clk;
+
+	sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM_NULL] = NULL;
+	clk = devm_clk_get_optional(dev, "not_an_existing_clock");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+	if (clk)
+		return -EINVAL;
+
+	return 0;
+}
+
 int sandbox_clk_test_get_bulk(struct udevice *dev)
 {
 	struct sandbox_clk_test *sbct = dev_get_priv(dev);
@@ -48,7 +80,7 @@
 	if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
 		return -EINVAL;
 
-	return clk_get_rate(&sbct->clks[id]);
+	return clk_get_rate(sbct->clkps[id]);
 }
 
 ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate)
@@ -58,7 +90,7 @@
 	if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
 		return -EINVAL;
 
-	return clk_set_rate(&sbct->clks[id], rate);
+	return clk_set_rate(sbct->clkps[id], rate);
 }
 
 int sandbox_clk_test_enable(struct udevice *dev, int id)
@@ -68,7 +100,7 @@
 	if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
 		return -EINVAL;
 
-	return clk_enable(&sbct->clks[id]);
+	return clk_enable(sbct->clkps[id]);
 }
 
 int sandbox_clk_test_enable_bulk(struct udevice *dev)
@@ -85,7 +117,7 @@
 	if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
 		return -EINVAL;
 
-	return clk_disable(&sbct->clks[id]);
+	return clk_disable(sbct->clkps[id]);
 }
 
 int sandbox_clk_test_disable_bulk(struct udevice *dev)
@@ -100,7 +132,8 @@
 	struct sandbox_clk_test *sbct = dev_get_priv(dev);
 	int i, ret;
 
-	for (i = 0; i < SANDBOX_CLK_TEST_ID_COUNT; i++) {
+	devm_clk_put(dev, sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM1]);
+	for (i = 0; i < SANDBOX_CLK_TEST_NON_DEVM_COUNT; i++) {
 		ret = clk_free(&sbct->clks[i]);
 		if (ret)
 			return ret;
@@ -122,13 +155,27 @@
 	int i;
 
 	for (i = 0; i < SANDBOX_CLK_TEST_ID_COUNT; i++) {
-		if (!clk_valid(&sbct->clks[i]))
-			return -EINVAL;
+		if (!clk_valid(sbct->clkps[i]))
+			if (i != SANDBOX_CLK_TEST_ID_DEVM_NULL)
+				return -EINVAL;
 	}
 
 	return 0;
 }
 
+static int sandbox_clk_test_probe(struct udevice *dev)
+{
+	struct sandbox_clk_test *sbct = dev_get_priv(dev);
+	int i;
+
+	for (i = 0; i < SANDBOX_CLK_TEST_ID_DEVM1; i++)
+		sbct->clkps[i] = &sbct->clks[i];
+	for (i = SANDBOX_CLK_TEST_ID_DEVM1; i < SANDBOX_CLK_TEST_ID_COUNT; i++)
+		sbct->clkps[i] = NULL;
+
+	return 0;
+}
+
 static const struct udevice_id sandbox_clk_test_ids[] = {
 	{ .compatible = "sandbox,clk-test" },
 	{ }
@@ -138,5 +185,6 @@
 	.name = "sandbox_clk_test",
 	.id = UCLASS_MISC,
 	.of_match = sandbox_clk_test_ids,
+	.probe = sandbox_clk_test_probe,
 	.priv_auto_alloc_size = sizeof(struct sandbox_clk_test),
 };
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index 92e9337..5ae4781 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -89,6 +89,9 @@
 };
 
 static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+static const char *const periph_sels[]	= { "periph_pre", "periph_clk2", };
+static const char *const periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m",
+					       "pll2_pfd0_352m", "pll2_198m", };
 
 static int imx6q_clk_probe(struct udevice *dev)
 {
@@ -161,6 +164,24 @@
 	clk_dm(IMX6QDL_CLK_USDHC4,
 	       imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8));
 
+	clk_dm(IMX6QDL_CLK_PERIPH_PRE,
+	       imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels,
+			   ARRAY_SIZE(periph_pre_sels)));
+	clk_dm(IMX6QDL_CLK_PERIPH,
+	       imx_clk_busy_mux("periph",  base + 0x14, 25, 1, base + 0x48,
+				5, periph_sels,  ARRAY_SIZE(periph_sels)));
+	clk_dm(IMX6QDL_CLK_AHB,
+	       imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3,
+				    base + 0x48, 1));
+	clk_dm(IMX6QDL_CLK_IPG,
+	       imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2));
+	clk_dm(IMX6QDL_CLK_IPG_PER,
+	       imx_clk_divider("ipg_per", "ipg", base + 0x1c, 0, 6));
+	clk_dm(IMX6QDL_CLK_I2C1,
+	       imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6));
+	clk_dm(IMX6QDL_CLK_I2C2,
+	       imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8));
+
 	return 0;
 }
 
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 4956e04..07dcf94 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -92,6 +92,14 @@
 			reg, shift, width, 0);
 }
 
+static inline struct clk *
+imx_clk_busy_divider(const char *name, const char *parent, void __iomem *reg,
+		     u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift)
+{
+	return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
+			reg, shift, width, 0);
+}
+
 static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
 		void __iomem *reg, u8 shift, u8 width)
 {
@@ -126,6 +134,16 @@
 			width, 0);
 }
 
+static inline struct clk *
+imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width,
+		 void __iomem *busy_reg, u8 busy_shift,
+		 const char * const *parents, int num_parents)
+{
+	return clk_register_mux(NULL, name, parents, num_parents,
+			CLK_SET_RATE_NO_REPARENT, reg, shift,
+			width, 0);
+}
+
 static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg,
 			u8 shift, u8 width, const char * const *parents,
 			int num_parents)
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 95f26ef..8eabaf8 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -423,7 +423,7 @@
 		 * Process 'assigned-{clocks/clock-parents/clock-rates}'
 		 * properties
 		 */
-		ret = clk_set_defaults(dev);
+		ret = clk_set_defaults(dev, 0);
 		if (ret)
 			goto fail;
 	}
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 297f0a0..8f0eab2 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -57,7 +57,7 @@
 
 int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
 {
-	const fdt64_t *cell;
+	const unaligned_fdt64_t *cell;
 	int len;
 
 	assert(ofnode_valid(node));
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index d1d12ee..e9e55c9 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -462,5 +462,5 @@
 
 	reg &= ~mask;
 
-	return regmap_write(map, offset, reg | val);
+	return regmap_write(map, offset, reg | (val & mask));
 }
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 36f4d1c..c520ef1 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -6,6 +6,8 @@
  * Pavel Herrmann <morpheus.ibis@gmail.com>
  */
 
+#define LOG_CATEGORY LOGC_DM
+
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
@@ -303,7 +305,7 @@
 	int ret;
 
 	*devp = NULL;
-	debug("%s: %d %d\n", __func__, find_req_seq, seq_or_req_seq);
+	log_debug("%d %d\n", find_req_seq, seq_or_req_seq);
 	if (seq_or_req_seq == -1)
 		return -ENODEV;
 	ret = uclass_get(id, &uc);
@@ -311,15 +313,16 @@
 		return ret;
 
 	uclass_foreach_dev(dev, uc) {
-		debug("   - %d %d '%s'\n", dev->req_seq, dev->seq, dev->name);
+		log_debug("   - %d %d '%s'\n",
+			  dev->req_seq, dev->seq, dev->name);
 		if ((find_req_seq ? dev->req_seq : dev->seq) ==
 				seq_or_req_seq) {
 			*devp = dev;
-			debug("   - found\n");
+			log_debug("   - found\n");
 			return 0;
 		}
 	}
-	debug("   - not found\n");
+	log_debug("   - not found\n");
 
 	return -ENODEV;
 }
diff --git a/drivers/gpio/da8xx_gpio.c b/drivers/gpio/da8xx_gpio.c
index bd79448..0a50c68 100644
--- a/drivers/gpio/da8xx_gpio.c
+++ b/drivers/gpio/da8xx_gpio.c
@@ -342,13 +342,6 @@
 }
 #endif
 
-static int _gpio_direction_output(struct davinci_gpio *bank, unsigned int gpio, int value)
-{
-	clrbits_le32(&bank->dir, 1U << GPIO_BIT(gpio));
-	gpio_set_value(gpio, value);
-	return 0;
-}
-
 static int _gpio_direction_input(struct davinci_gpio *bank, unsigned int gpio)
 {
 	setbits_le32(&bank->dir, 1U << GPIO_BIT(gpio));
@@ -377,6 +370,13 @@
 	return in_le32(&bank->dir) & (1U << GPIO_BIT(gpio));
 }
 
+static int _gpio_direction_output(struct davinci_gpio *bank, unsigned int gpio,
+				  int value)
+{
+	clrbits_le32(&bank->dir, 1U << GPIO_BIT(gpio));
+	_gpio_set_value(bank, gpio, value);
+	return 0;
+}
 #ifndef CONFIG_DM_GPIO
 
 void gpio_info(void)
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 28d2312..cd357ea 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -23,10 +23,6 @@
 #include <asm/io.h>
 #include <dm.h>
 
-#if !CONFIG_IS_ENABLED(BLK)
-#include "mmc_private.h"
-#endif
-
 DECLARE_GLOBAL_DATA_PTR;
 
 #define SDHCI_IRQ_EN_BITS		(IRQSTATEN_CC | IRQSTATEN_TC | \
@@ -35,7 +31,6 @@
 				IRQSTATEN_CIE | IRQSTATEN_DTOE | IRQSTATEN_DCE | \
 				IRQSTATEN_DEBE | IRQSTATEN_BRR | IRQSTATEN_BWR | \
 				IRQSTATEN_DINT)
-#define ESDHC_DRIVER_STAGE_VALUE 0xffffffff
 
 struct fsl_esdhc {
 	uint    dsaddr;		/* SDMA system address register */
@@ -98,7 +93,7 @@
 	struct clk per_clk;
 	unsigned int clock;
 	unsigned int bus_width;
-#if !CONFIG_IS_ENABLED(BLK)
+#if !CONFIG_IS_ENABLED(DM_MMC)
 	struct mmc *mmc;
 #endif
 	struct udevice *dev;
@@ -506,7 +501,6 @@
 	struct fsl_esdhc *regs = priv->esdhc_regs;
 	int div = 1;
 	int pre_div = 2;
-	int ddr_pre_div = mmc->ddr_mode ? 2 : 1;
 	unsigned int sdhc_clk = priv->sdhc_clk;
 	u32 time_out;
 	u32 value;
@@ -515,10 +509,10 @@
 	if (clock < mmc->cfg->f_min)
 		clock = mmc->cfg->f_min;
 
-	while (sdhc_clk / (16 * pre_div * ddr_pre_div) > clock && pre_div < 256)
+	while (sdhc_clk / (16 * pre_div) > clock && pre_div < 256)
 		pre_div *= 2;
 
-	while (sdhc_clk / (div * pre_div * ddr_pre_div) > clock && div < 16)
+	while (sdhc_clk / (div * pre_div) > clock && div < 16)
 		div++;
 
 	pre_div >>= 1;
@@ -778,9 +772,6 @@
 		cfg->host_caps = MMC_MODE_4BIT;
 
 	cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
-#ifdef CONFIG_SYS_FSL_ESDHC_HAS_DDR_MODE
-	cfg->host_caps |= MMC_MODE_DDR_52MHz;
-#endif
 
 	if (priv->bus_width > 0) {
 		if (priv->bus_width < 8)
@@ -960,9 +951,6 @@
 	fdt_addr_t addr;
 	unsigned int val;
 	struct mmc *mmc;
-#if !CONFIG_IS_ENABLED(BLK)
-	struct blk_desc *bdesc;
-#endif
 	int ret;
 
 	addr = dev_read_addr(dev);
@@ -1028,32 +1016,12 @@
 	mmc = &plat->mmc;
 	mmc->cfg = &plat->cfg;
 	mmc->dev = dev;
-#if !CONFIG_IS_ENABLED(BLK)
-	mmc->priv = priv;
-
-	/* Setup dsr related values */
-	mmc->dsr_imp = 0;
-	mmc->dsr = ESDHC_DRIVER_STAGE_VALUE;
-	/* Setup the universal parts of the block interface just once */
-	bdesc = mmc_get_blk_desc(mmc);
-	bdesc->if_type = IF_TYPE_MMC;
-	bdesc->removable = 1;
-	bdesc->devnum = mmc_get_next_devnum();
-	bdesc->block_read = mmc_bread;
-	bdesc->block_write = mmc_bwrite;
-	bdesc->block_erase = mmc_berase;
-
-	/* setup initial part type */
-	bdesc->part_type = mmc->cfg->part_type;
-	mmc_list_add(mmc);
-#endif
 
 	upriv->mmc = mmc;
 
 	return esdhc_init_common(priv, mmc);
 }
 
-#if CONFIG_IS_ENABLED(DM_MMC)
 static int fsl_esdhc_get_cd(struct udevice *dev)
 {
 	struct fsl_esdhc_priv *priv = dev_get_priv(dev);
@@ -1086,30 +1054,25 @@
 	.execute_tuning = fsl_esdhc_execute_tuning,
 #endif
 };
-#endif
 
 static const struct udevice_id fsl_esdhc_ids[] = {
 	{ .compatible = "fsl,esdhc", },
 	{ /* sentinel */ }
 };
 
-#if CONFIG_IS_ENABLED(BLK)
 static int fsl_esdhc_bind(struct udevice *dev)
 {
 	struct fsl_esdhc_plat *plat = dev_get_platdata(dev);
 
 	return mmc_bind(dev, &plat->mmc, &plat->cfg);
 }
-#endif
 
 U_BOOT_DRIVER(fsl_esdhc) = {
 	.name	= "fsl-esdhc-mmc",
 	.id	= UCLASS_MMC,
 	.of_match = fsl_esdhc_ids,
 	.ops	= &fsl_esdhc_ops,
-#if CONFIG_IS_ENABLED(BLK)
 	.bind	= fsl_esdhc_bind,
-#endif
 	.probe	= fsl_esdhc_probe,
 	.platdata_auto_alloc_size = sizeof(struct fsl_esdhc_plat),
 	.priv_auto_alloc_size = sizeof(struct fsl_esdhc_priv),
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c
index 96b27e6..8839483 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c
@@ -3,36 +3,6 @@
 #include <common.h>
 #include "brcmnand_compat.h"
 
-struct clk *devm_clk_get(struct udevice *dev, const char *id)
-{
-	struct clk *clk;
-	int ret;
-
-	clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
-	if (!clk) {
-		debug("%s: can't allocate clock\n", __func__);
-		return ERR_PTR(-ENOMEM);
-	}
-
-	ret = clk_get_by_name(dev, id, clk);
-	if (ret < 0) {
-		debug("%s: can't get clock (ret = %d)!\n", __func__, ret);
-		return ERR_PTR(ret);
-	}
-
-	return clk;
-}
-
-int clk_prepare_enable(struct clk *clk)
-{
-	return clk_enable(clk);
-}
-
-void clk_disable_unprepare(struct clk *clk)
-{
-	clk_disable(clk);
-}
-
 static char *devm_kvasprintf(struct udevice *dev, gfp_t gfp, const char *fmt,
 			     va_list ap)
 {
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
index 02cab0f..6f9bec7 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
@@ -6,10 +6,6 @@
 #include <clk.h>
 #include <dm.h>
 
-struct clk *devm_clk_get(struct udevice *dev, const char *id);
-int clk_prepare_enable(struct clk *clk);
-void clk_disable_unprepare(struct clk *clk);
-
 char *devm_kasprintf(struct udevice *dev, gfp_t gfp, const char *fmt, ...);
 
 #endif /* __BRCMNAND_COMPAT_H */
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index d3b007a..d77f818 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -3,6 +3,7 @@
 config DM_SPI_FLASH
 	bool "Enable Driver Model for SPI flash"
 	depends on DM && DM_SPI
+	imply SPI_FLASH
 	help
 	  Enable driver model for SPI flash. This SPI flash interface
 	  (spi_flash_probe(), spi_flash_write(), etc.) is then
@@ -26,11 +27,10 @@
 	  stored in a file on the host filesystem.
 
 config SPI_FLASH
-	bool "Legacy SPI Flash Interface support"
-	depends on SPI
+	bool "SPI Flash Core Interface support"
 	select SPI_MEM
 	help
-	  Enable the legacy SPI flash support. This will include basic
+	  Enable the SPI flash Core support. This will include basic
 	  standard support for things like probing, read / write, and
 	  erasing through cmd_sf interface.
 
@@ -196,4 +196,12 @@
 
 	  If unsure, say N
 
+config SPL_SPI_FLASH_MTD
+	bool "SPI flash MTD support for SPL"
+	depends on SPI_FLASH
+	help
+          Enable the MTD support for the SPI flash layer in SPL.
+
+	  If unsure, say N
+
 endmenu # menu "SPI Flash Support"
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 20db101..b5dfa30 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -19,5 +19,5 @@
 
 obj-$(CONFIG_SPI_FLASH) += spi-nor.o
 obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o
-obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o
+obj-$(CONFIG_$(SPL_)SPI_FLASH_MTD) += sf_mtd.o
 obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index bb8c19a..5c64303 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -77,7 +77,7 @@
 int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash);
 
 
-#ifdef CONFIG_SPI_FLASH_MTD
+#if CONFIG_IS_ENABLED(SPI_FLASH_MTD)
 int spi_flash_mtd_register(struct spi_flash *flash);
 void spi_flash_mtd_unregister(void);
 #endif
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 73297e1..f051e47 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -44,7 +44,7 @@
 	if (ret)
 		goto err_read_id;
 
-#ifdef CONFIG_SPI_FLASH_MTD
+#if CONFIG_IS_ENABLED(SPI_FLASH_MTD)
 	ret = spi_flash_mtd_register(flash);
 #endif
 
@@ -83,7 +83,7 @@
 
 void spi_flash_free(struct spi_flash *flash)
 {
-#ifdef CONFIG_SPI_FLASH_MTD
+#if CONFIG_IS_ENABLED(SPI_FLASH_MTD)
 	spi_flash_mtd_unregister();
 #endif
 	spi_free_slave(flash->spi);
@@ -152,7 +152,7 @@
 
 static int spi_flash_std_remove(struct udevice *dev)
 {
-#ifdef CONFIG_SPI_FLASH_MTD
+#if CONFIG_IS_ENABLED(SPI_FLASH_MTD)
 	spi_flash_mtd_unregister();
 #endif
 	return 0;
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 990e39d..5a8c084 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -380,12 +380,12 @@
 
 	if (fsr & (FSR_E_ERR | FSR_P_ERR)) {
 		if (fsr & FSR_E_ERR)
-			dev_dbg(nor->dev, "Erase operation failed.\n");
+			dev_err(nor->dev, "Erase operation failed.\n");
 		else
-			dev_dbg(nor->dev, "Program operation failed.\n");
+			dev_err(nor->dev, "Program operation failed.\n");
 
 		if (fsr & FSR_PT_ERR)
-			dev_dbg(nor->dev,
+			dev_err(nor->dev,
 				"Attempted to modify a protected sector.\n");
 
 		nor->write_reg(nor, SPINOR_OP_CLFSR, NULL, 0);
@@ -1916,7 +1916,7 @@
 
 		erasesize = 1U << erasesize;
 		opcode = (half >> 8) & 0xff;
-#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
+#ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS
 		if (erasesize == SZ_4K) {
 			nor->erase_opcode = opcode;
 			mtd->erasesize = erasesize;
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 6996c0a..d3b8457 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -58,7 +58,7 @@
  * All newly added entries should describe *hardware* and should use SECT_4K
  * (or SECT_4K_PMC) if hardware supports erasing 4 KiB sectors. For usage
  * scenarios excluding small sectors there is config option that can be
- * disabled: CONFIG_MTD_SPI_NOR_USE_4K_SECTORS.
+ * disabled: CONFIG_SPI_FLASH_USE_4K_SECTORS.
  * For historical (and compatibility) reasons (before we got above config) some
  * old entries may be missing 4K flag.
  */
@@ -75,6 +75,7 @@
 	{ INFO("at45db161d",	0x1f2600, 0, 64 * 1024,  32, SECT_4K) },
 	{ INFO("at45db321d",	0x1f2700, 0, 64 * 1024,  64, SECT_4K) },
 	{ INFO("at45db641d",	0x1f2800, 0, 64 * 1024, 128, SECT_4K) },
+	{ INFO("at25sl321",	0x1f4216, 0, 64 * 1024,  64, SECT_4K) },
 	{ INFO("at26df081a", 	0x1f4501, 0, 64 * 1024,  16, SECT_4K) },
 #endif
 #ifdef CONFIG_SPI_FLASH_EON		/* EON */
@@ -128,6 +129,8 @@
 			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ INFO("is25wp128",  0x9d7018, 0, 64 * 1024, 256,
 			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("is25wp256",  0x9d7019, 0, 64 * 1024, 512,
+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 #endif
 #ifdef CONFIG_SPI_FLASH_MACRONIX	/* MACRONIX */
 	/* Macronix */
@@ -161,12 +164,16 @@
 	{ INFO("n25q064a",    0x20bb17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
 	{ INFO("n25q128a11",  0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
 	{ INFO("n25q128a13",  0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
-	{ INFO("n25q256a",    0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-	{ INFO("n25q256ax1",  0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO6("mt25ql256a",    0x20ba19, 0x104400, 64 * 1024,  512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) },
+	{ INFO("n25q256a",    0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_FSR) },
+	{ INFO6("mt25qu256a",  0x20bb19, 0x104400, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) },
+	{ INFO("n25q256ax1",  0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ | USE_FSR) },
 	{ INFO6("mt25qu512a",  0x20bb20, 0x104400, 64 * 1024, 1024,
-		 SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-	{ INFO("n25q512a",    0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-	{ INFO("n25q512ax3",  0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+		 SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES |
+		 USE_FSR) },
+	{ INFO("n25q512a",    0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+	{ INFO6("mt25ql512a",  0x20ba20, 0x104400, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("n25q512ax3",  0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 	{ INFO("n25q00",      0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 	{ INFO("n25q00a",     0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 	{ INFO("mt25qu02g",   0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index ee6b581..f915817 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -123,6 +123,9 @@
 	}
 	*prp2 = (ulong)dev->prp_pool;
 
+	flush_dcache_range((ulong)dev->prp_pool, (ulong)dev->prp_pool +
+			   dev->prp_entry_num * sizeof(u64));
+
 	return 0;
 }
 
@@ -580,14 +583,19 @@
 
 static int nvme_get_info_from_identify(struct nvme_dev *dev)
 {
-	ALLOC_CACHE_ALIGN_BUFFER(char, buf, sizeof(struct nvme_id_ctrl));
-	struct nvme_id_ctrl *ctrl = (struct nvme_id_ctrl *)buf;
+	struct nvme_id_ctrl *ctrl;
 	int ret;
 	int shift = NVME_CAP_MPSMIN(dev->cap) + 12;
 
+	ctrl = memalign(dev->page_size, sizeof(struct nvme_id_ctrl));
+	if (!ctrl)
+		return -ENOMEM;
+
 	ret = nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl);
-	if (ret)
+	if (ret) {
+		free(ctrl);
 		return -EIO;
+	}
 
 	dev->nn = le32_to_cpu(ctrl->nn);
 	dev->vwc = ctrl->vwc;
@@ -618,6 +626,7 @@
 		dev->max_transfer_shift = 20;
 	}
 
+	free(ctrl);
 	return 0;
 }
 
@@ -658,16 +667,21 @@
 	struct blk_desc *desc = dev_get_uclass_platdata(udev);
 	struct nvme_ns *ns = dev_get_priv(udev);
 	u8 flbas;
-	ALLOC_CACHE_ALIGN_BUFFER(char, buf, sizeof(struct nvme_id_ns));
-	struct nvme_id_ns *id = (struct nvme_id_ns *)buf;
 	struct pci_child_platdata *pplat;
+	struct nvme_id_ns *id;
+
+	id = memalign(ndev->page_size, sizeof(struct nvme_id_ns));
+	if (!id)
+		return -ENOMEM;
 
 	memset(ns, 0, sizeof(*ns));
 	ns->dev = ndev;
 	/* extract the namespace id from the block device name */
 	ns->ns_id = trailing_strtol(udev->name) + 1;
-	if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)(long)id))
+	if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)(long)id)) {
+		free(id);
 		return -EIO;
+	}
 
 	memcpy(&ns->eui64, &id->eui64, sizeof(id->eui64));
 	flbas = id->flbas & NVME_NS_FLBAS_LBA_MASK;
@@ -686,6 +700,7 @@
 	memcpy(desc->product, ndev->serial, sizeof(ndev->serial));
 	memcpy(desc->revision, ndev->firmware_rev, sizeof(ndev->firmware_rev));
 
+	free(id);
 	return 0;
 }
 
@@ -705,9 +720,8 @@
 	u16 lbas = 1 << (dev->max_transfer_shift - ns->lba_shift);
 	u64 total_lbas = blkcnt;
 
-	if (!read)
-		flush_dcache_range((unsigned long)buffer,
-				   (unsigned long)buffer + total_len);
+	flush_dcache_range((unsigned long)buffer,
+			   (unsigned long)buffer + total_len);
 
 	c.rw.opcode = read ? nvme_cmd_read : nvme_cmd_write;
 	c.rw.flags = 0;
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c
index a0ac30a..e201a90 100644
--- a/drivers/phy/phy-uclass.c
+++ b/drivers/phy/phy-uclass.c
@@ -108,35 +108,55 @@
 
 int generic_phy_init(struct phy *phy)
 {
-	struct phy_ops const *ops = phy_dev_ops(phy->dev);
+	struct phy_ops const *ops;
+
+	if (!phy)
+		return 0;
+	ops = phy_dev_ops(phy->dev);
 
 	return ops->init ? ops->init(phy) : 0;
 }
 
 int generic_phy_reset(struct phy *phy)
 {
-	struct phy_ops const *ops = phy_dev_ops(phy->dev);
+	struct phy_ops const *ops;
+
+	if (!phy)
+		return 0;
+	ops = phy_dev_ops(phy->dev);
 
 	return ops->reset ? ops->reset(phy) : 0;
 }
 
 int generic_phy_exit(struct phy *phy)
 {
-	struct phy_ops const *ops = phy_dev_ops(phy->dev);
+	struct phy_ops const *ops;
+
+	if (!phy)
+		return 0;
+	ops = phy_dev_ops(phy->dev);
 
 	return ops->exit ? ops->exit(phy) : 0;
 }
 
 int generic_phy_power_on(struct phy *phy)
 {
-	struct phy_ops const *ops = phy_dev_ops(phy->dev);
+	struct phy_ops const *ops;
+
+	if (!phy)
+		return 0;
+	ops = phy_dev_ops(phy->dev);
 
 	return ops->power_on ? ops->power_on(phy) : 0;
 }
 
 int generic_phy_power_off(struct phy *phy)
 {
-	struct phy_ops const *ops = phy_dev_ops(phy->dev);
+	struct phy_ops const *ops;
+
+	if (!phy)
+		return 0;
+	ops = phy_dev_ops(phy->dev);
 
 	return ops->power_off ? ops->power_off(phy) : 0;
 }
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b8ca2bd..7be867d 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -1,5 +1,22 @@
 menuconfig SPI
 	bool "SPI Support"
+	help
+	  The "Serial Peripheral Interface" is a low level synchronous
+          protocol.  Chips that support SPI can have data transfer rates
+          up to several tens of Mbit/sec.  Chips are addressed with a
+          controller and a chipselect.  Most SPI slaves don't support
+          dynamic device discovery; some are even write-only or read-only.
+
+          SPI is widely used by microcontrollers to talk with sensors,
+          eeprom and flash memory, codecs and various other controller
+          chips, analog to digital (and d-to-a) converters, and more.
+          MMC and SD cards can be accessed using SPI protocol; and for
+          DataFlash cards used in MMC sockets, SPI must always be used.
+
+          SPI is one of a family of similar protocols using a four wire
+          interface (select, clock, data in, data out) including Microwire
+          (half duplex), SSP, SSI, and PSP.  This driver framework should
+          work with most such devices and controllers.
 
 if SPI
 
@@ -243,6 +260,7 @@
 
 config SPI_SUNXI
 	bool "Allwinner SoC SPI controllers"
+	default ARCH_SUNXI
 	help
 	  Enable the Allwinner SoC SPi controller driver.
 
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
index 4fd3c05..2070692 100644
--- a/drivers/spi/ath79_spi.c
+++ b/drivers/spi/ath79_spi.c
@@ -198,7 +198,7 @@
 {
 	/* Always allow activity on CS 0/1/2 */
 	if (cs >= 3)
-		return -ENODEV;
+		return -EINVAL;
 
 	return 0;
 }
diff --git a/drivers/spi/bcm63xx_hsspi.c b/drivers/spi/bcm63xx_hsspi.c
index e82b80c..529adfb 100644
--- a/drivers/spi/bcm63xx_hsspi.c
+++ b/drivers/spi/bcm63xx_hsspi.c
@@ -108,7 +108,7 @@
 
 	if (cs >= priv->num_cs) {
 		printf("no cs %u\n", cs);
-		return -ENODEV;
+		return -EINVAL;
 	}
 
 	return 0;
diff --git a/drivers/spi/bcm63xx_spi.c b/drivers/spi/bcm63xx_spi.c
index 4d19e03..69f88c9 100644
--- a/drivers/spi/bcm63xx_spi.c
+++ b/drivers/spi/bcm63xx_spi.c
@@ -130,7 +130,7 @@
 
 	if (cs >= priv->num_cs) {
 		printf("no cs %u\n", cs);
-		return -ENODEV;
+		return -EINVAL;
 	}
 
 	return 0;
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 7d58cfa..91e613e 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -518,8 +518,22 @@
 static int dw_spi_remove(struct udevice *bus)
 {
 	struct dw_spi_priv *priv = dev_get_priv(bus);
+	int ret;
+
+	ret = reset_release_bulk(&priv->resets);
+	if (ret)
+		return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+	ret = clk_disable(&priv->clk);
+	if (ret)
+		return ret;
 
-	return reset_release_bulk(&priv->resets);
+	ret = clk_free(&priv->clk);
+	if (ret)
+		return ret;
+#endif
+	return 0;
 }
 
 static const struct dm_spi_ops dw_spi_ops = {
diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c
index 906401e..16473ec 100644
--- a/drivers/spi/sandbox_spi.c
+++ b/drivers/spi/sandbox_spi.c
@@ -117,7 +117,7 @@
 {
 	/* Always allow activity on CS 0 */
 	if (cs >= 1)
-		return -ENODEV;
+		return -EINVAL;
 
 	return 0;
 }
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index a4d1b65..9475160 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -261,11 +261,10 @@
 		return ops->cs_info(bus, cs, info);
 
 	/*
-	 * We could assume there is at least one valid chip select, but best
-	 * to be sure and return an error in this case. The driver didn't
-	 * care enough to tell us.
+	 * We could assume there is at least one valid chip select.
+	 * The driver didn't care enough to tell us.
 	 */
-	return -ENODEV;
+	return 0;
 }
 
 int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp,
diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c
index a54b10f..567e33f 100644
--- a/drivers/spi/tegra20_sflash.c
+++ b/drivers/spi/tegra20_sflash.c
@@ -78,7 +78,7 @@
 {
 	/* Tegra20 SPI-Flash - only 1 device ('bus/cs') */
 	if (cs != 0)
-		return -ENODEV;
+		return -EINVAL;
 	else
 		return 0;
 }
diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c
index 08764ee..202e5ab 100644
--- a/drivers/virtio/virtio_pci_legacy.c
+++ b/drivers/virtio/virtio_pci_legacy.c
@@ -277,7 +277,7 @@
 
 static int virtio_pci_bind(struct udevice *udev)
 {
-	static int num_devs;
+	static unsigned int num_devs;
 	char name[20];
 
 	/* Create a unique device name for PCI type devices */
diff --git a/dts/Kconfig b/dts/Kconfig
index c9ab66c..2bd959a 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -44,7 +44,7 @@
 	depends on SPL && OF_CONTROL
 	help
 	  Some boards use device tree in U-Boot but only have 4KB of SRAM
-	  which is not enough to support device tree. Enable this option to
+	  which is not enough to support device tree. Disable this option to
 	  allow such boards to be supported by U-Boot SPL.
 
 config TPL_OF_CONTROL
@@ -131,7 +131,7 @@
 	  separated by <space>.
 
 choice
-	prompt "SPL OF LIST compression"
+	prompt "OF LIST compression"
 	depends on MULTI_DTB_FIT
 	default MULTI_DTB_FIT_NO_COMPRESSION
 
diff --git a/include/bootstage.h b/include/bootstage.h
index 5e7e242..d105ae0 100644
--- a/include/bootstage.h
+++ b/include/bootstage.h
@@ -170,6 +170,8 @@
 	 * rough boot timing information.
 	 */
 	BOOTSTAGE_ID_AWAKE,
+	BOOTSTAGE_ID_START_TPL,
+	BOOTSTAGE_ID_END_TPL,
 	BOOTSTAGE_ID_START_SPL,
 	BOOTSTAGE_ID_END_SPL,
 	BOOTSTAGE_ID_START_UBOOT_F,
diff --git a/include/clk.h b/include/clk.h
index 18b2e3c..a5ee53d 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -155,6 +155,37 @@
 int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk);
 
 /**
+ * devm_clk_get - lookup and obtain a managed reference to a clock producer.
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Returns a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno.  The implementation
+ * uses @dev and @id to determine the clock consumer, and thereby
+ * the clock producer.  (IOW, @id may be identical strings, but
+ * clk_get may return different clock producers depending on @dev.)
+ *
+ * Drivers must assume that the clock source is not enabled.
+ *
+ * devm_clk_get should not be called from within interrupt context.
+ *
+ * The clock will automatically be freed when the device is unbound
+ * from the bus.
+ */
+struct clk *devm_clk_get(struct udevice *dev, const char *id);
+
+/**
+ * devm_clk_get_optional - lookup and obtain a managed reference to an optional
+ *			   clock producer.
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Behaves the same as devm_clk_get() except where there is no clock producer.
+ * In this case, instead of returning -ENOENT, the function returns NULL.
+ */
+struct clk *devm_clk_get_optional(struct udevice *dev, const char *id);
+
+/**
  * clk_release_all() - Disable (turn off)/Free an array of previously
  * requested clocks.
  *
@@ -168,6 +199,19 @@
  */
 int clk_release_all(struct clk *clk, int count);
 
+/**
+ * devm_clk_put	- "free" a managed clock source
+ * @dev: device used to acquire the clock
+ * @clk: clock source acquired with devm_clk_get()
+ *
+ * Note: drivers must ensure that all clk_enable calls made on this
+ * clock source are balanced by clk_disable calls prior to calling
+ * this function.
+ *
+ * clk_put should not be called from within interrupt context.
+ */
+void devm_clk_put(struct udevice *dev, struct clk *clk);
+
 #else
 static inline int clk_get_by_index(struct udevice *dev, int index,
 				   struct clk *clk)
@@ -200,10 +244,13 @@
  *
  * @dev:        A device to process (the ofnode associated with this device
  *              will be processed).
+ * @stage:	A integer. 0 indicates that this is called before the device
+ *		is probed. 1 indicates that this is called just after the
+ *		device has been probed
  */
-int clk_set_defaults(struct udevice *dev);
+int clk_set_defaults(struct udevice *dev, int stage);
 #else
-static inline int clk_set_defaults(struct udevice *dev)
+static inline int clk_set_defaults(struct udevice *dev, int stage)
 {
 	return 0;
 }
@@ -356,7 +403,7 @@
  */
 static inline bool clk_valid(struct clk *clk)
 {
-	return !!clk->dev;
+	return clk && !!clk->dev;
 }
 
 /**
@@ -379,3 +426,6 @@
  */
 bool clk_dev_binded(struct clk *clk);
 #endif
+
+#define clk_prepare_enable(clk) clk_enable(clk)
+#define clk_disable_unprepare(clk) clk_disable(clk)
diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index 3570a32..fc0935f 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -189,6 +189,7 @@
 		"fi\0" \
 	\
 	"nvme_boot=" \
+		BOOTENV_RUN_PCI_ENUM \
 		BOOTENV_RUN_NVME_INIT \
 		BOOTENV_SHARED_BLKDEV_BODY(nvme)
 #define BOOTENV_DEV_NVME	BOOTENV_DEV_BLKDEV
diff --git a/include/configs/aristainetos-common.h b/include/configs/aristainetos-common.h
index e998d9b..b451c7e 100644
--- a/include/configs/aristainetos-common.h
+++ b/include/configs/aristainetos-common.h
@@ -30,7 +30,6 @@
 #define CONFIG_ETHPRIME			"FEC"
 #define CONFIG_FEC_MXC_PHYADDR		0
 
-#define CONFIG_SPI_FLASH_MTD
 #define CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
 
 #define CONFIG_EXTRA_ENV_SETTINGS \
diff --git a/include/configs/cm_fx6.h b/include/configs/cm_fx6.h
index b957e9c..c1a6625 100644
--- a/include/configs/cm_fx6.h
+++ b/include/configs/cm_fx6.h
@@ -38,13 +38,6 @@
 #define CONFIG_MXC_UART_BASE		UART4_BASE
 #define CONFIG_SYS_BAUDRATE_TABLE	{9600, 19200, 38400, 57600, 115200}
 
-/* SPI flash */
-
-/* MTD support */
-#ifndef CONFIG_SPL_BUILD
-#define CONFIG_SPI_FLASH_MTD
-#endif
-
 /* Environment */
 #define CONFIG_ENV_SECT_SIZE		(64 * 1024)
 #define CONFIG_ENV_SIZE			(8 * 1024)
diff --git a/include/configs/da850evm.h b/include/configs/da850evm.h
index 41f0813..6876134 100644
--- a/include/configs/da850evm.h
+++ b/include/configs/da850evm.h
@@ -190,16 +190,11 @@
 #define CONFIG_ENV_SECT_SIZE		CONFIG_SYS_FLASH_SECT_SZ
 #endif
 
-#ifdef CONFIG_USE_SPIFLASH
-#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
+#if defined(CONFIG_USE_SPIFLASH) && defined(CONFIG_ENV_IS_IN_SPI_FLASH)
 #define CONFIG_ENV_SIZE			(64 << 10)
 #define CONFIG_ENV_OFFSET		(512 << 10)
 #define CONFIG_ENV_SECT_SIZE	(64 << 10)
 #endif
-#ifdef CONFIG_SPL_BUILD
-#undef CONFIG_SPI_FLASH_MTD
-#endif
-#endif
 
 /*
  * U-Boot general configuration
diff --git a/include/configs/dh_imx6.h b/include/configs/dh_imx6.h
index a854d0b..86c1192 100644
--- a/include/configs/dh_imx6.h
+++ b/include/configs/dh_imx6.h
@@ -59,7 +59,6 @@
 #if defined(CONFIG_SPL_BUILD)
 #undef CONFIG_DM_SPI
 #undef CONFIG_DM_SPI_FLASH
-#undef CONFIG_SPI_FLASH_MTD
 #endif
 
 /* UART */
diff --git a/include/configs/display5.h b/include/configs/display5.h
index d806415..65dae1f 100644
--- a/include/configs/display5.h
+++ b/include/configs/display5.h
@@ -39,7 +39,6 @@
 #if defined(CONFIG_SPL_BUILD)
 #undef CONFIG_DM_SPI
 #undef CONFIG_DM_SPI_FLASH
-#undef CONFIG_SPI_FLASH_MTD
 #endif
 
 /* Below values are "dummy" - only to avoid build break */
diff --git a/include/configs/gw_ventana.h b/include/configs/gw_ventana.h
index a27627e..e543061 100644
--- a/include/configs/gw_ventana.h
+++ b/include/configs/gw_ventana.h
@@ -47,15 +47,7 @@
 #define CONFIG_MXC_UART
 #define CONFIG_MXC_UART_BASE	       UART2_BASE
 
-#ifdef CONFIG_SPI_FLASH
-
-/* SPI */
-#ifdef CONFIG_CMD_SF
-  #define CONFIG_SPI_FLASH_MTD
-					     /* GPIO 3-19 (21248) */
-#endif
-
-#elif defined(CONFIG_SPL_NAND_SUPPORT)
+#if !defined(CONFIG_SPI_FLASH) && defined(CONFIG_SPL_NAND_SUPPORT)
 /* Enable NAND support */
 #ifdef CONFIG_CMD_NAND
   #define CONFIG_SYS_MAX_NAND_DEVICE	1
diff --git a/include/configs/rcar-gen2-common.h b/include/configs/rcar-gen2-common.h
index 71a5909..e940a8b 100644
--- a/include/configs/rcar-gen2-common.h
+++ b/include/configs/rcar-gen2-common.h
@@ -46,11 +46,9 @@
 #define CONFIG_ENV_SIZE_REDUND	(CONFIG_SYS_MONITOR_LEN)
 
 /* SF MTD */
-#if defined(CONFIG_SPI_FLASH_MTD) && !defined(CONFIG_SPL_BUILD)
-#else
+#ifdef CONFIG_SPL_BUILD
 #undef CONFIG_DM_SPI
 #undef CONFIG_DM_SPI_FLASH
-#undef CONFIG_SPI_FLASH_MTD
 #endif
 
 /* Timer */
diff --git a/include/configs/socfpga_common.h b/include/configs/socfpga_common.h
index 94268ed..baa2143 100644
--- a/include/configs/socfpga_common.h
+++ b/include/configs/socfpga_common.h
@@ -132,10 +132,6 @@
 /*
  * QSPI support
  */
-/* Enable multiple SPI NOR flash manufacturers */
-#ifndef CONFIG_SPL_BUILD
-#define CONFIG_SPI_FLASH_MTD
-#endif
 /* QSPI reference clock */
 #ifndef __ASSEMBLY__
 unsigned int cm_get_qspi_controller_clk_hz(void);
diff --git a/include/errno.h b/include/errno.h
index ccb7869..3af539b 100644
--- a/include/errno.h
+++ b/include/errno.h
@@ -12,12 +12,21 @@
 
 #define __set_errno(val) do { errno = val; } while (0)
 
+/**
+ * errno_str() - get description for error number
+ *
+ * @errno:	error number (negative in case of error)
+ * Return:	string describing the error. If CONFIG_ERRNO_STR is not
+ *		defined an empty string is returned.
+ */
 #ifdef CONFIG_ERRNO_STR
 const char *errno_str(int errno);
 #else
+static const char error_message[] = "";
+
 static inline const char *errno_str(int errno)
 {
-	return 0;
+	return error_message;
 }
 #endif
 #endif /* _ERRNO_H */
diff --git a/include/generic-phy.h b/include/generic-phy.h
index 947c582..95caf58 100644
--- a/include/generic-phy.h
+++ b/include/generic-phy.h
@@ -270,7 +270,7 @@
  */
 static inline bool generic_phy_valid(struct phy *phy)
 {
-	return phy->dev != NULL;
+	return phy && phy->dev;
 }
 
 #endif /*__GENERIC_PHY_H */
diff --git a/include/image.h b/include/image.h
index c1065c0..f4d2aaf 100644
--- a/include/image.h
+++ b/include/image.h
@@ -319,13 +319,13 @@
  * all data in network byte order (aka natural aka bigendian).
  */
 typedef struct image_header {
-	__be32		ih_magic;	/* Image Header Magic Number	*/
-	__be32		ih_hcrc;	/* Image Header CRC Checksum	*/
-	__be32		ih_time;	/* Image Creation Timestamp	*/
-	__be32		ih_size;	/* Image Data Size		*/
-	__be32		ih_load;	/* Data	 Load  Address		*/
-	__be32		ih_ep;		/* Entry Point Address		*/
-	__be32		ih_dcrc;	/* Image Data CRC Checksum	*/
+	uint32_t	ih_magic;	/* Image Header Magic Number	*/
+	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
+	uint32_t	ih_time;	/* Image Creation Timestamp	*/
+	uint32_t	ih_size;	/* Image Data Size		*/
+	uint32_t	ih_load;	/* Data	 Load  Address		*/
+	uint32_t	ih_ep;		/* Entry Point Address		*/
+	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
 	uint8_t		ih_os;		/* Operating System		*/
 	uint8_t		ih_arch;	/* CPU architecture		*/
 	uint8_t		ih_type;	/* Image Type			*/
diff --git a/include/linux/libfdt_env.h b/include/linux/libfdt_env.h
index e2bf79c..e49fcd7 100644
--- a/include/linux/libfdt_env.h
+++ b/include/linux/libfdt_env.h
@@ -16,6 +16,7 @@
 typedef __be16 fdt16_t;
 typedef __be32 fdt32_t;
 typedef __be64 fdt64_t;
+typedef __be64 unaligned_fdt64_t __aligned(4);
 
 #define fdt32_to_cpu(x) be32_to_cpu(x)
 #define cpu_to_fdt32(x) cpu_to_be32(x)
diff --git a/include/linux/types.h b/include/linux/types.h
index cc6f7cb..51cb284 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -151,12 +151,14 @@
 
 typedef unsigned __bitwise__	gfp_t;
 
+#ifdef __linux__
 struct ustat {
 	__kernel_daddr_t	f_tfree;
 	__kernel_ino_t		f_tinode;
 	char			f_fname[6];
 	char			f_fpack[6];
 };
+#endif
 
 #define DECLARE_BITMAP(name, bits) \
 	unsigned long name[BITS_TO_LONGS(bits)]
diff --git a/include/regmap.h b/include/regmap.h
index 0854200..9ada1af 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -295,7 +295,8 @@
  * @map:	The map returned by regmap_init_mem*()
  * @offset:	Offset of the memory
  * @mask:	Mask to apply to the read value
- * @val:	Value to apply to the value to write
+ * @val:	Value to OR with the read value after masking. Note that any
+ *	bits set in @val which are not set in @mask are ignored
  * Return: 0 if OK, -ve on error
  */
 int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val);
diff --git a/include/spi.h b/include/spi.h
index 5eec0c4..3f79168 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -458,7 +458,7 @@
 	 * @cs:		The chip select (0..n-1)
 	 * @info:	Returns information about the chip select, if valid.
 	 *		On entry info->dev is NULL
-	 * @return 0 if OK (and @info is set up), -ENODEV if the chip select
+	 * @return 0 if OK (and @info is set up), -EINVAL if the chip select
 	 *	   is invalid, other -ve value on error
 	 */
 	int (*cs_info)(struct udevice *bus, uint cs, struct spi_cs_info *info);
diff --git a/include/test/ut.h b/include/test/ut.h
index 19bcb8c..fbfde10 100644
--- a/include/test/ut.h
+++ b/include/test/ut.h
@@ -61,7 +61,8 @@
 	if (val1 != val2) {						\
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 #expr1 " == " #expr2,				\
-			 "Expected %d, got %d", val1, val2);		\
+			 "Expected %#x (%d), got %#x (%d)", val1, val1,	\
+			 val2, val2);					\
 		return CMD_RET_FAILURE;					\
 	}								\
 }
diff --git a/include/time.h b/include/time.h
index 1e9b369..a114952 100644
--- a/include/time.h
+++ b/include/time.h
@@ -13,6 +13,7 @@
  * Granularity may be larger than 1us if hardware does not support this.
  */
 unsigned long timer_get_us(void);
+uint64_t get_timer_us(uint64_t base);
 
 /*
  * timer_test_add_offset()
diff --git a/lib/errno_str.c b/lib/errno_str.c
index 0ba950e..2e5f4a8 100644
--- a/lib/errno_str.c
+++ b/lib/errno_str.c
@@ -13,7 +13,7 @@
 static const char * const errno_message[] = {
 	ERRNO_MSG(0, "Success"),
 	ERRNO_MSG(EPERM, "Operation not permitted"),
-	ERRNO_MSG(ENOEN, "No such file or directory"),
+	ERRNO_MSG(ENOENT, "No such file or directory"),
 	ERRNO_MSG(ESRCH, "No such process"),
 	ERRNO_MSG(EINTR, "Interrupted system call"),
 	ERRNO_MSG(EIO, "I/O error"),
@@ -26,7 +26,7 @@
 	ERRNO_MSG(ENOMEM, "Out of memory"),
 	ERRNO_MSG(EACCES, "Permission denied"),
 	ERRNO_MSG(EFAULT, "Bad address"),
-	ERRNO_MSG(ENOTBL, "Block device required"),
+	ERRNO_MSG(ENOTBLK, "Block device required"),
 	ERRNO_MSG(EBUSY, "Device or resource busy"),
 	ERRNO_MSG(EEXIST, "File exists"),
 	ERRNO_MSG(EXDEV, "Cross-device link"),
@@ -136,6 +136,8 @@
 	ERRNO_MSG(EDQUOT, "Quota exceeded"),
 	ERRNO_MSG(ENOMEDIUM, "No medium found"),
 	ERRNO_MSG(EMEDIUMTYPE, "Wrong medium type"),
+	/* Message for unsupported error numbers */
+	ERRNO_MSG(0, "Unknown error"),
 };
 
 const char *errno_str(int errno)
@@ -143,5 +145,9 @@
 	if (errno >= 0)
 		return errno_message[0];
 
-	return errno_message[abs(errno)];
+	errno = -errno;
+	if (errno >= ARRAY_SIZE(errno_message))
+		errno = ARRAY_SIZE(errno_message) - 1;
+
+	return errno_message[errno];
 }
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 17736ce..125d9db 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -242,7 +242,7 @@
 uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
 			   uint64_t default_val)
 {
-	const uint64_t *cell64;
+	const unaligned_fdt64_t *cell64;
 	int length;
 
 	cell64 = fdt_getprop(blob, node, prop_name, &length);
diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c
index d246699..684c512 100644
--- a/lib/libavb/avb_cmdline.c
+++ b/lib/libavb/avb_cmdline.c
@@ -39,6 +39,14 @@
     char part_name[AVB_PART_NAME_MAX_SIZE];
     char guid_buf[37];
 
+    /* Don't attempt to query the partition guid unless its search string is
+     * present in the command line. Note: the original cmdline is used here,
+     * not the replaced one. See b/116010959.
+     */
+    if (avb_strstr(cmdline, replace_str[n]) == NULL) {
+      continue;
+    }
+
     if (!avb_str_concat(part_name,
                         sizeof part_name,
                         part_name_str[n],
@@ -70,7 +78,15 @@
     }
   }
 
-  avb_assert(ret != NULL);
+  /* It's possible there is no _PARTUUID for replacement above.
+   * Duplicate cmdline to ret for additional substitutions below.
+   */
+  if (ret == NULL) {
+    ret = avb_strdup(cmdline);
+    if (ret == NULL) {
+      goto fail;
+    }
+  }
 
   /* Replace any additional substitutions. */
   if (additional_substitutions != NULL) {
@@ -198,21 +214,27 @@
 
 AvbSlotVerifyResult avb_append_options(
     AvbOps* ops,
+    AvbSlotVerifyFlags flags,
     AvbSlotVerifyData* slot_data,
     AvbVBMetaImageHeader* toplevel_vbmeta,
     AvbAlgorithmType algorithm_type,
-    AvbHashtreeErrorMode hashtree_error_mode) {
+    AvbHashtreeErrorMode hashtree_error_mode,
+    AvbHashtreeErrorMode resolved_hashtree_error_mode) {
   AvbSlotVerifyResult ret;
   const char* verity_mode;
   bool is_device_unlocked;
   AvbIOResult io_ret;
 
-  /* Add androidboot.vbmeta.device option. */
-  if (!cmdline_append_option(slot_data,
-                             "androidboot.vbmeta.device",
-                             "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
-    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-    goto out;
+  /* Add androidboot.vbmeta.device option... except if not using a vbmeta
+   * partition since it doesn't make sense in that case.
+   */
+  if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
+    if (!cmdline_append_option(slot_data,
+                               "androidboot.vbmeta.device",
+                               "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
   }
 
   /* Add androidboot.vbmeta.avb_version option. */
@@ -304,7 +326,7 @@
     const char* dm_verity_mode;
     char* new_ret;
 
-    switch (hashtree_error_mode) {
+    switch (resolved_hashtree_error_mode) {
       case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
         if (!cmdline_append_option(
                 slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
@@ -331,6 +353,12 @@
         verity_mode = "logging";
         dm_verity_mode = "ignore_corruption";
         break;
+      case AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO:
+        // Should never get here because MANAGED_RESTART_AND_EIO is
+        // remapped by avb_manage_hashtree_error_mode().
+        avb_assert_not_reached();
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+        goto out;
       default:
         ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
         goto out;
@@ -349,6 +377,13 @@
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
     goto out;
   }
+  if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
+    if (!cmdline_append_option(
+            slot_data, "androidboot.veritymode.managed", "yes")) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
+  }
 
   ret = AVB_SLOT_VERIFY_RESULT_OK;
 
diff --git a/lib/libavb/avb_cmdline.h b/lib/libavb/avb_cmdline.h
index 9af3a99..96539d8 100644
--- a/lib/libavb/avb_cmdline.h
+++ b/lib/libavb/avb_cmdline.h
@@ -43,10 +43,12 @@
 
 AvbSlotVerifyResult avb_append_options(
     AvbOps* ops,
+    AvbSlotVerifyFlags flags,
     AvbSlotVerifyData* slot_data,
     AvbVBMetaImageHeader* toplevel_vbmeta,
     AvbAlgorithmType algorithm_type,
-    AvbHashtreeErrorMode hashtree_error_mode);
+    AvbHashtreeErrorMode hashtree_error_mode,
+    AvbHashtreeErrorMode resolved_hashtree_error_mode);
 
 /* Allocates and initializes a new command line substitution list. Free with
  * |avb_free_cmdline_subst_list|.
diff --git a/lib/libavb/avb_descriptor.c b/lib/libavb/avb_descriptor.c
index fb0b305..9f03b97 100644
--- a/lib/libavb/avb_descriptor.c
+++ b/lib/libavb/avb_descriptor.c
@@ -72,7 +72,11 @@
     const AvbDescriptor* dh = (const AvbDescriptor*)p;
     avb_assert_aligned(dh);
     uint64_t nb_following = avb_be64toh(dh->num_bytes_following);
-    uint64_t nb_total = sizeof(AvbDescriptor) + nb_following;
+    uint64_t nb_total = 0;
+    if (!avb_safe_add(&nb_total, sizeof(AvbDescriptor), nb_following)) {
+      avb_error("Invalid descriptor length.\n");
+      goto out;
+    }
 
     if ((nb_total & 7) != 0) {
       avb_error("Invalid descriptor length.\n");
@@ -88,7 +92,10 @@
       goto out;
     }
 
-    p += nb_total;
+    if (!avb_safe_add_to((uint64_t*)(&p), nb_total)) {
+      avb_error("Invalid descriptor length.\n");
+      goto out;
+    }
   }
 
   ret = true;
diff --git a/lib/libavb/avb_ops.h b/lib/libavb/avb_ops.h
index 8bbdc7c..6a5c589 100644
--- a/lib/libavb/avb_ops.h
+++ b/lib/libavb/avb_ops.h
@@ -18,6 +18,7 @@
 
 /* Well-known names of named persistent values. */
 #define AVB_NPV_PERSISTENT_DIGEST_PREFIX "avb.persistent_digest."
+#define AVB_NPV_MANAGED_VERITY_MODE "avb.managed_verity_mode"
 
 /* Return codes used for I/O operations.
  *
@@ -171,6 +172,10 @@
    *
    * If AVB_IO_RESULT_OK is returned then |out_is_trusted| is set -
    * true if trusted or false if untrusted.
+   *
+   * NOTE: If AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is passed to
+   * avb_slot_verify() then this operation is never used. Instead, the
+   * validate_public_key_for_partition() operation is used
    */
   AvbIOResult (*validate_vbmeta_public_key)(AvbOps* ops,
                                             const uint8_t* public_key_data,
@@ -231,6 +236,9 @@
    * (NUL-terminated UTF-8 string). Returns the value in
    * |out_size_num_bytes|.
    *
+   * If the partition doesn't exist the AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION
+   * error code should be returned.
+   *
    * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
    */
   AvbIOResult (*get_size_of_partition)(AvbOps* ops,
@@ -253,9 +261,10 @@
    * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If |buffer_size| is smaller than the
    * size of the stored value, returns AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE.
    *
-   * This operation is currently only used to support persistent digests. If a
-   * device does not use persistent digests this function pointer can be set to
-   * NULL.
+   * This operation is currently only used to support persistent digests or the
+   * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO hashtree error mode. If a
+   * device does not use one of these features this function pointer can be set
+   * to NULL.
    */
   AvbIOResult (*read_persistent_value)(AvbOps* ops,
                                        const char* name,
@@ -275,14 +284,34 @@
    * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If the |value_size| is not supported,
    * returns AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE.
    *
-   * This operation is currently only used to support persistent digests. If a
-   * device does not use persistent digests this function pointer can be set to
-   * NULL.
+   * This operation is currently only used to support persistent digests or the
+   * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO hashtree error mode. If a
+   * device does not use one of these features this function pointer can be set
+   * to NULL.
    */
   AvbIOResult (*write_persistent_value)(AvbOps* ops,
                                         const char* name,
                                         size_t value_size,
                                         const uint8_t* value);
+
+  /* Like validate_vbmeta_public_key() but for when the flag
+   * AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is being used. The name of the
+   * partition to get the public key for is passed in |partition_name|.
+   *
+   * Also returns the rollback index location to use for the partition, in
+   * |out_rollback_index_location|.
+   *
+   * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+   */
+  AvbIOResult (*validate_public_key_for_partition)(
+      AvbOps* ops,
+      const char* partition,
+      const uint8_t* public_key_data,
+      size_t public_key_length,
+      const uint8_t* public_key_metadata,
+      size_t public_key_metadata_length,
+      bool* out_is_trusted,
+      uint32_t* out_rollback_index_location);
 };
 
 #ifdef __cplusplus
diff --git a/lib/libavb/avb_sha.h b/lib/libavb/avb_sha.h
index 365aaad..f5d02e0 100644
--- a/lib/libavb/avb_sha.h
+++ b/lib/libavb/avb_sha.h
@@ -31,8 +31,8 @@
 /* Data structure used for SHA-256. */
 typedef struct {
   uint32_t h[8];
-  uint32_t tot_len;
-  uint32_t len;
+  uint64_t tot_len;
+  size_t len;
   uint8_t block[2 * AVB_SHA256_BLOCK_SIZE];
   uint8_t buf[AVB_SHA256_DIGEST_SIZE]; /* Used for storing the final digest. */
 } AvbSHA256Ctx;
@@ -40,8 +40,8 @@
 /* Data structure used for SHA-512. */
 typedef struct {
   uint64_t h[8];
-  uint32_t tot_len;
-  uint32_t len;
+  uint64_t tot_len;
+  size_t len;
   uint8_t block[2 * AVB_SHA512_BLOCK_SIZE];
   uint8_t buf[AVB_SHA512_DIGEST_SIZE]; /* Used for storing the final digest. */
 } AvbSHA512Ctx;
@@ -50,7 +50,7 @@
 void avb_sha256_init(AvbSHA256Ctx* ctx);
 
 /* Updates the SHA-256 context with |len| bytes from |data|. */
-void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len);
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, size_t len);
 
 /* Returns the SHA-256 digest. */
 uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
@@ -59,7 +59,7 @@
 void avb_sha512_init(AvbSHA512Ctx* ctx);
 
 /* Updates the SHA-512 context with |len| bytes from |data|. */
-void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len);
+void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, size_t len);
 
 /* Returns the SHA-512 digest. */
 uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
diff --git a/lib/libavb/avb_sha256.c b/lib/libavb/avb_sha256.c
index d24c701..86ecca5 100644
--- a/lib/libavb/avb_sha256.c
+++ b/lib/libavb/avb_sha256.c
@@ -29,6 +29,18 @@
     *((str) + 0) = (uint8_t)((x) >> 24); \
   }
 
+#define UNPACK64(x, str)                         \
+  {                                              \
+    *((str) + 7) = (uint8_t)x;                   \
+    *((str) + 6) = (uint8_t)((uint64_t)x >> 8);  \
+    *((str) + 5) = (uint8_t)((uint64_t)x >> 16); \
+    *((str) + 4) = (uint8_t)((uint64_t)x >> 24); \
+    *((str) + 3) = (uint8_t)((uint64_t)x >> 32); \
+    *((str) + 2) = (uint8_t)((uint64_t)x >> 40); \
+    *((str) + 1) = (uint8_t)((uint64_t)x >> 48); \
+    *((str) + 0) = (uint8_t)((uint64_t)x >> 56); \
+  }
+
 #define PACK32(str, x)                                                    \
   {                                                                       \
     *(x) = ((uint32_t) * ((str) + 3)) | ((uint32_t) * ((str) + 2) << 8) | \
@@ -96,18 +108,18 @@
 
 static void SHA256_transform(AvbSHA256Ctx* ctx,
                              const uint8_t* message,
-                             unsigned int block_nb) {
+                             size_t block_nb) {
   uint32_t w[64];
   uint32_t wv[8];
   uint32_t t1, t2;
   const unsigned char* sub_block;
-  int i;
+  size_t i;
 
 #ifndef UNROLL_LOOPS
-  int j;
+  size_t j;
 #endif
 
-  for (i = 0; i < (int)block_nb; i++) {
+  for (i = 0; i < block_nb; i++) {
     sub_block = message + (i << 6);
 
 #ifndef UNROLL_LOOPS
@@ -293,9 +305,9 @@
   }
 }
 
-void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len) {
-  unsigned int block_nb;
-  unsigned int new_len, rem_len, tmp_len;
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, size_t len) {
+  size_t block_nb;
+  size_t new_len, rem_len, tmp_len;
   const uint8_t* shifted_data;
 
   tmp_len = AVB_SHA256_BLOCK_SIZE - ctx->len;
@@ -325,11 +337,11 @@
 }
 
 uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) {
-  unsigned int block_nb;
-  unsigned int pm_len;
-  unsigned int len_b;
+  size_t block_nb;
+  size_t pm_len;
+  uint64_t len_b;
 #ifndef UNROLL_LOOPS
-  int i;
+  size_t i;
 #endif
 
   block_nb =
@@ -340,7 +352,7 @@
 
   avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
   ctx->block[ctx->len] = 0x80;
-  UNPACK32(len_b, ctx->block + pm_len - 4);
+  UNPACK64(len_b, ctx->block + pm_len - 8);
 
   SHA256_transform(ctx, ctx->block, block_nb);
 
diff --git a/lib/libavb/avb_sha512.c b/lib/libavb/avb_sha512.c
index a5e7297..b19054f 100644
--- a/lib/libavb/avb_sha512.c
+++ b/lib/libavb/avb_sha512.c
@@ -127,14 +127,14 @@
 
 static void SHA512_transform(AvbSHA512Ctx* ctx,
                              const uint8_t* message,
-                             unsigned int block_nb) {
+                             size_t block_nb) {
   uint64_t w[80];
   uint64_t wv[8];
   uint64_t t1, t2;
   const uint8_t* sub_block;
-  int i, j;
+  size_t i, j;
 
-  for (i = 0; i < (int)block_nb; i++) {
+  for (i = 0; i < block_nb; i++) {
     sub_block = message + (i << 7);
 
 #ifdef UNROLL_LOOPS_SHA512
@@ -291,9 +291,9 @@
   }
 }
 
-void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len) {
-  unsigned int block_nb;
-  unsigned int new_len, rem_len, tmp_len;
+void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, size_t len) {
+  size_t block_nb;
+  size_t new_len, rem_len, tmp_len;
   const uint8_t* shifted_data;
 
   tmp_len = AVB_SHA512_BLOCK_SIZE - ctx->len;
@@ -323,12 +323,12 @@
 }
 
 uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) {
-  unsigned int block_nb;
-  unsigned int pm_len;
-  unsigned int len_b;
+  size_t block_nb;
+  size_t pm_len;
+  uint64_t len_b;
 
 #ifndef UNROLL_LOOPS_SHA512
-  int i;
+  size_t i;
 #endif
 
   block_nb =
@@ -339,7 +339,7 @@
 
   avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
   ctx->block[ctx->len] = 0x80;
-  UNPACK32(len_b, ctx->block + pm_len - 4);
+  UNPACK64(len_b, ctx->block + pm_len - 8);
 
   SHA512_transform(ctx, ctx->block, block_nb);
 
diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
index a941850..c0defdf 100644
--- a/lib/libavb/avb_slot_verify.c
+++ b/lib/libavb/avb_slot_verify.c
@@ -24,6 +24,14 @@
 /* Maximum size of a vbmeta image - 64 KiB. */
 #define VBMETA_MAX_SIZE (64 * 1024)
 
+static AvbSlotVerifyResult initialize_persistent_digest(
+    AvbOps* ops,
+    const char* part_name,
+    const char* persistent_value_name,
+    size_t digest_size,
+    const uint8_t* initial_digest,
+    uint8_t* out_digest);
+
 /* Helper function to see if we should continue with verification in
  * allow_verification_error=true mode if something goes wrong. See the
  * comments for the avb_slot_verify() function for more information.
@@ -114,9 +122,26 @@
   return AVB_SLOT_VERIFY_RESULT_OK;
 }
 
+/* Reads a persistent digest stored as a named persistent value corresponding to
+ * the given |part_name|. The value is returned in |out_digest| which must point
+ * to |expected_digest_size| bytes. If there is no digest stored for |part_name|
+ * it can be initialized by providing a non-NULL |initial_digest| of length
+ * |expected_digest_size|. This automatic initialization will only occur if the
+ * device is currently locked. The |initial_digest| may be NULL.
+ *
+ * Returns AVB_SLOT_VERIFY_RESULT_OK on success, otherwise returns an
+ * AVB_SLOT_VERIFY_RESULT_ERROR_* error code.
+ *
+ * If the value does not exist, is not supported, or is not populated, and
+ * |initial_digest| is NULL, returns
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA. If |expected_digest_size| does
+ * not match the stored digest size, also returns
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA.
+ */
 static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
                                                   const char* part_name,
                                                   size_t expected_digest_size,
+                                                  const uint8_t* initial_digest,
                                                   uint8_t* out_digest) {
   char* persistent_value_name = NULL;
   AvbIOResult io_ret = AVB_IO_RESULT_OK;
@@ -131,30 +156,106 @@
   if (persistent_value_name == NULL) {
     return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
   }
+
   io_ret = ops->read_persistent_value(ops,
                                       persistent_value_name,
                                       expected_digest_size,
                                       out_digest,
                                       &stored_digest_size);
+
+  // If no such named persistent value exists and an initial digest value was
+  // given, initialize the named persistent value with the given digest. If
+  // initialized successfully, this will recurse into this function but with a
+  // NULL initial_digest.
+  if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE && initial_digest) {
+    AvbSlotVerifyResult ret =
+        initialize_persistent_digest(ops,
+                                     part_name,
+                                     persistent_value_name,
+                                     expected_digest_size,
+                                     initial_digest,
+                                     out_digest);
+    avb_free(persistent_value_name);
+    return ret;
+  }
   avb_free(persistent_value_name);
+
   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
     return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
   } else if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE) {
+    // Treat a missing persistent value as a verification error, which is
+    // ignoreable, rather than a metadata error which is not.
     avb_errorv(part_name, ": Persistent digest does not exist.\n", NULL);
-    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
   } else if (io_ret == AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE ||
-             io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE ||
-             expected_digest_size != stored_digest_size) {
+             io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE) {
     avb_errorv(
         part_name, ": Persistent digest is not of expected size.\n", NULL);
     return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
   } else if (io_ret != AVB_IO_RESULT_OK) {
     avb_errorv(part_name, ": Error reading persistent digest.\n", NULL);
     return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+  } else if (expected_digest_size != stored_digest_size) {
+    avb_errorv(
+        part_name, ": Persistent digest is not of expected size.\n", NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
   }
   return AVB_SLOT_VERIFY_RESULT_OK;
 }
 
+static AvbSlotVerifyResult initialize_persistent_digest(
+    AvbOps* ops,
+    const char* part_name,
+    const char* persistent_value_name,
+    size_t digest_size,
+    const uint8_t* initial_digest,
+    uint8_t* out_digest) {
+  AvbSlotVerifyResult ret;
+  AvbIOResult io_ret = AVB_IO_RESULT_OK;
+  bool is_device_unlocked = true;
+
+  io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("Error getting device lock state.\n");
+    return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+  }
+
+  if (is_device_unlocked) {
+    avb_debugv(part_name,
+               ": Digest does not exist, device unlocked so not initializing "
+               "digest.\n",
+               NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+  }
+
+  // Device locked; initialize digest with given initial value.
+  avb_debugv(part_name,
+             ": Digest does not exist, initializing persistent digest.\n",
+             NULL);
+  io_ret = ops->write_persistent_value(
+      ops, persistent_value_name, digest_size, initial_digest);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_errorv(part_name, ": Error initializing persistent digest.\n", NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+  }
+
+  // To ensure that the digest value was written successfully - and avoid a
+  // scenario where the digest is simply 'initialized' on every verify - recurse
+  // into read_persistent_digest to read back the written value. The NULL
+  // initial_digest ensures that this will not recurse again.
+  ret = read_persistent_digest(ops, part_name, digest_size, NULL, out_digest);
+  if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+    avb_errorv(part_name,
+               ": Reading back initialized persistent digest failed!\n",
+               NULL);
+  }
+  return ret;
+}
+
 static AvbSlotVerifyResult load_and_verify_hash_partition(
     AvbOps* ops,
     const char* const* requested_partitions,
@@ -248,24 +349,16 @@
    */
   image_size = hash_desc.image_size;
   if (allow_verification_error) {
-    if (ops->get_size_of_partition == NULL) {
-      avb_errorv(part_name,
-                 ": The get_size_of_partition() operation is "
-                 "not implemented so we may not load the entire partition. "
-                 "Please implement.",
-                 NULL);
-    } else {
-      io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
-      if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
-        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-        goto out;
-      } else if (io_ret != AVB_IO_RESULT_OK) {
-        avb_errorv(part_name, ": Error determining partition size.\n", NULL);
-        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
-        goto out;
-      }
-      avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+    io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    } else if (io_ret != AVB_IO_RESULT_OK) {
+      avb_errorv(part_name, ": Error determining partition size.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      goto out;
     }
+    avb_debugv(part_name, ": Loading entire partition.\n", NULL);
   }
 
   ret = load_full_partition(
@@ -273,19 +366,27 @@
   if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
     goto out;
   }
-
+  // Although only one of the type might be used, we have to defined the
+  // structure here so that they would live outside the 'if/else' scope to be
+  // used later.
+  AvbSHA256Ctx sha256_ctx;
+  AvbSHA512Ctx sha512_ctx;
+  size_t image_size_to_hash = hash_desc.image_size;
+  // If we allow verification error and the whole partition is smaller than
+  // image size in hash descriptor, we just hash the whole partition.
+  if (image_size_to_hash > image_size) {
+    image_size_to_hash = image_size;
+  }
   if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
-    AvbSHA256Ctx sha256_ctx;
     avb_sha256_init(&sha256_ctx);
     avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
-    avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
+    avb_sha256_update(&sha256_ctx, image_buf, image_size_to_hash);
     digest = avb_sha256_final(&sha256_ctx);
     digest_len = AVB_SHA256_DIGEST_SIZE;
   } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
-    AvbSHA512Ctx sha512_ctx;
     avb_sha512_init(&sha512_ctx);
     avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
-    avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
+    avb_sha512_update(&sha512_ctx, image_buf, image_size_to_hash);
     digest = avb_sha512_final(&sha512_ctx);
     digest_len = AVB_SHA512_DIGEST_SIZE;
   } else {
@@ -295,18 +396,21 @@
   }
 
   if (hash_desc.digest_len == 0) {
-    // Expect a match to a persistent digest.
+    /* Expect a match to a persistent digest. */
     avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL);
     expected_digest_len = digest_len;
     expected_digest = expected_digest_buf;
     avb_assert(expected_digest_len <= sizeof(expected_digest_buf));
-    ret =
-        read_persistent_digest(ops, part_name, digest_len, expected_digest_buf);
+    /* Pass |digest| as the |initial_digest| so devices not yet initialized get
+     * initialized to the current partition digest.
+     */
+    ret = read_persistent_digest(
+        ops, part_name, digest_len, digest, expected_digest_buf);
     if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
       goto out;
     }
   } else {
-    // Expect a match to the digest in the descriptor.
+    /* Expect a match to the digest in the descriptor. */
     expected_digest_len = hash_desc.digest_len;
     expected_digest = desc_digest;
   }
@@ -365,12 +469,6 @@
   bool image_preloaded = false;
   size_t n;
 
-  if (ops->get_size_of_partition == NULL) {
-    avb_error("get_size_of_partition() not implemented.\n");
-    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
-    goto out;
-  }
-
   for (n = 0; requested_partitions[n] != NULL; n++) {
     char part_name[AVB_PART_NAME_MAX_SIZE];
     AvbIOResult io_ret;
@@ -441,6 +539,7 @@
     AvbOps* ops,
     const char* const* requested_partitions,
     const char* ab_suffix,
+    AvbSlotVerifyFlags flags,
     bool allow_verification_error,
     AvbVBMetaImageFlags toplevel_vbmeta_flags,
     int rollback_index_location,
@@ -467,7 +566,7 @@
   size_t num_descriptors;
   size_t n;
   bool is_main_vbmeta;
-  bool is_vbmeta_partition;
+  bool look_for_vbmeta_footer;
   AvbVBMetaData* vbmeta_image_data = NULL;
 
   ret = AVB_SLOT_VERIFY_RESULT_OK;
@@ -478,8 +577,20 @@
    * rollback_index_location to determine whether we're the main
    * vbmeta struct.
    */
+  is_main_vbmeta = false;
+  if (rollback_index_location == 0) {
+    if ((flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) == 0) {
+      is_main_vbmeta = true;
+    }
+  }
+
+  /* Don't use footers for vbmeta partitions ('vbmeta' or
+   * 'vbmeta_<partition_name>').
+   */
-  is_main_vbmeta = (rollback_index_location == 0);
-  is_vbmeta_partition = (avb_strcmp(partition_name, "vbmeta") == 0);
+  look_for_vbmeta_footer = true;
+  if (avb_strncmp(partition_name, "vbmeta", avb_strlen("vbmeta")) == 0) {
+    look_for_vbmeta_footer = false;
+  }
 
   if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
     avb_error("Partition name is not valid UTF-8.\n");
@@ -487,7 +598,7 @@
     goto out;
   }
 
-  /* Construct full partition name. */
+  /* Construct full partition name e.g. system_a. */
   if (!avb_str_concat(full_partition_name,
                       sizeof full_partition_name,
                       partition_name,
@@ -499,19 +610,15 @@
     goto out;
   }
 
-  avb_debugv("Loading vbmeta struct from partition '",
-             full_partition_name,
-             "'.\n",
-             NULL);
-
-  /* If we're loading from the main vbmeta partition, the vbmeta
-   * struct is in the beginning. Otherwise we have to locate it via a
-   * footer.
+  /* If we're loading from the main vbmeta partition, the vbmeta struct is in
+   * the beginning. Otherwise we may have to locate it via a footer... if no
+   * footer is found, we look in the beginning to support e.g. vbmeta_<org>
+   * partitions holding data for e.g. super partitions (b/80195851 for
+   * rationale).
    */
-  if (is_vbmeta_partition) {
-    vbmeta_offset = 0;
-    vbmeta_size = VBMETA_MAX_SIZE;
-  } else {
+  vbmeta_offset = 0;
+  vbmeta_size = VBMETA_MAX_SIZE;
+  if (look_for_vbmeta_footer) {
     uint8_t footer_buf[AVB_FOOTER_SIZE];
     size_t footer_num_read;
     AvbFooter footer;
@@ -534,21 +641,17 @@
 
     if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
                                           &footer)) {
-      avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
-      goto out;
-    }
-
-    /* Basic footer sanity check since the data is untrusted. */
-    if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
-      avb_errorv(
-          full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
-      goto out;
+      avb_debugv(full_partition_name, ": No footer detected.\n", NULL);
+    } else {
+      /* Basic footer sanity check since the data is untrusted. */
+      if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
+        avb_errorv(
+            full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
+      } else {
+        vbmeta_offset = footer.vbmeta_offset;
+        vbmeta_size = footer.vbmeta_size;
+      }
     }
-
-    vbmeta_offset = footer.vbmeta_offset;
-    vbmeta_size = footer.vbmeta_size;
   }
 
   vbmeta_buf = avb_malloc(vbmeta_size);
@@ -557,6 +660,18 @@
     goto out;
   }
 
+  if (vbmeta_offset != 0) {
+    avb_debugv("Loading vbmeta struct in footer from partition '",
+               full_partition_name,
+               "'.\n",
+               NULL);
+  } else {
+    avb_debugv("Loading vbmeta struct from partition '",
+               full_partition_name,
+               "'.\n",
+               NULL);
+  }
+
   io_ret = ops->read_from_partition(ops,
                                     full_partition_name,
                                     vbmeta_offset,
@@ -571,13 +686,14 @@
      * go try to get it from the boot partition instead.
      */
     if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
-        is_vbmeta_partition) {
+        !look_for_vbmeta_footer) {
       avb_debugv(full_partition_name,
                  ": No such partition. Trying 'boot' instead.\n",
                  NULL);
       ret = load_and_verify_vbmeta(ops,
                                    requested_partitions,
                                    ab_suffix,
+                                   flags,
                                    allow_verification_error,
                                    0 /* toplevel_vbmeta_flags */,
                                    0 /* rollback_index_location */,
@@ -655,6 +771,8 @@
     }
   }
 
+  uint32_t rollback_index_location_to_use = rollback_index_location;
+
   /* Check if key used to make signature matches what is expected. */
   if (pk_data != NULL) {
     if (expected_public_key != NULL) {
@@ -682,9 +800,27 @@
         pk_metadata_len = vbmeta_header.public_key_metadata_size;
       }
 
-      avb_assert(is_main_vbmeta);
-      io_ret = ops->validate_vbmeta_public_key(
-          ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted);
+      // If we're not using a vbmeta partition, need to use another AvbOps...
+      if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+        io_ret = ops->validate_public_key_for_partition(
+            ops,
+            full_partition_name,
+            pk_data,
+            pk_len,
+            pk_metadata,
+            pk_metadata_len,
+            &key_is_trusted,
+            &rollback_index_location_to_use);
+      } else {
+        avb_assert(is_main_vbmeta);
+        io_ret = ops->validate_vbmeta_public_key(ops,
+                                                 pk_data,
+                                                 pk_len,
+                                                 pk_metadata,
+                                                 pk_metadata_len,
+                                                 &key_is_trusted);
+      }
+
       if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
         ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
         goto out;
@@ -709,7 +845,7 @@
 
   /* Check rollback index. */
   io_ret = ops->read_rollback_index(
-      ops, rollback_index_location, &stored_rollback_index);
+      ops, rollback_index_location_to_use, &stored_rollback_index);
   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
     goto out;
@@ -735,7 +871,9 @@
   if (is_main_vbmeta) {
     avb_assert(slot_data->num_vbmeta_images == 0);
   } else {
-    avb_assert(slot_data->num_vbmeta_images > 0);
+    if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
+      avb_assert(slot_data->num_vbmeta_images > 0);
+    }
   }
   if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
     avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
@@ -859,6 +997,7 @@
             load_and_verify_vbmeta(ops,
                                    requested_partitions,
                                    ab_suffix,
+                                   flags,
                                    allow_verification_error,
                                    toplevel_vbmeta_flags,
                                    chain_desc.rollback_index_location,
@@ -1019,7 +1158,11 @@
             goto out;
           }
 
-          ret = read_persistent_digest(ops, part_name, digest_len, digest_buf);
+          ret = read_persistent_digest(ops,
+                                       part_name,
+                                       digest_len,
+                                       NULL /* initial_digest */,
+                                       digest_buf);
           if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
             goto out;
           }
@@ -1043,7 +1186,8 @@
     }
   }
 
-  if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
+  if (rollback_index_location < 0 ||
+      rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
     avb_errorv(
         full_partition_name, ": Invalid rollback_index_location.\n", NULL);
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
@@ -1072,13 +1216,137 @@
   return ret;
 }
 
+static AvbIOResult avb_manage_hashtree_error_mode(
+    AvbOps* ops,
+    AvbSlotVerifyFlags flags,
+    AvbSlotVerifyData* data,
+    AvbHashtreeErrorMode* out_hashtree_error_mode) {
+  AvbHashtreeErrorMode ret = AVB_HASHTREE_ERROR_MODE_RESTART;
+  AvbIOResult io_ret = AVB_IO_RESULT_OK;
+  uint8_t vbmeta_digest_sha256[AVB_SHA256_DIGEST_SIZE];
+  uint8_t stored_vbmeta_digest_sha256[AVB_SHA256_DIGEST_SIZE];
+  size_t num_bytes_read;
+
+  avb_assert(out_hashtree_error_mode != NULL);
+  avb_assert(ops->read_persistent_value != NULL);
+  avb_assert(ops->write_persistent_value != NULL);
+
+  // If we're rebooting because of dm-verity corruption, make a note of
+  // the vbmeta hash so we can stay in 'eio' mode until things change.
+  if (flags & AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION) {
+    avb_debug(
+        "Rebooting because of dm-verity corruption - "
+        "recording OS instance and using 'eio' mode.\n");
+    avb_slot_verify_data_calculate_vbmeta_digest(
+        data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest_sha256);
+    io_ret = ops->write_persistent_value(ops,
+                                         AVB_NPV_MANAGED_VERITY_MODE,
+                                         AVB_SHA256_DIGEST_SIZE,
+                                         vbmeta_digest_sha256);
+    if (io_ret != AVB_IO_RESULT_OK) {
+      avb_error("Error writing to " AVB_NPV_MANAGED_VERITY_MODE ".\n");
+      goto out;
+    }
+    ret = AVB_HASHTREE_ERROR_MODE_EIO;
+    io_ret = AVB_IO_RESULT_OK;
+    goto out;
+  }
+
+  // See if we're in 'eio' mode.
+  io_ret = ops->read_persistent_value(ops,
+                                      AVB_NPV_MANAGED_VERITY_MODE,
+                                      AVB_SHA256_DIGEST_SIZE,
+                                      stored_vbmeta_digest_sha256,
+                                      &num_bytes_read);
+  if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE ||
+      (io_ret == AVB_IO_RESULT_OK && num_bytes_read == 0)) {
+    // This is the usual case ('eio' mode not set).
+    avb_debug("No dm-verity corruption - using in 'restart' mode.\n");
+    ret = AVB_HASHTREE_ERROR_MODE_RESTART;
+    io_ret = AVB_IO_RESULT_OK;
+    goto out;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("Error reading from " AVB_NPV_MANAGED_VERITY_MODE ".\n");
+    goto out;
+  }
+  if (num_bytes_read != AVB_SHA256_DIGEST_SIZE) {
+    avb_error(
+        "Unexpected number of bytes read from " AVB_NPV_MANAGED_VERITY_MODE
+        ".\n");
+    io_ret = AVB_IO_RESULT_ERROR_IO;
+    goto out;
+  }
+
+  // OK, so we're currently in 'eio' mode and the vbmeta digest of the OS
+  // that caused this is in |stored_vbmeta_digest_sha256| ... now see if
+  // the OS we're dealing with now is the same.
+  avb_slot_verify_data_calculate_vbmeta_digest(
+      data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest_sha256);
+  if (avb_memcmp(vbmeta_digest_sha256,
+                 stored_vbmeta_digest_sha256,
+                 AVB_SHA256_DIGEST_SIZE) == 0) {
+    // It's the same so we're still in 'eio' mode.
+    avb_debug("Same OS instance detected - staying in 'eio' mode.\n");
+    ret = AVB_HASHTREE_ERROR_MODE_EIO;
+    io_ret = AVB_IO_RESULT_OK;
+  } else {
+    // It did change!
+    avb_debug(
+        "New OS instance detected - changing from 'eio' to 'restart' mode.\n");
+    io_ret =
+        ops->write_persistent_value(ops,
+                                    AVB_NPV_MANAGED_VERITY_MODE,
+                                    0,  // This clears the persistent property.
+                                    vbmeta_digest_sha256);
+    if (io_ret != AVB_IO_RESULT_OK) {
+      avb_error("Error clearing " AVB_NPV_MANAGED_VERITY_MODE ".\n");
+      goto out;
+    }
+    ret = AVB_HASHTREE_ERROR_MODE_RESTART;
+    io_ret = AVB_IO_RESULT_OK;
+  }
+
+out:
+  *out_hashtree_error_mode = ret;
+  return io_ret;
+}
+
+static bool has_system_partition(AvbOps* ops, const char* ab_suffix) {
+  char part_name[AVB_PART_NAME_MAX_SIZE];
+  char* system_part_name = "system";
+  char guid_buf[37];
+  AvbIOResult io_ret;
+
+  if (!avb_str_concat(part_name,
+                      sizeof part_name,
+                      system_part_name,
+                      avb_strlen(system_part_name),
+                      ab_suffix,
+                      avb_strlen(ab_suffix))) {
+    avb_error("System partition name and suffix does not fit.\n");
+    return false;
+  }
+
+  io_ret = ops->get_unique_guid_for_partition(
+      ops, part_name, guid_buf, sizeof guid_buf);
+  if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
+    avb_debug("No system partition.\n");
+    return false;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("Error getting unique GUID for system partition.\n");
+    return false;
+  }
+
+  return true;
+}
+
 AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
                                     const char* const* requested_partitions,
                                     const char* ab_suffix,
                                     AvbSlotVerifyFlags flags,
                                     AvbHashtreeErrorMode hashtree_error_mode,
                                     AvbSlotVerifyData** out_data) {
-  AvbSlotVerifyResult ret;
+  AvbSlotVerifyResult ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
   AvbSlotVerifyData* slot_data = NULL;
   AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
   bool using_boot_for_vbmeta = false;
@@ -1087,14 +1355,10 @@
       (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
   AvbCmdlineSubstList* additional_cmdline_subst = NULL;
 
-  /* Fail early if we're missing the AvbOps needed for slot verification.
-   *
-   * For now, handle get_size_of_partition() not being implemented. In
-   * a later release we may change that.
-   */
+  /* Fail early if we're missing the AvbOps needed for slot verification. */
   avb_assert(ops->read_is_device_unlocked != NULL);
   avb_assert(ops->read_from_partition != NULL);
-  avb_assert(ops->validate_vbmeta_public_key != NULL);
+  avb_assert(ops->get_size_of_partition != NULL);
   avb_assert(ops->read_rollback_index != NULL);
   avb_assert(ops->get_unique_guid_for_partition != NULL);
 
@@ -1112,6 +1376,36 @@
     goto fail;
   }
 
+  /* Make sure passed-in AvbOps support persistent values if
+   * asking for libavb to manage verity state.
+   */
+  if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
+    if (ops->read_persistent_value == NULL ||
+        ops->write_persistent_value == NULL) {
+      avb_error(
+          "Persistent values required for "
+          "AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO "
+          "but are not implemented in given AvbOps.\n");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+      goto fail;
+    }
+  }
+
+  /* Make sure passed-in AvbOps support verifying public keys and getting
+   * rollback index location if not using a vbmeta partition.
+   */
+  if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+    if (ops->validate_public_key_for_partition == NULL) {
+      avb_error(
+          "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION was passed but the "
+          "validate_public_key_for_partition() operation isn't implemented.\n");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+      goto fail;
+    }
+  } else {
+    avb_assert(ops->validate_vbmeta_public_key != NULL);
+  }
+
   slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
   if (slot_data == NULL) {
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
@@ -1136,99 +1430,163 @@
     goto fail;
   }
 
+  if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+    if (requested_partitions == NULL || requested_partitions[0] == NULL) {
+      avb_fatal(
+          "Requested partitions cannot be empty when using "
+          "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+      goto fail;
+    }
+
+    /* No vbmeta partition, go through each of the requested partitions... */
+    for (size_t n = 0; requested_partitions[n] != NULL; n++) {
+      ret = load_and_verify_vbmeta(ops,
+                                   requested_partitions,
+                                   ab_suffix,
+                                   flags,
+                                   allow_verification_error,
+                                   0 /* toplevel_vbmeta_flags */,
+                                   0 /* rollback_index_location */,
+                                   requested_partitions[n],
+                                   avb_strlen(requested_partitions[n]),
+                                   NULL /* expected_public_key */,
+                                   0 /* expected_public_key_length */,
+                                   slot_data,
+                                   &algorithm_type,
+                                   additional_cmdline_subst);
+      if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+        goto fail;
+      }
+    }
+
+  } else {
+    /* Usual path, load "vbmeta"... */
+    ret = load_and_verify_vbmeta(ops,
+                                 requested_partitions,
+                                 ab_suffix,
+                                 flags,
+                                 allow_verification_error,
+                                 0 /* toplevel_vbmeta_flags */,
+                                 0 /* rollback_index_location */,
+                                 "vbmeta",
+                                 avb_strlen("vbmeta"),
+                                 NULL /* expected_public_key */,
+                                 0 /* expected_public_key_length */,
+                                 slot_data,
+                                 &algorithm_type,
+                                 additional_cmdline_subst);
+    if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+      goto fail;
+    }
+  }
+
-  ret = load_and_verify_vbmeta(ops,
-                               requested_partitions,
-                               ab_suffix,
-                               allow_verification_error,
-                               0 /* toplevel_vbmeta_flags */,
-                               0 /* rollback_index_location */,
-                               "vbmeta",
-                               avb_strlen("vbmeta"),
-                               NULL /* expected_public_key */,
-                               0 /* expected_public_key_length */,
-                               slot_data,
-                               &algorithm_type,
-                               additional_cmdline_subst);
-  if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+  if (!result_should_continue(ret)) {
     goto fail;
   }
 
   /* If things check out, mangle the kernel command-line as needed. */
-  if (result_should_continue(ret)) {
+  if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
     if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
       avb_assert(
           avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0);
       using_boot_for_vbmeta = true;
     }
+  }
 
-    /* Byteswap top-level vbmeta header since we'll need it below. */
-    avb_vbmeta_image_header_to_host_byte_order(
-        (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
-        &toplevel_vbmeta);
+  /* Byteswap top-level vbmeta header since we'll need it below. */
+  avb_vbmeta_image_header_to_host_byte_order(
+      (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
+      &toplevel_vbmeta);
 
-    /* Fill in |ab_suffix| field. */
-    slot_data->ab_suffix = avb_strdup(ab_suffix);
-    if (slot_data->ab_suffix == NULL) {
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-      goto fail;
-    }
+  /* Fill in |ab_suffix| field. */
+  slot_data->ab_suffix = avb_strdup(ab_suffix);
+  if (slot_data->ab_suffix == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto fail;
+  }
 
-    /* If verification is disabled, we are done ... we specifically
-     * don't want to add any androidboot.* options since verification
-     * is disabled.
+  /* If verification is disabled, we are done ... we specifically
+   * don't want to add any androidboot.* options since verification
+   * is disabled.
+   */
+  if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+    /* Since verification is disabled we didn't process any
+     * descriptors and thus there's no cmdline... so set root= such
+     * that the system partition is mounted.
      */
-    if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
-      /* Since verification is disabled we didn't process any
-       * descriptors and thus there's no cmdline... so set root= such
-       * that the system partition is mounted.
-       */
-      avb_assert(slot_data->cmdline == NULL);
+    avb_assert(slot_data->cmdline == NULL);
+    // Devices with dynamic partitions won't have system partition.
+    // Instead, it has a large super partition to accommodate *.img files.
+    // See b/119551429 for details.
+    if (has_system_partition(ops, ab_suffix)) {
       slot_data->cmdline =
           avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
-      if (slot_data->cmdline == NULL) {
-        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-        goto fail;
-      }
     } else {
-      /* Add options - any failure in avb_append_options() is either an
-       * I/O or OOM error.
-       */
-      AvbSlotVerifyResult sub_ret = avb_append_options(ops,
-                                                       slot_data,
-                                                       &toplevel_vbmeta,
-                                                       algorithm_type,
-                                                       hashtree_error_mode);
-      if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
-        ret = sub_ret;
-        goto fail;
-      }
+      // The |cmdline| field should be a NUL-terminated string.
+      slot_data->cmdline = avb_strdup("");
     }
-
-    /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
-    if (slot_data->cmdline != NULL) {
-      char* new_cmdline;
-      new_cmdline = avb_sub_cmdline(ops,
-                                    slot_data->cmdline,
-                                    ab_suffix,
-                                    using_boot_for_vbmeta,
-                                    additional_cmdline_subst);
-      if (new_cmdline != slot_data->cmdline) {
-        if (new_cmdline == NULL) {
+    if (slot_data->cmdline == NULL) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto fail;
+    }
+  } else {
+    /* If requested, manage dm-verity mode... */
+    AvbHashtreeErrorMode resolved_hashtree_error_mode = hashtree_error_mode;
+    if (hashtree_error_mode ==
+        AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
+      AvbIOResult io_ret;
+      io_ret = avb_manage_hashtree_error_mode(
+          ops, flags, slot_data, &resolved_hashtree_error_mode);
+      if (io_ret != AVB_IO_RESULT_OK) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+        if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
           ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-          goto fail;
         }
-        avb_free(slot_data->cmdline);
-        slot_data->cmdline = new_cmdline;
+        goto fail;
       }
     }
+    slot_data->resolved_hashtree_error_mode = resolved_hashtree_error_mode;
 
-    if (out_data != NULL) {
-      *out_data = slot_data;
-    } else {
-      avb_slot_verify_data_free(slot_data);
+    /* Add options... */
+    AvbSlotVerifyResult sub_ret;
+    sub_ret = avb_append_options(ops,
+                                 flags,
+                                 slot_data,
+                                 &toplevel_vbmeta,
+                                 algorithm_type,
+                                 hashtree_error_mode,
+                                 resolved_hashtree_error_mode);
+    if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+      ret = sub_ret;
+      goto fail;
+    }
+  }
+
+  /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
+  if (slot_data->cmdline != NULL && avb_strlen(slot_data->cmdline) != 0) {
+    char* new_cmdline;
+    new_cmdline = avb_sub_cmdline(ops,
+                                  slot_data->cmdline,
+                                  ab_suffix,
+                                  using_boot_for_vbmeta,
+                                  additional_cmdline_subst);
+    if (new_cmdline != slot_data->cmdline) {
+      if (new_cmdline == NULL) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto fail;
+      }
+      avb_free(slot_data->cmdline);
+      slot_data->cmdline = new_cmdline;
     }
   }
 
+  if (out_data != NULL) {
+    *out_data = slot_data;
+  } else {
+    avb_slot_verify_data_free(slot_data);
+  }
+
   avb_free_cmdline_subst_list(additional_cmdline_subst);
   additional_cmdline_subst = NULL;
 
diff --git a/lib/libavb/avb_slot_verify.h b/lib/libavb/avb_slot_verify.h
index 73fd70d..8d0fa53 100644
--- a/lib/libavb/avb_slot_verify.h
+++ b/lib/libavb/avb_slot_verify.h
@@ -51,12 +51,25 @@
  * be used ONLY for diagnostics and debugging. It cannot be used
  * unless AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is also
  * used.
+ *
+ * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO means that either
+ * AVB_HASHTREE_ERROR_MODE_RESTART or AVB_HASHTREE_ERROR_MODE_EIO is used
+ * depending on state. This mode implements a state machine whereby
+ * AVB_HASHTREE_ERROR_MODE_RESTART is used by default and when
+ * AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION is passed the
+ * mode transitions to AVB_HASHTREE_ERROR_MODE_EIO. When a new OS has been
+ * detected the device transitions back to the AVB_HASHTREE_ERROR_MODE_RESTART
+ * mode. To do this persistent storage is needed - specifically this means that
+ * the passed in AvbOps will need to have the read_persistent_value() and
+ * write_persistent_value() operations implemented. The name of the persistent
+ * value used is "avb.managed_verity_mode" and 32 bytes of storage is needed.
  */
 typedef enum {
   AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
   AVB_HASHTREE_ERROR_MODE_RESTART,
   AVB_HASHTREE_ERROR_MODE_EIO,
-  AVB_HASHTREE_ERROR_MODE_LOGGING
+  AVB_HASHTREE_ERROR_MODE_LOGGING,
+  AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO
 } AvbHashtreeErrorMode;
 
 /* Flags that influence how avb_slot_verify() works.
@@ -80,10 +93,26 @@
  * contents loaded from |requested_partition| will be the contents of
  * the entire partition instead of just the size specified in the hash
  * descriptor.
+ *
+ * The AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION flag
+ * should be set if using AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO
+ * and the reason the boot loader is running is because the device
+ * was restarted by the dm-verity driver.
+ *
+ * If the AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION flag is set then
+ * data won't be loaded from the "vbmeta" partition and the
+ * |validate_vbmeta_public_key| operation is never called. Instead, the
+ * vbmeta structs in |requested_partitions| are loaded and processed and the
+ * |validate_public_key_for_partition| operation is called for each of these
+ * vbmeta structs. This flag is useful when booting into recovery on a device
+ * not using A/B - see section "Booting into recovery" in README.md for
+ * more information.
  */
 typedef enum {
   AVB_SLOT_VERIFY_FLAGS_NONE = 0,
-  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0)
+  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0),
+  AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION = (1 << 1),
+  AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION = (1 << 2),
 } AvbSlotVerifyFlags;
 
 /* Get a textual representation of |result|. */
@@ -188,6 +217,10 @@
  *   set to AVB_HASHTREE_ERROR_MODE_EIO, and 'logging' if it's set to
  *   AVB_HASHTREE_ERROR_MODE_LOGGING.
  *
+ *   androidboot.veritymode.managed: This is set to 'yes' only
+ *   if hashtree validation isn't disabled and the passed-in hashtree
+ *   error mode is AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO.
+ *
  *   androidboot.vbmeta.invalidate_on_error: This is set to 'yes' only
  *   if hashtree validation isn't disabled and the passed-in hashtree
  *   error mode is AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE.
@@ -203,7 +236,9 @@
  *   PARTUUID=$(ANDROID_VBMETA_PARTUUID) before substitution so it
  *   will end up pointing to the vbmeta partition for the verified
  *   slot. If there is no vbmeta partition it will point to the boot
- *   partition of the verified slot.
+ *   partition of the verified slot. If the flag
+ *   AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is used, this is not
+ *   set.
  *
  *   androidboot.vbmeta.avb_version: This is set to the decimal value
  *   of AVB_VERSION_MAJOR followed by a dot followed by the decimal
@@ -228,6 +263,15 @@
  * appropriate system partition is substituted in. Note that none of
  * the androidboot.* options mentioned above will be set.
  *
+ * The |resolved_hashtree_error_mode| is the the value of the passed
+ * avb_slot_verify()'s |hashtree_error_mode| parameter except that it never has
+ * the value AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO. If this value was
+ * passed in, then the restart/eio state machine is used resulting in
+ * |resolved_hashtree_error_mode| being set to either
+ * AVB_HASHTREE_ERROR_MODE_RESTART or AVB_HASHTREE_ERROR_MODE_EIO.  If set to
+ * AVB_HASHTREE_ERROR_MODE_EIO the boot loader should present a RED warning
+ * screen for the user to click through before continuing to boot.
+ *
  * This struct may grow in the future without it being considered an
  * ABI break.
  */
@@ -239,6 +283,7 @@
   size_t num_loaded_partitions;
   char* cmdline;
   uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
+  AvbHashtreeErrorMode resolved_hashtree_error_mode;
 } AvbSlotVerifyData;
 
 /* Calculates a digest of all vbmeta images in |data| using
@@ -282,12 +327,8 @@
  * ignore verification errors which is something needed in the
  * UNLOCKED state. See the AvbSlotVerifyFlags enumeration for details.
  *
- * The |hashtree_error_mode| parameter should be set to the desired
- * error handling mode when hashtree validation fails inside the
- * HLOS. This value isn't used by libavb per se - it is forwarded to
- * the HLOS through the androidboot.veritymode and
- * androidboot.vbmeta.invalidate_on_error cmdline parameters. See the
- * AvbHashtreeErrorMode enumeration for details.
+ * The |hashtree_error_mode| parameter should be set to the desired error
+ * handling mode. See the AvbHashtreeErrorMode enumeration for details.
  *
  * Also note that |out_data| is never set if
  * AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO,
diff --git a/lib/libavb/avb_sysdeps.h b/lib/libavb/avb_sysdeps.h
index f032de4..f52428c 100644
--- a/lib/libavb/avb_sysdeps.h
+++ b/lib/libavb/avb_sysdeps.h
@@ -53,6 +53,14 @@
  */
 int avb_strcmp(const char* s1, const char* s2);
 
+/* Compare |n| bytes in two strings.
+ *
+ * Return an integer less than, equal to, or greater than zero if the
+ * first |n| bytes of |s1| is found, respectively, to be less than,
+ * to match, or be greater than the first |n| bytes of |s2|.
+ */
+int avb_strncmp(const char* s1, const char* s2, size_t n);
+
 /* Copy |n| bytes from |src| to |dest|. */
 void* avb_memcpy(void* dest, const void* src, size_t n);
 
diff --git a/lib/libavb/avb_sysdeps_posix.c b/lib/libavb/avb_sysdeps_posix.c
index e9addc1..4ccf41e 100644
--- a/lib/libavb/avb_sysdeps_posix.c
+++ b/lib/libavb/avb_sysdeps_posix.c
@@ -24,14 +24,12 @@
   return strcmp(s1, s2);
 }
 
-size_t avb_strlen(const char* str) {
-  return strlen(str);
+int avb_strncmp(const char* s1, const char* s2, size_t n) {
+  return strncmp(s1, s2, n);
 }
 
-uint32_t avb_div_by_10(uint64_t* dividend) {
-  uint32_t rem = (uint32_t)(*dividend % 10);
-  *dividend /= 10;
-  return rem;
+size_t avb_strlen(const char* str) {
+  return strlen(str);
 }
 
 void avb_abort(void) {
@@ -60,3 +58,9 @@
 void avb_free(void* ptr) {
   free(ptr);
 }
+
+uint32_t avb_div_by_10(uint64_t* dividend) {
+  uint32_t rem = (uint32_t)(*dividend % 10);
+  *dividend /= 10;
+  return rem;
+}
diff --git a/lib/libavb/avb_vbmeta_image.c b/lib/libavb/avb_vbmeta_image.c
index a7e2322..384f5ac 100644
--- a/lib/libavb/avb_vbmeta_image.c
+++ b/lib/libavb/avb_vbmeta_image.c
@@ -35,17 +35,18 @@
     *out_public_key_length = 0;
   }
 
+  /* Before we byteswap or compare Magic, ensure length is long enough. */
+  if (length < sizeof(AvbVBMetaImageHeader)) {
+    avb_error("Length is smaller than header.\n");
+    goto out;
+  }
+
   /* Ensure magic is correct. */
   if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
     avb_error("Magic is incorrect.\n");
     goto out;
   }
 
-  /* Before we byteswap, ensure length is long enough. */
-  if (length < sizeof(AvbVBMetaImageHeader)) {
-    avb_error("Length is smaller than header.\n");
-    goto out;
-  }
   avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data,
                                              &h);
 
diff --git a/lib/linux_compat.c b/lib/linux_compat.c
index 6373b44..81ea8fb 100644
--- a/lib/linux_compat.c
+++ b/lib/linux_compat.c
@@ -20,7 +20,7 @@
 	void *p;
 
 	p = malloc_cache_aligned(size);
-	if (flags & __GFP_ZERO)
+	if (p && flags & __GFP_ZERO)
 		memset(p, 0, size);
 
 	return p;
diff --git a/lib/time.c b/lib/time.c
index f5751ab..f30fc05 100644
--- a/lib/time.c
+++ b/lib/time.c
@@ -134,6 +134,20 @@
 	return tick_to_time(get_ticks()) - base;
 }
 
+static uint64_t notrace tick_to_time_us(uint64_t tick)
+{
+	ulong div = get_tbclk() / 1000;
+
+	tick *= CONFIG_SYS_HZ;
+	do_div(tick, div);
+	return tick;
+}
+
+uint64_t __weak get_timer_us(uint64_t base)
+{
+	return tick_to_time_us(get_ticks()) - base;
+}
+
 unsigned long __weak notrace timer_get_us(void)
 {
 	return tick_to_time(get_ticks() * 1000);
diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c
index ebef92f..1138c70 100644
--- a/lib/tiny-printf.c
+++ b/lib/tiny-printf.c
@@ -157,7 +157,8 @@
  *       decimal).
  */
 
-static void pointer(struct printf_info *info, const char *fmt, void *ptr)
+static void __maybe_unused pointer(struct printf_info *info, const char *fmt,
+				   void *ptr)
 {
 #ifdef DEBUG
 	unsigned long num = (uintptr_t)ptr;
@@ -266,6 +267,21 @@
 						div_out(info, &num, div);
 				}
 				break;
+			case 'p':
+#ifdef DEBUG
+				pointer(info, fmt, va_arg(va, void *));
+				/*
+				 * Skip this because it pulls in _ctype which is
+				 * 256 bytes, and we don't generally implement
+				 * pointer anyway
+				 */
+				while (isalnum(fmt[0]))
+					fmt++;
+				break;
+#else
+				islong = true;
+				/* no break */
+#endif
 			case 'x':
 				if (islong) {
 					num = va_arg(va, unsigned long);
@@ -287,11 +303,6 @@
 			case 's':
 				p = va_arg(va, char*);
 				break;
-			case 'p':
-				pointer(info, fmt, va_arg(va, void *));
-				while (isalnum(fmt[0]))
-					fmt++;
-				break;
 			case '%':
 				out(info, '%');
 			default:
@@ -365,6 +376,22 @@
 
 	return ret;
 }
+
+#if CONFIG_IS_ENABLED(LOG)
+/* Note that size is ignored */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list va)
+{
+	struct printf_info info;
+	int ret;
+
+	info.outstr = buf;
+	info.putc = putc_outstr;
+	ret = _vprintf(&info, fmt, va);
+	*info.outstr = '\0';
+
+	return ret;
+}
+#endif
 
 /* Note that size is ignored */
 int snprintf(char *buf, size_t size, const char *fmt, ...)
@@ -382,3 +409,9 @@
 
 	return ret;
 }
+
+void print_grouped_ull(unsigned long long int_val, int digits)
+{
+	/* Don't try to print the upper 32-bits */
+	printf("%ld ", (ulong)int_val);
+}
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 373094e..6fcc66a 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1,9 +1,11 @@
 #!/usr/bin/env perl
+# SPDX-License-Identifier: GPL-2.0
+#
 # (c) 2001, Dave Jones. (the file handling bit)
 # (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
 # (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
 # (c) 2008-2010 Andy Whitcroft <apw@canonical.com>
-# Licensed under the terms of the GNU GPL License version 2
+# (c) 2010-2018 Joe Perches <joe@perches.com>
 
 use strict;
 use warnings;
@@ -11,6 +13,7 @@
 use File::Basename;
 use Cwd 'abs_path';
 use Term::ANSIColor qw(:constants);
+use Encode qw(decode encode);
 
 my $P = $0;
 my $D = dirname(abs_path($P));
@@ -58,7 +61,9 @@
 my $conststructsfile = "$D/const_structs.checkpatch";
 my $typedefsfile = "";
 my $color = "auto";
-my $allow_c99_comments = 1;
+my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE
+# git output parsing needs US English output, so first set backtick child process LANGUAGE
+my $git_command ='export LANGUAGE=en_US.UTF-8; git';
 
 sub help {
 	my ($exitcode) = @_;
@@ -238,11 +243,11 @@
 
 my $exit = 0;
 
+my $perl_version_ok = 1;
 if ($^V && $^V lt $minimum_perl_version) {
+	$perl_version_ok = 0;
 	printf "$P: requires at least perl version %vd\n", $minimum_perl_version;
-	if (!$ignore_perl_version) {
-		exit(1);
-	}
+	exit(1) if (!$ignore_perl_version);
 }
 
 #if no filenames are given, push '-' to read patch from stdin
@@ -344,9 +349,10 @@
 			__force|
 			__iomem|
 			__must_check|
-			__init_refok|
 			__kprobes|
 			__ref|
+			__refconst|
+			__refdata|
 			__rcu|
 			__private
 		}x;
@@ -376,6 +382,7 @@
 			__noclone|
 			__deprecated|
 			__read_mostly|
+			__ro_after_init|
 			__kprobes|
 			$InitAttribute|
 			____cacheline_aligned|
@@ -461,8 +468,19 @@
 	seq_vprintf|seq_printf|seq_puts
 )};
 
+our $allocFunctions = qr{(?x:
+	(?:(?:devm_)?
+		(?:kv|k|v)[czm]alloc(?:_node|_array)? |
+		kstrdup(?:_const)? |
+		kmemdup(?:_nul)?) |
+	(?:\w+)?alloc_skb(?:ip_align)? |
+				# dev_alloc_skb/netdev_alloc_skb, et al
+	dma_alloc_coherent
+)};
+
 our $signature_tags = qr{(?xi:
 	Signed-off-by:|
+	Co-developed-by:|
 	Acked-by:|
 	Tested-by:|
 	Reviewed-by:|
@@ -568,6 +586,27 @@
 }
 $mode_perms_search = "(?:${mode_perms_search})";
 
+our %deprecated_apis = (
+	"synchronize_rcu_bh"			=> "synchronize_rcu",
+	"synchronize_rcu_bh_expedited"		=> "synchronize_rcu_expedited",
+	"call_rcu_bh"				=> "call_rcu",
+	"rcu_barrier_bh"			=> "rcu_barrier",
+	"synchronize_sched"			=> "synchronize_rcu",
+	"synchronize_sched_expedited"		=> "synchronize_rcu_expedited",
+	"call_rcu_sched"			=> "call_rcu",
+	"rcu_barrier_sched"			=> "rcu_barrier",
+	"get_state_synchronize_sched"		=> "get_state_synchronize_rcu",
+	"cond_synchronize_sched"		=> "cond_synchronize_rcu",
+);
+
+#Create a search pattern for all these strings to speed up a loop below
+our $deprecated_apis_search = "";
+foreach my $entry (keys %deprecated_apis) {
+	$deprecated_apis_search .= '|' if ($deprecated_apis_search ne "");
+	$deprecated_apis_search .= $entry;
+}
+$deprecated_apis_search = "(?:${deprecated_apis_search})";
+
 our $mode_perms_world_writable = qr{
 	S_IWUGO		|
 	S_IWOTH		|
@@ -845,6 +884,17 @@
 	return $status =~ /obsolete/i;
 }
 
+sub is_SPDX_License_valid {
+	my ($license) = @_;
+
+	return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$root/.git"));
+
+	my $root_path = abs_path($root);
+	my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`;
+	return 0 if ($status ne "");
+	return 1;
+}
+
 my $camelcase_seeded = 0;
 sub seed_camelcase_includes {
 	return if ($camelcase_seeded);
@@ -856,7 +906,7 @@
 	$camelcase_seeded = 1;
 
 	if (-e ".git") {
-		my $git_last_include_commit = `git log --no-merges --pretty=format:"%h%n" -1 -- include`;
+		my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`;
 		chomp $git_last_include_commit;
 		$camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit";
 	} else {
@@ -884,7 +934,7 @@
 	}
 
 	if (-e ".git") {
-		$files = `git ls-files "include/*.h"`;
+		$files = `${git_command} ls-files "include/*.h"`;
 		@include_files = split('\n', $files);
 	}
 
@@ -908,13 +958,13 @@
 
 	return ($id, $desc) if ((which("git") eq "") || !(-e ".git"));
 
-	my $output = `git log --no-color --format='%H %s' -1 $commit 2>&1`;
+	my $output = `${git_command} log --no-color --format='%H %s' -1 $commit 2>&1`;
 	$output =~ s/^\s*//gm;
 	my @lines = split("\n", $output);
 
 	return ($id, $desc) if ($#lines < 0);
 
-	if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous\./) {
+	if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous/) {
 # Maybe one day convert this block of bash into something that returns
 # all matching commit ids, but it's very slow...
 #
@@ -958,7 +1008,7 @@
 		} else {
 			$git_range = "-1 $commit_expr";
 		}
-		my $lines = `git log --no-color --no-merges --pretty=format:'%H %s' $git_range`;
+		my $lines = `${git_command} log --no-color --no-merges --pretty=format:'%H %s' $git_range`;
 		foreach my $line (split(/\n/, $lines)) {
 			$line =~ /^([0-9a-fA-F]{40,40}) (.*)$/;
 			next if (!defined($1) || !defined($2));
@@ -973,6 +1023,7 @@
 }
 
 my $vname;
+$allow_c99_comments = !defined $ignore_type{"C99_COMMENT_TOLERANCE"};
 for my $filename (@ARGV) {
 	my $FILE;
 	if ($git) {
@@ -1024,11 +1075,11 @@
 	hash_show_words(\%use_type, "Used");
 	hash_show_words(\%ignore_type, "Ignored");
 
-	if ($^V lt 5.10.0) {
+	if (!$perl_version_ok) {
 		print << "EOM"
 
 NOTE: perl $^V is not modern enough to detect all possible issues.
-      An upgrade to at least perl v5.10.0 is suggested.
+      An upgrade to at least perl $minimum_perl_version is suggested.
 EOM
 	}
 	if ($exit) {
@@ -2233,10 +2284,14 @@
 
 	our $clean = 1;
 	my $signoff = 0;
+	my $author = '';
+	my $authorsignoff = 0;
 	my $is_patch = 0;
+	my $is_binding_patch = -1;
 	my $in_header_lines = $file ? 0 : 1;
 	my $in_commit_log = 0;		#Scanning lines before patch
 	my $has_commit_log = 0;		#Encountered lines before patch
+	my $commit_log_lines = 0;	#Number of commit log lines
 	my $commit_log_possible_stack_dump = 0;
 	my $commit_log_long_line = 0;
 	my $commit_log_has_diff = 0;
@@ -2375,6 +2430,14 @@
 
 		my $rawline = $rawlines[$linenr - 1];
 
+# check if it's a mode change, rename or start of a patch
+		if (!$in_commit_log &&
+		    ($line =~ /^ mode change [0-7]+ => [0-7]+ \S+\s*$/ ||
+		    ($line =~ /^rename (?:from|to) \S+\s*$/ ||
+		     $line =~ /^diff --git a\/[\w\/\.\_\-]+ b\/\S+\s*$/))) {
+			$is_patch = 1;
+		}
+
 #extract the line range in the file after the patch is applied
 		if (!$in_commit_log &&
 		    $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) {
@@ -2475,6 +2538,19 @@
 				$check = $check_orig;
 			}
 			$checklicenseline = 1;
+
+			if ($realfile !~ /^MAINTAINERS/) {
+				my $last_binding_patch = $is_binding_patch;
+
+				$is_binding_patch = () = $realfile =~ m@^(?:Documentation/devicetree/|include/dt-bindings/)@;
+
+				if (($last_binding_patch != -1) &&
+				    ($last_binding_patch ^ $is_binding_patch)) {
+					WARN("DT_SPLIT_BINDING_PATCH",
+					     "DT binding docs and includes should be a separate patch. See: Documentation/devicetree/bindings/submitting-patches.txt\n");
+				}
+			}
+
 			next;
 		}
 
@@ -2486,6 +2562,18 @@
 
 		$cnt_lines++ if ($realcnt != 0);
 
+# Verify the existence of a commit log if appropriate
+# 2 is used because a $signature is counted in $commit_log_lines
+		if ($in_commit_log) {
+			if ($line !~ /^\s*$/) {
+				$commit_log_lines++;	#could be a $signature
+			}
+		} elsif ($has_commit_log && $commit_log_lines < 2) {
+			WARN("COMMIT_MESSAGE",
+			     "Missing commit description - Add an appropriate one\n");
+			$commit_log_lines = 2;	#warn only once
+		}
+
 # Check if the commit log has what seems like a diff which can confuse patch
 		if ($in_commit_log && !$commit_log_has_diff &&
 		    (($line =~ m@^\s+diff\b.*a/[\w/]+@ &&
@@ -2507,10 +2595,24 @@
 			}
 		}
 
+# Check the patch for a From:
+		if (decode("MIME-Header", $line) =~ /^From:\s*(.*)/) {
+			$author = $1;
+			$author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i);
+			$author =~ s/"//g;
+		}
+
 # Check the patch for a signoff:
 		if ($line =~ /^\s*signed-off-by:/i) {
 			$signoff++;
 			$in_commit_log = 0;
+			if ($author ne '') {
+				my $l = $line;
+				$l =~ s/"//g;
+				if ($l =~ /^\s*signed-off-by:\s*\Q$author\E/i) {
+				    $authorsignoff = 1;
+				}
+			}
 		}
 
 # Check if MAINTAINERS is being updated.  If so, there's probably no need to
@@ -2587,6 +2689,24 @@
 			} else {
 				$signatures{$sig_nospace} = 1;
 			}
+
+# Check Co-developed-by: immediately followed by Signed-off-by: with same name and email
+			if ($sign_off =~ /^co-developed-by:$/i) {
+				if ($email eq $author) {
+					WARN("BAD_SIGN_OFF",
+					      "Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . "$here\n" . $rawline);
+				}
+				if (!defined $lines[$linenr]) {
+					WARN("BAD_SIGN_OFF",
+                                             "Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline);
+				} elsif ($rawlines[$linenr] !~ /^\s*signed-off-by:\s*(.*)/i) {
+					WARN("BAD_SIGN_OFF",
+					     "Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]);
+				} elsif ($1 ne $email) {
+					WARN("BAD_SIGN_OFF",
+					     "Co-developed-by and Signed-off-by: name/email do not match \n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]);
+				}
+			}
 		}
 
 # Check email subject for common tools that don't need to be mentioned
@@ -2596,12 +2716,6 @@
 			     "A patch subject line should describe the change not the tool that found it\n" . $herecurr);
 		}
 
-# Check for old stable address
-		if ($line =~ /^\s*cc:\s*.*<?\bstable\@kernel\.org\b>?.*$/i) {
-			ERROR("STABLE_ADDRESS",
-			      "The 'stable' address should be 'stable\@vger.kernel.org'\n" . $herecurr);
-		}
-
 # Check for unwanted Gerrit info
 		if ($in_commit_log && $line =~ /^\s*change-id:/i) {
 			ERROR("GERRIT_CHANGE_ID",
@@ -2613,8 +2727,10 @@
 		    ($line =~ /^\s*(?:WARNING:|BUG:)/ ||
 		     $line =~ /^\s*\[\s*\d+\.\d{6,6}\s*\]/ ||
 					# timestamp
-		     $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/)) {
-					# stack dump address
+		     $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/) ||
+		     $line =~ /^(?:\s+\w+:\s+[0-9a-fA-F]+){3,3}/ ||
+		     $line =~ /^\s*\#\d+\s*\[[0-9a-fA-F]+\]\s*\w+ at [0-9a-fA-F]+/) {
+					# stack dump address styles
 			$commit_log_possible_stack_dump = 1;
 		}
 
@@ -2786,6 +2902,17 @@
 			}
 		}
 
+# check for invalid commit id
+		if ($in_commit_log && $line =~ /(^fixes:|\bcommit)\s+([0-9a-f]{6,40})\b/i) {
+			my $id;
+			my $description;
+			($id, $description) = git_commit_info($2, undef, undef);
+			if (!defined($id)) {
+				WARN("UNKNOWN_COMMIT_ID",
+				     "Unknown commit id '$2', maybe rebased or not pulled?\n" . $herecurr);
+			}
+		}
+
 # ignore non-hunk lines and lines being removed
 		next if (!$hunk_line || $line =~ /^-/);
 
@@ -2915,7 +3042,7 @@
 			my @compats = $rawline =~ /\"([a-zA-Z0-9\-\,\.\+_]+)\"/g;
 
 			my $dt_path = $root . "/Documentation/devicetree/bindings/";
-			my $vp_file = $dt_path . "vendor-prefixes.txt";
+			my $vp_file = $dt_path . "vendor-prefixes.yaml";
 
 			foreach my $compat (@compats) {
 				my $compat2 = $compat;
@@ -2930,7 +3057,7 @@
 
 				next if $compat !~ /^([a-zA-Z0-9\-]+)\,/;
 				my $vendor = $1;
-				`grep -Eq "^$vendor\\b" $vp_file`;
+				`grep -Eq "\\"\\^\Q$vendor\E,\\.\\*\\":" $vp_file`;
 				if ( $? >> 8 ) {
 					WARN("UNDOCUMENTED_DT_STRING",
 					     "DT compatible string vendor \"$vendor\" appears un-documented -- check $vp_file\n" . $herecurr);
@@ -2954,10 +3081,24 @@
 					$comment = '..';
 				}
 
+# check SPDX comment style for .[chsS] files
+				if ($realfile =~ /\.[chsS]$/ &&
+				    $rawline =~ /SPDX-License-Identifier:/ &&
+				    $rawline !~ m@^\+\s*\Q$comment\E\s*@) {
+					WARN("SPDX_LICENSE_TAG",
+					     "Improper SPDX comment style for '$realfile', please use '$comment' instead\n" . $herecurr);
+				}
+
 				if ($comment !~ /^$/ &&
-				    $rawline !~ /^\+\Q$comment\E SPDX-License-Identifier: /) {
+				    $rawline !~ m@^\+\Q$comment\E SPDX-License-Identifier: @) {
 					WARN("SPDX_LICENSE_TAG",
 					     "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr);
+				} elsif ($rawline =~ /(SPDX-License-Identifier: .*)/) {
+					my $spdx_license = $1;
+					if (!is_SPDX_License_valid($spdx_license)) {
+						WARN("SPDX_LICENSE_TAG",
+						     "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr);
+					}
 				}
 			}
 		}
@@ -2965,6 +3106,14 @@
 # check we are in a valid source file if not then ignore this hunk
 		next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/);
 
+# check for using SPDX-License-Identifier on the wrong line number
+		if ($realline != $checklicenseline &&
+		    $rawline =~ /\bSPDX-License-Identifier:/ &&
+		    substr($line, @-, @+ - @-) eq "$;" x (@+ - @-)) {
+			WARN("SPDX_LICENSE_TAG",
+			     "Misplaced SPDX-License-Identifier tag - use line $checklicenseline instead\n" . $herecurr);
+		}
+
 # line length limit (with some exclusions)
 #
 # There are a few types of lines that may extend beyond $max_line_length:
@@ -3062,6 +3211,12 @@
 			}
 		}
 
+# check for assignments on the start of a line
+		if ($sline =~ /^\+\s+($Assignment)[^=]/) {
+			CHK("ASSIGNMENT_CONTINUATIONS",
+			    "Assignment operator '$1' should be on the previous line\n" . $hereprev);
+		}
+
 # check for && or || at the start of a line
 		if ($rawline =~ /^\+\s*(&&|\|\|)/) {
 			CHK("LOGICAL_CONTINUATIONS",
@@ -3069,7 +3224,7 @@
 		}
 
 # check indentation starts on a tab stop
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$)|$Declare\s*$Ident\s*[;=])/) {
 			my $indent = length($1);
 			if ($indent % 8) {
@@ -3082,7 +3237,7 @@
 		}
 
 # check multi-line statement indentation matches previous line
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|(?:\*\s*)*$Lval\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) {
 			$prevline =~ /^\+(\t*)(.*)$/;
 			my $oldindent = $1;
@@ -3239,7 +3394,7 @@
 			# known declaration macros
 		      $sline =~ /^\+\s+$declaration_macros/ ||
 			# start of struct or union or enum
-		      $sline =~ /^\+\s+(?:union|struct|enum|typedef)\b/ ||
+		      $sline =~ /^\+\s+(?:static\s+)?(?:const\s+)?(?:union|struct|enum|typedef)\b/ ||
 			# start or end of block or continuation of declaration
 		      $sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ ||
 			# bitfield continuation
@@ -3771,19 +3926,48 @@
 			     "type '$tmp' should be specified in [[un]signed] [short|int|long|long long] order\n" . $herecurr);
 		}
 
+# check for unnecessary <signed> int declarations of short/long/long long
+		while ($sline =~ m{\b($TypeMisordered(\s*\*)*|$C90_int_types)\b}g) {
+			my $type = trim($1);
+			next if ($type !~ /\bint\b/);
+			next if ($type !~ /\b(?:short|long\s+long|long)\b/);
+			my $new_type = $type;
+			$new_type =~ s/\b\s*int\s*\b/ /;
+			$new_type =~ s/\b\s*(?:un)?signed\b\s*/ /;
+			$new_type =~ s/^const\s+//;
+			$new_type = "unsigned $new_type" if ($type =~ /\bunsigned\b/);
+			$new_type = "const $new_type" if ($type =~ /^const\b/);
+			$new_type =~ s/\s+/ /g;
+			$new_type = trim($new_type);
+			if (WARN("UNNECESSARY_INT",
+				 "Prefer '$new_type' over '$type' as the int is unnecessary\n" . $herecurr) &&
+			    $fix) {
+				$fixed[$fixlinenr] =~ s/\b\Q$type\E\b/$new_type/;
+			}
+		}
+
 # check for static const char * arrays.
 		if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) {
 			WARN("STATIC_CONST_CHAR_ARRAY",
 			     "static const char * array should probably be static const char * const\n" .
 				$herecurr);
-               }
+		}
+
+# check for initialized const char arrays that should be static const
+		if ($line =~ /^\+\s*const\s+(char|unsigned\s+char|_*u8|(?:[us]_)?int8_t)\s+\w+\s*\[\s*(?:\w+\s*)?\]\s*=\s*"/) {
+			if (WARN("STATIC_CONST_CHAR_ARRAY",
+				 "const array should probably be static const\n" . $herecurr) &&
+			    $fix) {
+				$fixed[$fixlinenr] =~ s/(^.\s*)const\b/${1}static const/;
+			}
+		}
 
 # check for static char foo[] = "bar" declarations.
 		if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) {
 			WARN("STATIC_CONST_CHAR_ARRAY",
 			     "static char array declaration should probably be static const char\n" .
 				$herecurr);
-               }
+		}
 
 # check for const <foo> const where <foo> is not a pointer or array type
 		if ($sline =~ /\bconst\s+($BasicType)\s+const\b/) {
@@ -3957,7 +4141,7 @@
 
 # function brace can't be on same line, except for #defines of do while,
 # or if closed on same line
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    $sline =~ /$Type\s*$Ident\s*$balanced_parens\s*\{/ &&
 		    $sline !~ /\#\s*define\b.*do\s*\{/ &&
 		    $sline !~ /}/) {
@@ -4083,7 +4267,7 @@
 			my ($where, $prefix) = ($-[1], $1);
 			if ($prefix !~ /$Type\s+$/ &&
 			    ($where != 0 || $prefix !~ /^.\s+$/) &&
-			    $prefix !~ /[{,]\s+$/) {
+			    $prefix !~ /[{,:]\s+$/) {
 				if (ERROR("BRACKET_SPACE",
 					  "space prohibited before open square bracket '['\n" . $herecurr) &&
 				    $fix) {
@@ -4473,11 +4657,11 @@
 
 #need space before brace following if, while, etc
 		if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) ||
-		    $line =~ /do\{/) {
+		    $line =~ /\b(?:else|do)\{/) {
 			if (ERROR("SPACING",
 				  "space required before the open brace '{'\n" . $herecurr) &&
 			    $fix) {
-				$fixed[$fixlinenr] =~ s/^(\+.*(?:do|\)))\{/$1 {/;
+				$fixed[$fixlinenr] =~ s/^(\+.*(?:do|else|\)))\{/$1 {/;
 			}
 		}
 
@@ -4491,7 +4675,7 @@
 
 # closing brace should have a space following it when it has anything
 # on the line
-		if ($line =~ /}(?!(?:,|;|\)))\S/) {
+		if ($line =~ /}(?!(?:,|;|\)|\}))\S/) {
 			if (ERROR("SPACING",
 				  "space required after that close brace '}'\n" . $herecurr) &&
 			    $fix) {
@@ -4568,7 +4752,7 @@
 # check for unnecessary parentheses around comparisons in if uses
 # when !drivers/staging or command-line uses --strict
 		if (($realfile !~ m@^(?:drivers/staging/)@ || $check_orig) &&
-		    $^V && $^V ge 5.10.0 && defined($stat) &&
+		    $perl_version_ok && defined($stat) &&
 		    $stat =~ /(^.\s*if\s*($balanced_parens))/) {
 			my $if_stat = $1;
 			my $test = substr($2, 1, -1);
@@ -4605,7 +4789,7 @@
 # return is not a function
 		if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) {
 			my $spacing = $1;
-			if ($^V && $^V ge 5.10.0 &&
+			if ($perl_version_ok &&
 			    $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) {
 				my $value = $1;
 				$value = deparenthesize($value);
@@ -4632,7 +4816,7 @@
                }
 
 # if statements using unnecessary parentheses - ie: if ((foo == bar))
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    $line =~ /\bif\s*((?:\(\s*){2,})/) {
 			my $openparens = $1;
 			my $count = $openparens =~ tr@\(@\(@;
@@ -4649,7 +4833,7 @@
 #	avoid cases like "foo + BAR < baz"
 #	only fix matches surrounded by parentheses to avoid incorrect
 #	conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5"
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) {
 			my $lead = $1;
 			my $const = $2;
@@ -4841,17 +5025,6 @@
 		while ($line =~ m{($Constant|$Lval)}g) {
 			my $var = $1;
 
-#gcc binary extension
-			if ($var =~ /^$Binary$/) {
-				if (WARN("GCC_BINARY_CONSTANT",
-					 "Avoid gcc v4.3+ binary constant extension: <$var>\n" . $herecurr) &&
-				    $fix) {
-					my $hexval = sprintf("0x%x", oct($var));
-					$fixed[$fixlinenr] =~
-					    s/\b$var\b/$hexval/;
-				}
-			}
-
 #CamelCase
 			if ($var !~ /^$Constant$/ &&
 			    $var =~ /[A-Z][a-z]|[a-z][A-Z]/ &&
@@ -4939,6 +5112,7 @@
 			if (defined $define_args && $define_args ne "") {
 				$define_args = substr($define_args, 1, length($define_args) - 2);
 				$define_args =~ s/\s*//g;
+				$define_args =~ s/\\\+?//g;
 				@def_args = split(",", $define_args);
 			}
 
@@ -5032,10 +5206,10 @@
 			        next if ($arg =~ /\.\.\./);
 			        next if ($arg =~ /^type$/i);
 				my $tmp_stmt = $define_stmt;
-				$tmp_stmt =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
+				$tmp_stmt =~ s/\b(sizeof|typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
 				$tmp_stmt =~ s/\#+\s*$arg\b//g;
 				$tmp_stmt =~ s/\b$arg\s*\#\#//g;
-				my $use_cnt = $tmp_stmt =~ s/\b$arg\b//g;
+				my $use_cnt = () = $tmp_stmt =~ /\b$arg\b/g;
 				if ($use_cnt > 1) {
 					CHK("MACRO_ARG_REUSE",
 					    "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx");
@@ -5074,7 +5248,7 @@
 # do {} while (0) macro tests:
 # single-statement macros do not need to be enclosed in do while (0) loop,
 # macro should not end with a semicolon
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    $realfile !~ m@/vmlinux.lds.h$@ &&
 		    $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) {
 			my $ln = $linenr;
@@ -5115,16 +5289,6 @@
 			}
 		}
 
-# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
-# all assignments may have only one of the following with an assignment:
-#	.
-#	ALIGN(...)
-#	VMLINUX_SYMBOL(...)
-		if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
-			WARN("MISSING_VMLINUX_SYMBOL",
-			     "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr);
-		}
-
 # check for redundant bracing round if etc
 		if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
 			my ($level, $endln, @chunks) =
@@ -5330,15 +5494,28 @@
 		}
 
 # concatenated string without spaces between elements
-		if ($line =~ /$String[A-Z_]/ || $line =~ /[A-Za-z0-9_]$String/) {
-			CHK("CONCATENATED_STRING",
-			    "Concatenated strings should use spaces between elements\n" . $herecurr);
+		if ($line =~ /$String[A-Za-z0-9_]/ || $line =~ /[A-Za-z0-9_]$String/) {
+			if (CHK("CONCATENATED_STRING",
+				"Concatenated strings should use spaces between elements\n" . $herecurr) &&
+			    $fix) {
+				while ($line =~ /($String)/g) {
+					my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]);
+					$fixed[$fixlinenr] =~ s/\Q$extracted_string\E([A-Za-z0-9_])/$extracted_string $1/;
+					$fixed[$fixlinenr] =~ s/([A-Za-z0-9_])\Q$extracted_string\E/$1 $extracted_string/;
+				}
+			}
 		}
 
 # uncoalesced string fragments
 		if ($line =~ /$String\s*"/) {
-			WARN("STRING_FRAGMENTS",
-			     "Consecutive strings are generally better as a single string\n" . $herecurr);
+			if (WARN("STRING_FRAGMENTS",
+				 "Consecutive strings are generally better as a single string\n" . $herecurr) &&
+			    $fix) {
+				while ($line =~ /($String)(?=\s*")/g) {
+					my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]);
+					$fixed[$fixlinenr] =~ s/\Q$extracted_string\E\s*"/substr($extracted_string, 0, -1)/e;
+				}
+			}
 		}
 
 # check for non-standard and hex prefixed decimal printf formats
@@ -5374,9 +5551,14 @@
 
 # warn about #if 0
 		if ($line =~ /^.\s*\#\s*if\s+0\b/) {
-			CHK("REDUNDANT_CODE",
-			    "if this code is redundant consider removing it\n" .
-				$herecurr);
+			WARN("IF_0",
+			     "Consider removing the code enclosed by this #if 0 and its #endif\n" . $herecurr);
+		}
+
+# warn about #if 1
+		if ($line =~ /^.\s*\#\s*if\s+1\b/) {
+			WARN("IF_1",
+			     "Consider removing the #if 1 and its #endif\n" . $herecurr);
 		}
 
 # check for needless "if (<foo>) fn(<foo>)" uses
@@ -5423,7 +5605,8 @@
 			my ($s, $c) = ctx_statement_block($linenr - 3, $realcnt, 0);
 #			print("line: <$line>\nprevline: <$prevline>\ns: <$s>\nc: <$c>\n\n\n");
 
-			if ($s =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*(?:devm_)?(?:[kv][czm]alloc(?:_node|_array)?\b|kstrdup|kmemdup|(?:dev_)?alloc_skb)/) {
+			if ($s =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*$allocFunctions\s*\(/ &&
+			    $s !~ /\b__GFP_NOWARN\b/ ) {
 				WARN("OOM_MESSAGE",
 				     "Possible unnecessary 'out of memory' message\n" . $hereprev);
 			}
@@ -5447,7 +5630,7 @@
 		}
 
 # check for mask then right shift without a parentheses
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ &&
 		    $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so
 			WARN("MASK_THEN_SHIFT",
@@ -5455,7 +5638,7 @@
 		}
 
 # check for pointer comparisons to NULL
-		if ($^V && $^V ge 5.10.0) {
+		if ($perl_version_ok) {
 			while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) {
 				my $val = $1;
 				my $equal = "!";
@@ -5544,7 +5727,7 @@
 			# ignore udelay's < 10, however
 			if (! ($delay < 10) ) {
 				CHK("USLEEP_RANGE",
-				    "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $herecurr);
+				    "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst\n" . $herecurr);
 			}
 			if ($delay > 2000) {
 				WARN("LONG_UDELAY",
@@ -5556,7 +5739,7 @@
 		if ($line =~ /\bmsleep\s*\((\d+)\);/) {
 			if ($1 < 20) {
 				WARN("MSLEEP",
-				     "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $herecurr);
+				     "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.rst\n" . $herecurr);
 			}
 		}
 
@@ -5698,13 +5881,6 @@
 			     "__packed is preferred over __attribute__((packed))\n" . $herecurr);
 		}
 
-# Check for new packed members, warn to use care
-		if ($realfile !~ m@\binclude/uapi/@ &&
-		    $line =~ /\b(__attribute__\s*\(\s*\(.*\bpacked|__packed)\b/) {
-			WARN("NEW_PACKED",
-			     "Adding new packed members is to be done with care\n" . $herecurr);
-		}
-
 # Check for __attribute__ aligned, prefer __aligned
 		if ($realfile !~ m@\binclude/uapi/@ &&
 		    $line =~ /\b__attribute__\s*\(\s*\(.*aligned/) {
@@ -5712,6 +5888,18 @@
 			     "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr);
 		}
 
+# Check for __attribute__ section, prefer __section
+		if ($realfile !~ m@\binclude/uapi/@ &&
+		    $line =~ /\b__attribute__\s*\(\s*\(.*_*section_*\s*\(\s*("[^"]*")/) {
+			my $old = substr($rawline, $-[1], $+[1] - $-[1]);
+			my $new = substr($old, 1, -1);
+			if (WARN("PREFER_SECTION",
+				 "__section($new) is preferred over __attribute__((section($old)))\n" . $herecurr) &&
+			    $fix) {
+				$fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*_*section_*\s*\(\s*\Q$old\E\s*\)\s*\)\s*\)/__section($new)/;
+			}
+		}
+
 # Check for __attribute__ format(printf, prefer __printf
 		if ($realfile !~ m@\binclude/uapi/@ &&
 		    $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) {
@@ -5734,7 +5922,7 @@
 		}
 
 # Check for __attribute__ weak, or __weak declarations (may have link issues)
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ &&
 		    ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ ||
 		     $line =~ /\b__weak\b/)) {
@@ -5816,25 +6004,25 @@
 		}
 
 # check for vsprintf extension %p<foo> misuses
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s &&
 		    $1 !~ /^_*volatile_*$/) {
-			my $specifier;
-			my $extension;
-			my $bad_specifier = "";
 			my $stat_real;
 
 			my $lc = $stat =~ tr@\n@@;
 			$lc = $lc + $linenr;
 		        for (my $count = $linenr; $count <= $lc; $count++) {
+				my $specifier;
+				my $extension;
+				my $bad_specifier = "";
 				my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
 				$fmt =~ s/%%//g;
 
 				while ($fmt =~ /(\%[\*\d\.]*p(\w))/g) {
 					$specifier = $1;
 					$extension = $2;
-					if ($extension !~ /[SsBKRraEhMmIiUDdgVCbGNOx]/) {
+					if ($extension !~ /[SsBKRraEhMmIiUDdgVCbGNOxt]/) {
 						$bad_specifier = $specifier;
 						last;
 					}
@@ -5863,7 +6051,7 @@
 		}
 
 # Check for misused memsets
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/) {
 
@@ -5881,7 +6069,7 @@
 		}
 
 # Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar)
-#		if ($^V && $^V ge 5.10.0 &&
+#		if ($perl_version_ok &&
 #		    defined $stat &&
 #		    $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
 #			if (WARN("PREFER_ETHER_ADDR_COPY",
@@ -5892,7 +6080,7 @@
 #		}
 
 # Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar)
-#		if ($^V && $^V ge 5.10.0 &&
+#		if ($perl_version_ok &&
 #		    defined $stat &&
 #		    $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
 #			WARN("PREFER_ETHER_ADDR_EQUAL",
@@ -5901,7 +6089,7 @@
 
 # check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr
 # check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr
-#		if ($^V && $^V ge 5.10.0 &&
+#		if ($perl_version_ok &&
 #		    defined $stat &&
 #		    $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
 #
@@ -5923,7 +6111,7 @@
 #		}
 
 # typecasts on min/max could be min_t/max_t
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) {
 			if (defined $2 || defined $7) {
@@ -5947,23 +6135,23 @@
 		}
 
 # check usleep_range arguments
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) {
 			my $min = $1;
 			my $max = $7;
 			if ($min eq $max) {
 				WARN("USLEEP_RANGE",
-				     "usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
+				     "usleep_range should not use min == max args; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n");
 			} elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ &&
 				 $min > $max) {
 				WARN("USLEEP_RANGE",
-				     "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
+				     "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n");
 			}
 		}
 
 # check for naked sscanf
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $line =~ /\bsscanf\b/ &&
 		    ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ &&
@@ -5977,7 +6165,7 @@
 		}
 
 # check for simple sscanf that should be kstrto<foo>
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $line =~ /\bsscanf\b/) {
 			my $lc = $stat =~ tr@\n@@;
@@ -6049,7 +6237,7 @@
 		}
 
 # check for function definitions
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $stat =~ /^.\s*(?:$Storage\s+)?$Type\s*($Ident)\s*$balanced_parens\s*{/s) {
 			$context_function = $1;
@@ -6081,22 +6269,22 @@
 			}
 		}
 
-# check for pointless casting of kmalloc return
-		if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) {
+# check for pointless casting of alloc functions
+		if ($line =~ /\*\s*\)\s*$allocFunctions\b/) {
 			WARN("UNNECESSARY_CASTS",
 			     "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
 		}
 
 # alloc style
 # p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...)
-		if ($^V && $^V ge 5.10.0 &&
-		    $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*([kv][mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) {
+		if ($perl_version_ok &&
+		    $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k|v)[mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) {
 			CHK("ALLOC_SIZEOF_STRUCT",
 			    "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr);
 		}
 
 # check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
 			my $oldfunc = $3;
@@ -6125,8 +6313,9 @@
 		}
 
 # check for krealloc arg reuse
-		if ($^V && $^V ge 5.10.0 &&
-		    $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/) {
+		if ($perl_version_ok &&
+		    $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*($Lval)\s*,/ &&
+		    $1 eq $3) {
 			WARN("KREALLOC_ARG_REUSE",
 			     "Reusing the krealloc arg is almost always a bug\n" . $herecurr);
 		}
@@ -6194,7 +6383,7 @@
 		}
 
 # check for switch/default statements without a break;
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) {
 			my $cnt = statement_rawlines($stat);
@@ -6270,6 +6459,20 @@
 			     "please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr);
 		}
 
+# check for spin_is_locked(), suggest lockdep instead
+		if ($line =~ /\bspin_is_locked\(/) {
+			WARN("USE_LOCKDEP",
+			     "Where possible, use lockdep_assert_held instead of assertions based on spin_is_locked\n" . $herecurr);
+		}
+
+# check for deprecated apis
+		if ($line =~ /\b($deprecated_apis_search)\b\s*\(/) {
+			my $deprecated_api = $1;
+			my $new_api = $deprecated_apis{$deprecated_api};
+			WARN("DEPRECATED_API",
+			     "Deprecated use of '$deprecated_api', prefer '$new_api' instead\n" . $herecurr);
+		}
+
 # check for various structs that are normally const (ops, kgdb, device_tree)
 # and avoid what seem like struct definitions 'struct foo {'
 		if ($line !~ /\bconst\b/ &&
@@ -6298,12 +6501,18 @@
 		}
 
 # likely/unlikely comparisons similar to "(likely(foo) > 0)"
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) {
 			WARN("LIKELY_MISUSE",
 			     "Using $1 should generally have parentheses around the comparison\n" . $herecurr);
 		}
 
+# nested likely/unlikely calls
+		if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) {
+			WARN("LIKELY_MISUSE",
+			     "nested (un)?likely() calls, $1 already uses unlikely() internally\n" . $herecurr);
+		}
+
 # whine mightly about in_atomic
 		if ($line =~ /\bin_atomic\s*\(/) {
 			if ($realfile =~ m@^drivers/@) {
@@ -6341,7 +6550,7 @@
 # check for DEVICE_ATTR uses that could be DEVICE_ATTR_<FOO>
 # and whether or not function naming is typical and if
 # DEVICE_ATTR permissions uses are unusual too
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $stat =~ /\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?\s*(\s*(?:${multi_mode_perms_string_search}|0[0-7]{3,3})\s*)\s*\)?\s*,\s*(\w+)\s*,\s*(\w+)\s*\)/) {
 			my $var = $1;
@@ -6401,7 +6610,7 @@
 #   specific definition of not visible in sysfs.
 # o Ignore proc_create*(...) uses with a decimal 0 permission as that means
 #   use the default permissions
-		if ($^V && $^V ge 5.10.0 &&
+		if ($perl_version_ok &&
 		    defined $stat &&
 		    $line =~ /$mode_perms_search/) {
 			foreach my $entry (@mode_permission_funcs) {
@@ -6463,6 +6672,12 @@
 				     "unknown module license " . $extracted_string . "\n" . $herecurr);
 			}
 		}
+
+# check for sysctl duplicate constants
+		if ($line =~ /\.extra[12]\s*=\s*&(zero|one|int_max)\b/) {
+			WARN("DUPLICATED_SYSCTL_CONST",
+				"duplicated sysctl range checking value '$1', consider using the shared one in include/linux/sysctl.h\n" . $herecurr);
+		}
 	}
 
 	# If we have no input at all, then there is nothing to report on
@@ -6487,9 +6702,14 @@
 		ERROR("NOT_UNIFIED_DIFF",
 		      "Does not appear to be a unified-diff format patch\n");
 	}
-	if ($is_patch && $has_commit_log && $chk_signoff && $signoff == 0) {
-		ERROR("MISSING_SIGN_OFF",
-		      "Missing Signed-off-by: line(s)\n");
+	if ($is_patch && $has_commit_log && $chk_signoff) {
+		if ($signoff == 0) {
+			ERROR("MISSING_SIGN_OFF",
+			      "Missing Signed-off-by: line(s)\n");
+		} elsif (!$authorsignoff) {
+			WARN("NO_AUTHOR_SIGN_OFF",
+			     "Missing Signed-off-by: line by nominal patch author '$author'\n");
+		}
 	}
 
 	print report_dump();
diff --git a/test/dm/clk.c b/test/dm/clk.c
index 676ef21..31335a5 100644
--- a/test/dm/clk.c
+++ b/test/dm/clk.c
@@ -8,6 +8,7 @@
 #include <dm.h>
 #include <asm/clk.h>
 #include <dm/test.h>
+#include <dm/device-internal.h>
 #include <linux/err.h>
 #include <test/ut.h>
 
@@ -53,8 +54,19 @@
 	ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test",
 					      &dev_test));
 	ut_assertok(sandbox_clk_test_get(dev_test));
+	ut_assertok(sandbox_clk_test_devm_get(dev_test));
 	ut_assertok(sandbox_clk_test_valid(dev_test));
 
+	ut_asserteq(0, sandbox_clk_test_get_rate(dev_test,
+						 SANDBOX_CLK_TEST_ID_DEVM_NULL));
+	ut_asserteq(0, sandbox_clk_test_set_rate(dev_test,
+						 SANDBOX_CLK_TEST_ID_DEVM_NULL,
+						 0));
+	ut_asserteq(0, sandbox_clk_test_enable(dev_test,
+					       SANDBOX_CLK_TEST_ID_DEVM_NULL));
+	ut_asserteq(0, sandbox_clk_test_disable(dev_test,
+						SANDBOX_CLK_TEST_ID_DEVM_NULL));
+
 	ut_asserteq(1234,
 		    sandbox_clk_test_get_rate(dev_test,
 					      SANDBOX_CLK_TEST_ID_FIXED));
@@ -62,6 +74,10 @@
 						 SANDBOX_CLK_TEST_ID_SPI));
 	ut_asserteq(0, sandbox_clk_test_get_rate(dev_test,
 						 SANDBOX_CLK_TEST_ID_I2C));
+	ut_asserteq(321, sandbox_clk_test_get_rate(dev_test,
+						   SANDBOX_CLK_TEST_ID_DEVM1));
+	ut_asserteq(0, sandbox_clk_test_get_rate(dev_test,
+						 SANDBOX_CLK_TEST_ID_DEVM2));
 
 	rate = sandbox_clk_test_set_rate(dev_test, SANDBOX_CLK_TEST_ID_FIXED,
 					 12345);
@@ -121,8 +137,25 @@
 	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
 	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
 
+	ut_asserteq(1, sandbox_clk_query_requested(dev_clk,
+						   SANDBOX_CLK_ID_SPI));
+	ut_asserteq(1, sandbox_clk_query_requested(dev_clk,
+						   SANDBOX_CLK_ID_I2C));
+	ut_asserteq(1, sandbox_clk_query_requested(dev_clk,
+						   SANDBOX_CLK_ID_UART2));
 	ut_assertok(sandbox_clk_test_free(dev_test));
+	ut_asserteq(0, sandbox_clk_query_requested(dev_clk,
+						   SANDBOX_CLK_ID_SPI));
+	ut_asserteq(0, sandbox_clk_query_requested(dev_clk,
+						   SANDBOX_CLK_ID_I2C));
+	ut_asserteq(0, sandbox_clk_query_requested(dev_clk,
+						   SANDBOX_CLK_ID_UART2));
 
+	ut_asserteq(1, sandbox_clk_query_requested(dev_clk,
+						   SANDBOX_CLK_ID_UART1));
+	ut_assertok(device_remove(dev_test, DM_REMOVE_NORMAL));
+	ut_asserteq(0, sandbox_clk_query_requested(dev_clk,
+						   SANDBOX_CLK_ID_UART1));
 	return 0;
 }
 DM_TEST(dm_test_clk, DM_TESTF_SCAN_FDT);
@@ -159,6 +192,7 @@
 	ut_assertok(sandbox_clk_test_release_bulk(dev_test));
 	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
 	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+	ut_assertok(device_remove(dev_test, DM_REMOVE_NORMAL));
 
 	return 0;
 }
diff --git a/test/dm/regmap.c b/test/dm/regmap.c
index 82de295..6fd1f20 100644
--- a/test/dm/regmap.c
+++ b/test/dm/regmap.c
@@ -99,18 +99,27 @@
 	struct regmap *map;
 	uint reg;
 
+	sandbox_set_enable_memio(true);
 	ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
 	map = syscon_get_regmap(dev);
 	ut_assertok_ptr(map);
 
 	ut_assertok(regmap_write(map, 0, 0xcacafafa));
-	ut_assertok(regmap_write(map, 3, 0x55aa2211));
+	ut_assertok(regmap_write(map, 5, 0x55aa2211));
 
 	ut_assertok(regmap_read(map, 0, &reg));
-	ut_assertok(regmap_read(map, 3, &reg));
+	ut_asserteq(0xcacafafa, reg);
+	ut_assertok(regmap_read(map, 5, &reg));
+	ut_asserteq(0x55aa2211, reg);
 
+	ut_assertok(regmap_read(map, 0, &reg));
+	ut_asserteq(0xcacafafa, reg);
 	ut_assertok(regmap_update_bits(map, 0, 0xff00ff00, 0x55aa2211));
-	ut_assertok(regmap_update_bits(map, 3, 0x00ff00ff, 0xcacafada));
+	ut_assertok(regmap_read(map, 0, &reg));
+	ut_asserteq(0x55ca22fa, reg);
+	ut_assertok(regmap_update_bits(map, 5, 0x00ff00ff, 0xcacafada));
+	ut_assertok(regmap_read(map, 5, &reg));
+	ut_asserteq(0x55ca22da, reg);
 
 	return 0;
 }
@@ -130,6 +139,7 @@
 		u32 val3;
 	};
 
+	sandbox_set_enable_memio(true);
 	ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
 	map = syscon_get_regmap(dev);
 	ut_assertok_ptr(map);
@@ -138,7 +148,9 @@
 	regmap_set(map, struct layout, val3, 0x55aa2211);
 
 	ut_assertok(regmap_get(map, struct layout, val0, &reg));
+	ut_asserteq(0xcacafafa, reg);
 	ut_assertok(regmap_get(map, struct layout, val3, &reg));
+	ut_asserteq(0x55aa2211, reg);
 
 	return 0;
 }
@@ -159,6 +171,7 @@
 
 	start = get_timer(0);
 
+	ut_assertok(regmap_write(map, 0, 0x0));
 	ut_asserteq(-ETIMEDOUT,
 		    regmap_read_poll_timeout_test(map, 0, reg,
 						  (reg == 0xcacafafa),
diff --git a/test/lib/Makefile b/test/lib/Makefile
index 308c617..b13aaca 100644
--- a/test/lib/Makefile
+++ b/test/lib/Makefile
@@ -6,3 +6,4 @@
 obj-y += hexdump.o
 obj-y += lmb.o
 obj-y += string.o
+obj-$(CONFIG_ERRNO_STR) += test_errno_str.o
diff --git a/test/lib/test_errno_str.c b/test/lib/test_errno_str.c
new file mode 100644
index 0000000..8a9f1fd
--- /dev/null
+++ b/test/lib/test_errno_str.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Unit tests for memory functions
+ *
+ * The architecture dependent implementations run through different lines of
+ * code depending on the alignment and length of memory regions copied or set.
+ * This has to be considered in testing.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <test/lib.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+/**
+ * lib_errno_str() - unit test for errno_str()
+ *
+ * Test errno_str() with varied alignment and length of the copied buffer.
+ *
+ * @uts:	unit test state
+ * Return:	0 = success, 1 = failure
+ */
+static int lib_errno_str(struct unit_test_state *uts)
+{
+	const char *msg;
+
+	msg = errno_str(1);
+	ut_asserteq_str("Success", msg);
+
+	msg = errno_str(0);
+	ut_asserteq_str("Success", msg);
+
+	msg = errno_str(-ENOMEM);
+	ut_asserteq_str("Out of memory", msg);
+
+	msg = errno_str(-99999);
+	ut_asserteq_str("Unknown error", msg);
+
+	return 0;
+}
+
+LIB_TEST(lib_errno_str, 0);
diff --git a/test/py/README.md b/test/py/README.md
index 2156661..3cbe01b 100644
--- a/test/py/README.md
+++ b/test/py/README.md
@@ -21,19 +21,26 @@
 need to implement various "hook" scripts that are called by the test suite at
 the appropriate time.
 
-On Debian or Debian-like distributions, the following packages are required.
-Some packages are required to execute any test, and others only for specific
-tests. Similar package names should exist in other distributions.
+In order to run the testsuite at a minimum we require that both python3 and
+pip for python3 be installed.  All of the required python modules are
+described in the requirements.txt file in this directory and can be installed
+with the command ```pip install -r requirements.txt```
 
-| Package        | Version tested (Ubuntu 14.04) |
-| -------------- | ----------------------------- |
-| python         | 2.7.5-5ubuntu3                |
-| python-pytest  | 2.5.1-1                       |
-| python-subunit | -                             |
-| gdisk          | 0.8.8-1ubuntu0.1              |
-| dfu-util       | 0.5-1                         |
-| dtc            | 1.4.0+dfsg-1                  |
-| openssl        | 1.0.1f-1ubuntu2.22            |
+In order to execute certain tests on their supported platforms other tools
+will be required.  The following is an incomplete list:
+
+| Package        |
+| -------------- |
+| gdisk          |
+| dfu-util       |
+| dtc            |
+| openssl        |
+| sudo OR guestmount |
+| e2fsprogs      |
+| dosfstools     |
+
+Please use the apporirate commands for your distribution to match these tools
+up with the package that provides them.
 
 The test script supports either:
 
@@ -45,18 +52,16 @@
 
 ### Using `virtualenv` to provide requirements
 
-Older distributions (e.g. Ubuntu 10.04) may not provide all the required
-packages, or may provide versions that are too old to run the test suite. One
-can use the Python `virtualenv` script to locally install more up-to-date
-versions of the required packages without interfering with the OS installation.
-For example:
+The recommended way to run the test suite, in order to ensure reproducibility
+is to use `virtualenv` to set up the necessary environment.  This can be done
+via the following commands:
 
 ```bash
 $ cd /path/to/u-boot
-$ sudo apt-get install python python-virtualenv
-$ virtualenv venv
+$ sudo apt-get install python3 python3-virtualenv
+$ virtualenv -p /usr/bin/python3 venv
 $ . ./venv/bin/activate
-$ pip install pytest
+$ pip install -r test/py/requirements.txt
 ```
 
 ## Testing sandbox
diff --git a/test/py/conftest.py b/test/py/conftest.py
index 00d8ef8..bffee6b 100644
--- a/test/py/conftest.py
+++ b/test/py/conftest.py
@@ -13,20 +13,16 @@
 # - Implementing custom pytest markers.
 
 import atexit
+import configparser
 import errno
+import io
 import os
 import os.path
 import pytest
-from _pytest.runner import runtestprotocol
 import re
-import StringIO
+from _pytest.runner import runtestprotocol
 import sys
 
-try:
-    import configparser
-except:
-    import ConfigParser as configparser
-
 # Globals: The HTML log file, and the connection to the U-Boot console.
 log = None
 console = None
@@ -169,9 +165,9 @@
 
         with open(dot_config, 'rt') as f:
             ini_str = '[root]\n' + f.read()
-            ini_sio = StringIO.StringIO(ini_str)
+            ini_sio = io.StringIO(ini_str)
             parser = configparser.RawConfigParser()
-            parser.readfp(ini_sio)
+            parser.read_file(ini_sio)
             ubconfig.buildconfig.update(parser.items('root'))
 
     ubconfig.test_py_dir = test_py_dir
@@ -431,11 +427,9 @@
         Nothing.
     """
 
-    mark = item.get_marker('boardspec')
-    if not mark:
-        return
     required_boards = []
-    for board in mark.args:
+    for boards in item.iter_markers('boardspec'):
+        board = boards.args[0]
         if board.startswith('!'):
             if ubconfig.board_type == board[1:]:
                 pytest.skip('board "%s" not supported' % ubconfig.board_type)
@@ -459,16 +453,14 @@
         Nothing.
     """
 
-    mark = item.get_marker('buildconfigspec')
-    if mark:
-        for option in mark.args:
-            if not ubconfig.buildconfig.get('config_' + option.lower(), None):
-                pytest.skip('.config feature "%s" not enabled' % option.lower())
-    notmark = item.get_marker('notbuildconfigspec')
-    if notmark:
-        for option in notmark.args:
-            if ubconfig.buildconfig.get('config_' + option.lower(), None):
-                pytest.skip('.config feature "%s" enabled' % option.lower())
+    for options in item.iter_markers('buildconfigspec'):
+        option = options.args[0]
+        if not ubconfig.buildconfig.get('config_' + option.lower(), None):
+            pytest.skip('.config feature "%s" not enabled' % option.lower())
+    for option in item.iter_markers('notbuildconfigspec'):
+        option = options.args[0]
+        if ubconfig.buildconfig.get('config_' + option.lower(), None):
+            pytest.skip('.config feature "%s" enabled' % option.lower())
 
 def tool_is_in_path(tool):
     for path in os.environ["PATH"].split(os.pathsep):
@@ -491,10 +483,8 @@
         Nothing.
     """
 
-    mark = item.get_marker('requiredtool')
-    if not mark:
-        return
-    for tool in mark.args:
+    for tools in item.iter_markers('requiredtool'):
+        tool = tools.args[0]
         if not tool_is_in_path(tool):
             pytest.skip('tool "%s" not in $PATH' % tool)
 
diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py
index 637a3bd..545a774 100644
--- a/test/py/multiplexed_log.py
+++ b/test/py/multiplexed_log.py
@@ -5,8 +5,8 @@
 # Generate an HTML-formatted log file containing multiple streams of data,
 # each represented in a well-delineated/-structured fashion.
 
-import cgi
 import datetime
+import html
 import os.path
 import shutil
 import subprocess
@@ -51,7 +51,7 @@
         """Write data to the log stream.
 
         Args:
-            data: The data to write tot he file.
+            data: The data to write to the file.
             implicit: Boolean indicating whether data actually appeared in the
                 stream, or was implicitly generated. A valid use-case is to
                 repeat a shell prompt at the start of each separate log
@@ -64,7 +64,8 @@
 
         self.logfile.write(self, data, implicit)
         if self.chained_file:
-            self.chained_file.write(data)
+            # Chained file is console, convert things a little
+            self.chained_file.write((data.encode('ascii', 'replace')).decode())
 
     def flush(self):
         """Flush the log stream, to ensure correct log interleaving.
@@ -136,6 +137,10 @@
             p = subprocess.Popen(cmd, cwd=cwd,
                 stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
             (stdout, stderr) = p.communicate()
+            if stdout is not None:
+                stdout = stdout.decode('utf-8')
+            if stderr is not None:
+                stderr = stderr.decode('utf-8')
             output = ''
             if stdout:
                 if stderr:
@@ -215,7 +220,7 @@
             Nothing.
         """
 
-        self.f = open(fn, 'wt')
+        self.f = open(fn, 'wt', encoding='utf-8')
         self.last_stream = None
         self.blocks = []
         self.cur_evt = 1
@@ -334,7 +339,7 @@
         data = data.replace(chr(13), '')
         data = ''.join((ord(c) in self._nonprint) and ('%%%02x' % ord(c)) or
                        c for c in data)
-        data = cgi.escape(data)
+        data = html.escape(data)
         return data
 
     def _terminate_stream(self):
diff --git a/test/py/pytest.ini b/test/py/pytest.ini
index 7e40068..e93d010 100644
--- a/test/py/pytest.ini
+++ b/test/py/pytest.ini
@@ -8,3 +8,6 @@
 markers =
     boardspec: U-Boot: Describes the set of boards a test can/can't run on.
     buildconfigspec: U-Boot: Describes Kconfig/config-header constraints.
+    notbuildconfigspec: U-Boot: Describes required disabled Kconfig options.
+    requiredtool: U-Boot: Required host tools for a test.
+    slow: U-Boot: Specific test will run slowly.
diff --git a/test/py/requirements.txt b/test/py/requirements.txt
new file mode 100644
index 0000000..cf25118
--- /dev/null
+++ b/test/py/requirements.txt
@@ -0,0 +1,22 @@
+atomicwrites==1.3.0
+attrs==19.3.0
+coverage==4.5.4
+extras==1.0.0
+fixtures==3.0.0
+importlib-metadata==0.23
+linecache2==1.0.0
+more-itertools==7.2.0
+packaging==19.2
+pbr==5.4.3
+pluggy==0.13.0
+py==1.8.0
+pyparsing==2.4.2
+pytest==5.2.1
+python-mimeparse==1.6.0
+python-subunit==1.3.0
+six==1.12.0
+testtools==2.3.0
+traceback2==1.4.0
+unittest2==1.1.0
+wcwidth==0.1.7
+zipp==0.6.0
diff --git a/test/py/test.py b/test/py/test.py
index a514094..bee88d9 100755
--- a/test/py/test.py
+++ b/test/py/test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
 # SPDX-License-Identifier: GPL-2.0
 
 # Copyright (c) 2015 Stephen Warren
@@ -7,28 +7,14 @@
 # Wrapper script to invoke pytest with the directory name that contains the
 # U-Boot tests.
 
-from __future__ import print_function
-
 import os
 import os.path
 import sys
-
-# Get rid of argv[0]
-sys.argv.pop(0)
+from pkg_resources import load_entry_point
 
 # argv; py.test test_directory_name user-supplied-arguments
-args = ['py.test', os.path.dirname(__file__) + '/tests']
+args = [os.path.dirname(__file__) + '/tests']
 args.extend(sys.argv)
 
-try:
-    os.execvp('py.test', args)
-except:
-    # Log full details of any exception for detailed analysis
-    import traceback
-    traceback.print_exc()
-    # Hint to the user that they likely simply haven't installed the required
-    # dependencies.
-    print('''
-exec(py.test) failed; perhaps you are missing some dependencies?
-See test/py/README.md for the list.''', file=sys.stderr)
-    sys.exit(1)
+if __name__ == '__main__':
+    sys.exit(load_entry_point('pytest', 'console_scripts', 'pytest')(args))
diff --git a/test/py/tests/test_android/test_avb.py b/test/py/tests/test_android/test_avb.py
index 8132423..20ccaf6 100644
--- a/test/py/tests/test_android/test_avb.py
+++ b/test/py/tests/test_android/test_avb.py
@@ -23,7 +23,8 @@
 temp_addr = 0x90000000
 temp_addr2 = 0x90002000
 
-@pytest.mark.buildconfigspec('cmd_avb', 'cmd_mmc')
+@pytest.mark.buildconfigspec('cmd_avb')
+@pytest.mark.buildconfigspec('cmd_mmc')
 def test_avb_verify(u_boot_console):
     """Run AVB 2.0 boot verification chain with avb subset of commands
     """
@@ -36,7 +37,8 @@
     assert response.find(success_str)
 
 
-@pytest.mark.buildconfigspec('cmd_avb', 'cmd_mmc')
+@pytest.mark.buildconfigspec('cmd_avb')
+@pytest.mark.buildconfigspec('cmd_mmc')
 def test_avb_mmc_uuid(u_boot_console):
     """Check if 'avb get_uuid' works, compare results with
     'part list mmc 1' output
@@ -93,7 +95,8 @@
     assert response == 'Unlocked = 1'
 
 
-@pytest.mark.buildconfigspec('cmd_avb', 'cmd_mmc')
+@pytest.mark.buildconfigspec('cmd_avb')
+@pytest.mark.buildconfigspec('cmd_mmc')
 def test_avb_mmc_read(u_boot_console):
     """Test mmc read operation
     """
diff --git a/test/py/tests/test_bind.py b/test/py/tests/test_bind.py
index 2d48484..20c6050 100644
--- a/test/py/tests/test_bind.py
+++ b/test/py/tests/test_bind.py
@@ -9,11 +9,11 @@
 	lines = [x.strip() for x in response.splitlines()]
 	leaf = ' ' * 4 * depth;
 	if not last_child:
-		leaf = leaf + '\|'
+		leaf = leaf + r'\|'
 	else:
 		leaf = leaf + '`'
 	leaf = leaf + '-- ' + name
-	line = (' *{:10.10}    [0-9]*  \[ [ +] \]   {:20.20}  {}$'
+	line = (r' *{:10.10}    [0-9]*  \[ [ +] \]   {:20.20}  {}$'
 	        .format(uclass, drv, leaf))
 	prog = re.compile(line)
 	for l in lines:
diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py
index d5430f9..ca01542 100644
--- a/test/py/tests/test_efi_selftest.py
+++ b/test/py/tests/test_efi_selftest.py
@@ -59,7 +59,7 @@
 	u_boot_console.run_command(cmd='setenv efi_selftest text input')
 	output = u_boot_console.run_command(cmd='bootefi selftest',
 					    wait_for_prompt=False)
-	m = u_boot_console.p.expect(['To terminate type \'x\''])
+	m = u_boot_console.p.expect([r'To terminate type \'x\''])
 	if m != 0:
 		raise Exception('No prompt for \'text input\' test')
 	u_boot_console.drain_console()
@@ -68,7 +68,7 @@
 	u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
 				   send_nl=False, wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 4 \(unknown\), scan code 0 \(Null\)'])
+		[r'Unicode char 4 \(unknown\), scan code 0 \(Null\)'])
 	if m != 0:
 		raise Exception('EOT failed in \'text input\' test')
 	u_boot_console.drain_console()
@@ -76,7 +76,7 @@
 	u_boot_console.run_command(cmd=chr(8), wait_for_echo=False,
 				   send_nl=False, wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 8 \(BS\), scan code 0 \(Null\)'])
+		[r'Unicode char 8 \(BS\), scan code 0 \(Null\)'])
 	if m != 0:
 		raise Exception('BS failed in \'text input\' test')
 	u_boot_console.drain_console()
@@ -84,7 +84,7 @@
 	u_boot_console.run_command(cmd=chr(9), wait_for_echo=False,
 				   send_nl=False, wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 9 \(TAB\), scan code 0 \(Null\)'])
+		[r'Unicode char 9 \(TAB\), scan code 0 \(Null\)'])
 	if m != 0:
 		raise Exception('BS failed in \'text input\' test')
 	u_boot_console.drain_console()
@@ -92,7 +92,7 @@
 	u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False,
 				   wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
+		[r'Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
 	if m != 0:
 		raise Exception('\'a\' failed in \'text input\' test')
 	u_boot_console.drain_console()
@@ -100,14 +100,14 @@
 	u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False,
 				   send_nl=False, wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 0 \(Null\), scan code 1 \(Up\)'])
+		[r'Unicode char 0 \(Null\), scan code 1 \(Up\)'])
 	if m != 0:
 		raise Exception('UP failed in \'text input\' test')
 	u_boot_console.drain_console()
 	# Euro sign
-	u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False,
+	u_boot_console.run_command(cmd=b'\xe2\x82\xac'.decode(), wait_for_echo=False,
 				   send_nl=False, wait_for_prompt=False)
-	m = u_boot_console.p.expect(['Unicode char 8364 \(\''])
+	m = u_boot_console.p.expect([r'Unicode char 8364 \(\''])
 	if m != 0:
 		raise Exception('Euro sign failed in \'text input\' test')
 	u_boot_console.drain_console()
@@ -129,7 +129,7 @@
 	u_boot_console.run_command(cmd='setenv efi_selftest extended text input')
 	output = u_boot_console.run_command(cmd='bootefi selftest',
 					    wait_for_prompt=False)
-	m = u_boot_console.p.expect(['To terminate type \'CTRL\+x\''])
+	m = u_boot_console.p.expect([r'To terminate type \'CTRL\+x\''])
 	if m != 0:
 		raise Exception('No prompt for \'text input\' test')
 	u_boot_console.drain_console()
@@ -138,7 +138,7 @@
 	u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
 				   send_nl=False, wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 100 \\(\'d\'\\), scan code 0 \\(CTRL\\+Null\\)'])
+		[r'Unicode char 100 \(\'d\'\), scan code 0 \(CTRL\+Null\)'])
 	if m != 0:
 		raise Exception('EOT failed in \'text input\' test')
 	u_boot_console.drain_console()
@@ -146,7 +146,7 @@
 	u_boot_console.run_command(cmd=chr(8), wait_for_echo=False,
 				   send_nl=False, wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 8 \(BS\), scan code 0 \(\+Null\)'])
+		[r'Unicode char 8 \(BS\), scan code 0 \(\+Null\)'])
 	if m != 0:
 		raise Exception('BS failed in \'text input\' test')
 	u_boot_console.drain_console()
@@ -154,7 +154,7 @@
 	u_boot_console.run_command(cmd=chr(9), wait_for_echo=False,
 				   send_nl=False, wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 9 \(TAB\), scan code 0 \(\+Null\)'])
+		[r'Unicode char 9 \(TAB\), scan code 0 \(\+Null\)'])
 	if m != 0:
 		raise Exception('TAB failed in \'text input\' test')
 	u_boot_console.drain_console()
@@ -162,7 +162,7 @@
 	u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False,
 				   wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
+		[r'Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
 	if m != 0:
 		raise Exception('\'a\' failed in \'text input\' test')
 	u_boot_console.drain_console()
@@ -170,23 +170,23 @@
 	u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False,
 				   send_nl=False, wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 0 \(Null\), scan code 1 \(\+Up\)'])
+		[r'Unicode char 0 \(Null\), scan code 1 \(\+Up\)'])
 	if m != 0:
 		raise Exception('UP failed in \'text input\' test')
 	u_boot_console.drain_console()
 	# Euro sign
-	u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False,
+	u_boot_console.run_command(cmd=b'\xe2\x82\xac'.decode(), wait_for_echo=False,
 				   send_nl=False, wait_for_prompt=False)
-	m = u_boot_console.p.expect(['Unicode char 8364 \(\''])
+	m = u_boot_console.p.expect([r'Unicode char 8364 \(\''])
 	if m != 0:
 		raise Exception('Euro sign failed in \'text input\' test')
 	u_boot_console.drain_console()
 	# SHIFT+ALT+FN 5
-	u_boot_console.run_command(cmd='\x1b\x5b\x31\x35\x3b\x34\x7e',
+	u_boot_console.run_command(cmd=b'\x1b\x5b\x31\x35\x3b\x34\x7e'.decode(),
 				   wait_for_echo=False, send_nl=False,
 				   wait_for_prompt=False)
 	m = u_boot_console.p.expect(
-		['Unicode char 0 \(Null\), scan code 15 \(SHIFT\+ALT\+FN 5\)'])
+		[r'Unicode char 0 \(Null\), scan code 15 \(SHIFT\+ALT\+FN 5\)'])
 	if m != 0:
 		raise Exception('SHIFT+ALT+FN 5 failed in \'text input\' test')
 	u_boot_console.drain_console()
diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py
index e3210ed..356d9a2 100755
--- a/test/py/tests/test_fit.py
+++ b/test/py/tests/test_fit.py
@@ -3,8 +3,6 @@
 #
 # Sanity check of the FIT handling in U-Boot
 
-from __future__ import print_function
-
 import os
 import pytest
 import struct
@@ -155,7 +153,7 @@
         src = make_fname('u-boot.dts')
         dtb = make_fname('u-boot.dtb')
         with open(src, 'w') as fd:
-            print(base_fdt, file=fd)
+            fd.write(base_fdt)
         util.run_and_log(cons, ['dtc', src, '-O', 'dtb', '-o', dtb])
         return dtb
 
@@ -188,7 +186,7 @@
         its = make_its(params)
         util.run_and_log(cons, [mkimage, '-f', its, fit])
         with open(make_fname('u-boot.dts'), 'w') as fd:
-            print(base_fdt, file=fd)
+            fd.write(base_fdt)
         return fit
 
     def make_kernel(filename, text):
diff --git a/test/py/tests/test_fpga.py b/test/py/tests/test_fpga.py
index e3bb7b4..ca7ef8e 100644
--- a/test/py/tests/test_fpga.py
+++ b/test/py/tests/test_fpga.py
@@ -175,29 +175,29 @@
     f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'bitstream_load')
 
     for cmd in ['dump', 'load', 'loadb']:
-	# missing dev parameter
-	expected = 'fpga: incorrect parameters passed'
-	output = u_boot_console.run_command('fpga %s %x $filesize' % (cmd, addr))
-	#assert expected in output
-	assert expected_usage in output
+        # missing dev parameter
+        expected = 'fpga: incorrect parameters passed'
+        output = u_boot_console.run_command('fpga %s %x $filesize' % (cmd, addr))
+        #assert expected in output
+        assert expected_usage in output
 
-	# more parameters - 0 at the end
-	expected = 'fpga: more parameters passed'
-	output = u_boot_console.run_command('fpga %s %x %x $filesize 0' % (cmd, dev, addr))
-	#assert expected in output
-	assert expected_usage in output
+        # more parameters - 0 at the end
+        expected = 'fpga: more parameters passed'
+        output = u_boot_console.run_command('fpga %s %x %x $filesize 0' % (cmd, dev, addr))
+        #assert expected in output
+        assert expected_usage in output
 
-	# 0 address
-	expected = 'fpga: zero fpga_data address'
-	output = u_boot_console.run_command('fpga %s %x 0 $filesize' % (cmd, dev))
-	#assert expected in output
-	assert expected_usage in output
+        # 0 address
+        expected = 'fpga: zero fpga_data address'
+        output = u_boot_console.run_command('fpga %s %x 0 $filesize' % (cmd, dev))
+        #assert expected in output
+        assert expected_usage in output
 
-	# 0 filesize
-	expected = 'fpga: zero size'
-	output = u_boot_console.run_command('fpga %s %x %x 0' % (cmd, dev, addr))
-	#assert expected in output
-	assert expected_usage in output
+        # 0 filesize
+        expected = 'fpga: zero size'
+        output = u_boot_console.run_command('fpga %s %x %x 0' % (cmd, dev, addr))
+        #assert expected in output
+        assert expected_usage in output
 
 @pytest.mark.buildconfigspec('cmd_fpga')
 @pytest.mark.buildconfigspec('cmd_echo')
diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py
index 9324657..1949f91 100644
--- a/test/py/tests/test_fs/conftest.py
+++ b/test/py/tests/test_fs/conftest.py
@@ -300,38 +300,38 @@
         # Generate the md5sums of reads that we will test against small file
         out = check_output(
             'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
-	    % small_file, shell=True)
+	    % small_file, shell=True).decode()
         md5val = [ out.split()[0] ]
 
         # Generate the md5sums of reads that we will test against big file
         # One from beginning of file.
         out = check_output(
             'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
-	    % big_file, shell=True)
+	    % big_file, shell=True).decode()
         md5val.append(out.split()[0])
 
         # One from end of file.
         out = check_output(
             'dd if=%s bs=1M skip=2499 count=1 2> /dev/null | md5sum'
-	    % big_file, shell=True)
+	    % big_file, shell=True).decode()
         md5val.append(out.split()[0])
 
         # One from the last 1MB chunk of 2GB
         out = check_output(
             'dd if=%s bs=1M skip=2047 count=1 2> /dev/null | md5sum'
-	    % big_file, shell=True)
+	    % big_file, shell=True).decode()
         md5val.append(out.split()[0])
 
         # One from the start 1MB chunk from 2GB
         out = check_output(
             'dd if=%s bs=1M skip=2048 count=1 2> /dev/null | md5sum'
-	    % big_file, shell=True)
+	    % big_file, shell=True).decode()
         md5val.append(out.split()[0])
 
         # One 1MB chunk crossing the 2GB boundary
         out = check_output(
             'dd if=%s bs=512K skip=4095 count=2 2> /dev/null | md5sum'
-	    % big_file, shell=True)
+	    % big_file, shell=True).decode()
         md5val.append(out.split()[0])
 
         umount_fs(mount_dir)
@@ -390,7 +390,7 @@
             % min_file, shell=True)
         out = check_output(
             'dd if=%s bs=1K 2> /dev/null | md5sum'
-            % min_file, shell=True)
+            % min_file, shell=True).decode()
         md5val = [ out.split()[0] ]
 
         # Calculate md5sum of Test Case 4
@@ -399,7 +399,7 @@
         check_call('dd if=%s of=%s bs=1K seek=5 count=20'
             % (min_file, tmp_file), shell=True)
         out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
-            % tmp_file, shell=True)
+            % tmp_file, shell=True).decode()
         md5val.append(out.split()[0])
 
         # Calculate md5sum of Test Case 5
@@ -408,7 +408,7 @@
         check_call('dd if=%s of=%s bs=1K seek=5 count=5'
             % (min_file, tmp_file), shell=True)
         out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
-            % tmp_file, shell=True)
+            % tmp_file, shell=True).decode()
         md5val.append(out.split()[0])
 
         # Calculate md5sum of Test Case 7
@@ -417,7 +417,7 @@
         check_call('dd if=%s of=%s bs=1K seek=20 count=20'
             % (min_file, tmp_file), shell=True)
         out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
-            % tmp_file, shell=True)
+            % tmp_file, shell=True).decode()
         md5val.append(out.split()[0])
 
         check_call('rm %s' % tmp_file, shell=True)
@@ -508,8 +508,8 @@
 
         # Test Case 2
         check_call('mkdir %s/dir2' % mount_dir, shell=True)
-	for i in range(0, 20):
-	    check_call('mkdir %s/dir2/0123456789abcdef%02x'
+        for i in range(0, 20):
+            check_call('mkdir %s/dir2/0123456789abcdef%02x'
                                     % (mount_dir, i), shell=True)
 
         # Test Case 4
@@ -582,11 +582,11 @@
         # Generate the md5sums of reads that we will test against small file
         out = check_output(
             'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
-            % small_file, shell=True)
+            % small_file, shell=True).decode()
         md5val = [out.split()[0]]
         out = check_output(
             'dd if=%s bs=10M skip=0 count=1 2> /dev/null | md5sum'
-            % medium_file, shell=True)
+            % medium_file, shell=True).decode()
         md5val.extend([out.split()[0]])
 
         umount_fs(mount_dir)
diff --git a/test/py/tests/test_log.py b/test/py/tests/test_log.py
index cb18344..75325fa 100644
--- a/test/py/tests/test_log.py
+++ b/test/py/tests/test_log.py
@@ -27,9 +27,9 @@
         """
         for i in range(max_level):
             if mask & 1:
-                assert 'log_run() log %d' % i == lines.next()
+                assert 'log_run() log %d' % i == next(lines)
             if mask & 3:
-                assert 'func() _log %d' % i == lines.next()
+                assert 'func() _log %d' % i == next(lines)
 
     def run_test(testnum):
         """Run a particular test number (the 'log test' command)
@@ -43,7 +43,7 @@
            output = u_boot_console.run_command('log test %d' % testnum)
         split = output.replace('\r', '').splitlines()
         lines = iter(split)
-        assert 'test %d' % testnum == lines.next()
+        assert 'test %d' % testnum == next(lines)
         return lines
 
     def test0():
@@ -88,7 +88,7 @@
     def test10():
         lines = run_test(10)
         for i in range(7):
-            assert 'log_test() level %d' % i == lines.next()
+            assert 'log_test() level %d' % i == next(lines)
 
     # TODO(sjg@chromium.org): Consider structuring this as separate tests
     cons = u_boot_console
diff --git a/test/py/tests/test_mmc_wr.py b/test/py/tests/test_mmc_wr.py
index 8b18781..05e5c1e 100644
--- a/test/py/tests/test_mmc_wr.py
+++ b/test/py/tests/test_mmc_wr.py
@@ -35,7 +35,9 @@
 
 """
 
-@pytest.mark.buildconfigspec('cmd_mmc','cmd_memory', 'cmd_random')
+@pytest.mark.buildconfigspec('cmd_mmc')
+@pytest.mark.buildconfigspec('cmd_memory')
+@pytest.mark.buildconfigspec('cmd_random')
 def test_mmc_wr(u_boot_console, env__mmc_wr_config):
     """Test the "mmc write" command.
 
@@ -65,41 +67,39 @@
 
 
     for i in range(test_iterations):
-	# Generate random data
-	cmd = 'random %s %x' % (src_addr, count_bytes)
-	response = u_boot_console.run_command(cmd)
-	good_response = '%d bytes filled with random data' % (count_bytes)
-	assert good_response in response
+        # Generate random data
+        cmd = 'random %s %x' % (src_addr, count_bytes)
+        response = u_boot_console.run_command(cmd)
+        good_response = '%d bytes filled with random data' % (count_bytes)
+        assert good_response in response
 
-	# Select MMC device
-	cmd = 'mmc dev %d' % devid
-	if is_emmc:
-		cmd += ' %d' % partid
-	response = u_boot_console.run_command(cmd)
-	assert 'no card present' not in response
-	if is_emmc:
-		partid_response = "(part %d)" % partid
-	else:
-		partid_response = ""
-	good_response = 'mmc%d%s is current device' % (devid, partid_response)
-	assert good_response in response
+        # Select MMC device
+        cmd = 'mmc dev %d' % devid
+        if is_emmc:
+            cmd += ' %d' % partid
+        response = u_boot_console.run_command(cmd)
+        assert 'no card present' not in response
+        if is_emmc:
+            partid_response = "(part %d)" % partid
+        else:
+            partid_response = ""
+        good_response = 'mmc%d%s is current device' % (devid, partid_response)
+        assert good_response in response
 
-	# Write data
-	cmd = 'mmc write %s %x %x' % (src_addr, sector, count_sectors)
-	response = u_boot_console.run_command(cmd)
-	good_response = 'MMC write: dev # %d, block # %d, count %d ... %d blocks written: OK' % (
-		devid, sector, count_sectors, count_sectors)
-	assert good_response in response
+        # Write data
+        cmd = 'mmc write %s %x %x' % (src_addr, sector, count_sectors)
+        response = u_boot_console.run_command(cmd)
+        good_response = 'MMC write: dev # %d, block # %d, count %d ... %d blocks written: OK' % (devid, sector, count_sectors, count_sectors)
+        assert good_response in response
 
-	# Read data
-	cmd = 'mmc read %s %x %x' % (dst_addr, sector, count_sectors)
-	response = u_boot_console.run_command(cmd)
-	good_response = 'MMC read: dev # %d, block # %d, count %d ... %d blocks read: OK' % (
-		devid, sector, count_sectors, count_sectors)
-	assert good_response in response
+        # Read data
+        cmd = 'mmc read %s %x %x' % (dst_addr, sector, count_sectors)
+        response = u_boot_console.run_command(cmd)
+        good_response = 'MMC read: dev # %d, block # %d, count %d ... %d blocks read: OK' % (devid, sector, count_sectors, count_sectors)
+        assert good_response in response
 
-	# Compare src and dst data
-	cmd = 'cmp.b %s %s %x' % (src_addr, dst_addr, count_bytes)
-	response = u_boot_console.run_command(cmd)
-	good_response = 'Total of %d byte(s) were the same' % (count_bytes)
-	assert good_response in response
+        # Compare src and dst data
+        cmd = 'cmp.b %s %s %x' % (src_addr, dst_addr, count_bytes)
+        response = u_boot_console.run_command(cmd)
+        good_response = 'Total of %d byte(s) were the same' % (count_bytes)
+        assert good_response in response
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py
index 62037d2..6c7b8dd 100644
--- a/test/py/tests/test_ut.py
+++ b/test/py/tests/test_ut.py
@@ -10,14 +10,14 @@
 
     fn = u_boot_console.config.source_dir + '/testflash.bin'
     if not os.path.exists(fn):
-        data = 'this is a test'
-        data += '\x00' * ((4 * 1024 * 1024) - len(data))
+        data = b'this is a test'
+        data += b'\x00' * ((4 * 1024 * 1024) - len(data))
         with open(fn, 'wb') as fh:
             fh.write(data)
 
     fn = u_boot_console.config.source_dir + '/spi.bin'
     if not os.path.exists(fn):
-        data = '\x00' * (2 * 1024 * 1024)
+        data = b'\x00' * (2 * 1024 * 1024)
         with open(fn, 'wb') as fh:
             fh.write(data)
 
diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py
index b011a3e..6991b78 100644
--- a/test/py/u_boot_spawn.py
+++ b/test/py/u_boot_spawn.py
@@ -42,10 +42,7 @@
         self.after = ''
         self.timeout = None
         # http://stackoverflow.com/questions/7857352/python-regex-to-match-vt100-escape-sequences
-        # Note that re.I doesn't seem to work with this regex (or perhaps the
-        # version of Python in Ubuntu 14.04), hence the inclusion of a-z inside
-        # [] instead.
-        self.re_vt100 = re.compile('(\x1b\[|\x9b)[^@-_a-z]*[@-_a-z]|\x1b[@-_a-z]')
+        self.re_vt100 = re.compile(r'(\x1b\[|\x9b)[^@-_]*[@-_]|\x1b[@-_]', re.I)
 
         (self.pid, self.fd) = pty.fork()
         if self.pid == 0:
@@ -113,7 +110,7 @@
             Nothing.
         """
 
-        os.write(self.fd, data)
+        os.write(self.fd, data.encode(errors='replace'))
 
     def expect(self, patterns):
         """Wait for the sub-process to emit specific data.
@@ -171,7 +168,7 @@
                 events = self.poll.poll(poll_maxwait)
                 if not events:
                     raise Timeout()
-                c = os.read(self.fd, 1024)
+                c = os.read(self.fd, 1024).decode(errors='replace')
                 if not c:
                     raise EOFError()
                 if self.logfile_read:
diff --git a/tools/.gitignore b/tools/.gitignore
index bd03d32..d0176a7 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -31,4 +31,5 @@
 /spl_size_limit
 /sunxi-spl-image-builder
 /ubsha1
+/version.h
 /xway-swap-bytes
diff --git a/tools/buildman/control.py b/tools/buildman/control.py
index fcf531c..9787b86 100644
--- a/tools/buildman/control.py
+++ b/tools/buildman/control.py
@@ -201,14 +201,14 @@
 
     # Work out what subset of the boards we are building
     if not boards:
-        board_file = os.path.join(options.git, 'boards.cfg')
-        status = subprocess.call([os.path.join(options.git,
-                                                'tools/genboardscfg.py')])
+        board_file = os.path.join(options.output_dir, 'boards.cfg')
+        genboardscfg = os.path.join(options.git, 'tools/genboardscfg.py')
+        status = subprocess.call([genboardscfg, '-o', board_file])
         if status != 0:
-                sys.exit("Failed to generate boards.cfg")
+            sys.exit("Failed to generate boards.cfg")
 
         boards = board.Boards()
-        boards.ReadBoards(os.path.join(options.git, 'boards.cfg'))
+        boards.ReadBoards(board_file)
 
     exclude = []
     if options.exclude:
diff --git a/tools/buildman/test.py b/tools/buildman/test.py
index de02f61..ed99b93 100644
--- a/tools/buildman/test.py
+++ b/tools/buildman/test.py
@@ -156,14 +156,6 @@
             result.return_code = commit.return_code
             result.stderr = (''.join(commit.error_list)
                 % {'basedir' : base_dir + '/.bm-work/00/'})
-        if stage == 'build':
-            target_dir = None
-            for arg in args:
-                if arg.startswith('O='):
-                    target_dir = arg[2:]
-
-            if not os.path.isdir(target_dir):
-                os.mkdir(target_dir)
 
         result.combined = result.stdout + result.stderr
         return result
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 5aca634..0201cc4 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -229,6 +229,7 @@
 	for (cont = params->content_head; cont; cont = cont->next) {
 		if (cont->type != IH_TYPE_FLATDT)
 			continue;
+		typename = genimg_get_type_short_name(cont->type);
 		snprintf(str, sizeof(str), "%s-%d", FIT_FDT_PROP, ++upto);
 		fdt_begin_node(fdt, str);
 
@@ -253,6 +254,8 @@
 		fdt_property_string(fdt, FIT_TYPE_PROP, FIT_RAMDISK_PROP);
 		fdt_property_string(fdt, FIT_OS_PROP,
 				    genimg_get_os_short_name(params->os));
+		fdt_property_string(fdt, FIT_ARCH_PROP,
+				    genimg_get_arch_short_name(params->arch));
 
 		ret = fdt_property_file(params, fdt, FIT_DATA_PROP,
 					params->fit_ramdisk);
diff --git a/tools/ifwitool.c b/tools/ifwitool.c
index 2e020a8..543e9d4 100644
--- a/tools/ifwitool.c
+++ b/tools/ifwitool.c
@@ -10,7 +10,9 @@
 #include <getopt.h>
 #include "os_support.h"
 
+#ifndef __packed
 #define __packed		__attribute__((packed))
+#endif
 #define KiB			1024
 #define ALIGN(x, a)		__ALIGN_MASK((x), (typeof(x))(a) - 1)
 #define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
diff --git a/tools/mtk_image.h b/tools/mtk_image.h
index 0a9eab3..4e78b3d 100644
--- a/tools/mtk_image.h
+++ b/tools/mtk_image.h
@@ -9,14 +9,14 @@
 #ifndef _MTK_IMAGE_H
 #define _MTK_IMAGE_H
 
-/* Device header definitions */
+/* Device header definitions, all fields are little-endian */
 
 /* Header for NOR/SD/eMMC */
 union gen_boot_header {
 	struct {
 		char name[12];
-		__le32 version;
-		__le32 size;
+		uint32_t version;
+		uint32_t size;
 	};
 
 	uint8_t pad[0x200];
@@ -32,14 +32,14 @@
 		char name[12];
 		char version[4];
 		char id[8];
-		__le16 ioif;
-		__le16 pagesize;
-		__le16 addrcycles;
-		__le16 oobsize;
-		__le16 pages_of_block;
-		__le16 numblocks;
-		__le16 writesize_shift;
-		__le16 erasesize_shift;
+		uint16_t ioif;
+		uint16_t pagesize;
+		uint16_t addrcycles;
+		uint16_t oobsize;
+		uint16_t pages_of_block;
+		uint16_t numblocks;
+		uint16_t writesize_shift;
+		uint16_t erasesize_shift;
 		uint8_t dummy[60];
 		uint8_t ecc_parity[28];
 	};
@@ -54,14 +54,14 @@
 /* BootROM layout header */
 struct brom_layout_header {
 	char name[8];
-	__le32 version;
-	__le32 header_size;
-	__le32 total_size;
-	__le32 magic;
-	__le32 type;
-	__le32 header_size_2;
-	__le32 total_size_2;
-	__le32 unused;
+	uint32_t version;
+	uint32_t header_size;
+	uint32_t total_size;
+	uint32_t magic;
+	uint32_t type;
+	uint32_t header_size_2;
+	uint32_t total_size_2;
+	uint32_t unused;
 };
 
 #define BRLYT_NAME		"BRLYT"
@@ -90,8 +90,8 @@
 struct gfh_common_header {
 	uint8_t magic[3];
 	uint8_t version;
-	__le16 size;
-	__le16 type;
+	uint16_t size;
+	uint16_t type;
 };
 
 #define GFH_HEADER_MAGIC	"MMM"
@@ -106,17 +106,17 @@
 struct gfh_file_info {
 	struct gfh_common_header gfh;
 	char name[12];
-	__le32 unused;
-	__le16 file_type;
+	uint32_t unused;
+	uint16_t file_type;
 	uint8_t flash_type;
 	uint8_t sig_type;
-	__le32 load_addr;
-	__le32 total_size;
-	__le32 max_size;
-	__le32 hdr_size;
-	__le32 sig_size;
-	__le32 jump_offset;
-	__le32 processed;
+	uint32_t load_addr;
+	uint32_t total_size;
+	uint32_t max_size;
+	uint32_t hdr_size;
+	uint32_t sig_size;
+	uint32_t jump_offset;
+	uint32_t processed;
 };
 
 #define GFH_FILE_INFO_NAME	"FILE_INFO"
@@ -129,16 +129,16 @@
 
 struct gfh_bl_info {
 	struct gfh_common_header gfh;
-	__le32 attr;
+	uint32_t attr;
 };
 
 struct gfh_brom_cfg {
 	struct gfh_common_header gfh;
-	__le32 cfg_bits;
-	__le32 usbdl_by_auto_detect_timeout_ms;
+	uint32_t cfg_bits;
+	uint32_t usbdl_by_auto_detect_timeout_ms;
 	uint8_t unused[0x48];
-	__le32 usbdl_by_kcol0_timeout_ms;
-	__le32 usbdl_by_flag_timeout_ms;
+	uint32_t usbdl_by_kcol0_timeout_ms;
+	uint32_t usbdl_by_flag_timeout_ms;
 	uint32_t pad;
 };
 
@@ -157,15 +157,15 @@
 	uint8_t ac_b2k;
 	uint8_t ac_b2c;
 	uint16_t pad;
-	__le32 ac_offset;
-	__le32 ac_len;
+	uint32_t ac_offset;
+	uint32_t ac_len;
 };
 
 struct gfh_brom_sec_cfg {
 	struct gfh_common_header gfh;
-	__le32 cfg_bits;
+	uint32_t cfg_bits;
 	char customer_name[0x20];
-	__le32 pad;
+	uint32_t pad;
 };
 
 #define BROM_SEC_CFG_JTAG_EN	1
@@ -184,11 +184,11 @@
 
 union lk_hdr {
 	struct {
-		__le32 magic;
-		__le32 size;
+		uint32_t magic;
+		uint32_t size;
 		char name[32];
-		__le32 loadaddr;
-		__le32 mode;
+		uint32_t loadaddr;
+		uint32_t mode;
 	};
 
 	uint8_t data[512];
diff --git a/tools/patman/func_test.py b/tools/patman/func_test.py
index 50a2741..2321f9e 100644
--- a/tools/patman/func_test.py
+++ b/tools/patman/func_test.py
@@ -198,9 +198,9 @@
         line += 4
         self.assertEqual(expected, tools.ToUnicode(lines[line]))
 
-        self.assertEqual(('%s %s, %s' % (args[0], rick, stefan)),
+        self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)),
                          tools.ToUnicode(cc_lines[0]))
-        self.assertEqual(('%s %s, %s, %s, %s' % (args[1], fred, ed, rick,
+        self.assertEqual(('%s %s\0%s\0%s\0%s' % (args[1], fred, ed, rick,
                                      stefan)), tools.ToUnicode(cc_lines[1]))
 
         expected = '''
diff --git a/tools/patman/patman.py b/tools/patman/patman.py
index 9605a36..0187ebe 100755
--- a/tools/patman/patman.py
+++ b/tools/patman/patman.py
@@ -112,7 +112,7 @@
     for line in fd.readlines():
         match = re_line.match(line)
         if match and match.group(1) == args[0]:
-            for cc in match.group(2).split(', '):
+            for cc in match.group(2).split('\0'):
                 cc = cc.strip()
                 if cc:
                     print(cc)
diff --git a/tools/patman/series.py b/tools/patman/series.py
index 67103f0..d667d9b 100644
--- a/tools/patman/series.py
+++ b/tools/patman/series.py
@@ -243,13 +243,13 @@
             if limit is not None:
                 cc = cc[:limit]
             all_ccs += cc
-            print(commit.patch, ', '.join(sorted(set(cc))), file=fd)
+            print(commit.patch, '\0'.join(sorted(set(cc))), file=fd)
             self._generated_cc[commit.patch] = cc
 
         if cover_fname:
             cover_cc = gitutil.BuildEmailList(self.get('cover_cc', ''))
             cover_cc = [tools.FromUnicode(m) for m in cover_cc]
-            cc_list = ', '.join([tools.ToUnicode(x)
+            cc_list = '\0'.join([tools.ToUnicode(x)
                                  for x in sorted(set(cover_cc + all_ccs))])
             print(cover_fname, cc_list.encode('utf-8'), file=fd)
 
diff --git a/tools/version.h b/tools/version.h
deleted file mode 120000
index bb57607..0000000
--- a/tools/version.h
+++ /dev/null
@@ -1 +0,0 @@
-../include/version.h
\ No newline at end of file
diff --git a/tools/zynqmpbif.c b/tools/zynqmpbif.c
index 8c47107..82ce0ac 100644
--- a/tools/zynqmpbif.c
+++ b/tools/zynqmpbif.c
@@ -517,7 +517,7 @@
 	debug("Bitstream Length: 0x%x\n", bitlen);
 	for (i = 0; i < bitlen; i += sizeof(uint32_t)) {
 		uint32_t *bitbin32 = (uint32_t *)&bitbin[i];
-		*bitbin32 = __swab32(*bitbin32);
+		*bitbin32 = __builtin_bswap32(*bitbin32);
 	}
 
 	if (!bf->dest_dev)