Merge branch 'master' of https://gitlab.denx.de/u-boot/custodians/u-boot-spi
- fix for fsl_qspi read timeout (Thomas)
- spi-mem read data size fix (Ye Li)
- SiFive SPI driver, mmc_spi flags (Bhargav, Anup)
- Micron spi-nor parts (Ashish)
- MT7629 spi-mem driver(Weijie)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..95fc689
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,364 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+# Grab our configured image. The source for this is found at:
+# https://gitlab.denx.de/u-boot/gitlab-ci-runner
+image: trini/u-boot-gitlab-ci-runner:xenial-20190720-24Jul2019
+
+# We run some tests in different order, to catch some failures quicker.
+stages:
+ - test.py
+ - testsuites
+ - world build
+
+.buildman_and_testpy_template: &buildman_and_testpy_dfn
+ tags: [ 'all' ]
+ stage: test.py
+ before_script:
+ # Clone uboot-test-hooks
+ - git clone --depth=1 git://github.com/swarren/uboot-test-hooks.git /tmp/uboot-test-hooks
+ - ln -s travis-ci /tmp/uboot-test-hooks/bin/`hostname`
+ - ln -s travis-ci /tmp/uboot-test-hooks/py/`hostname`
+ - virtualenv /tmp/venv
+ - . /tmp/venv/bin/activate
+ - pip install pytest==2.8.7
+ - pip install python-subunit
+ - grub-mkimage -o ~/grub_x86.efi -O i386-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd
+ - grub-mkimage -o ~/grub_x64.efi -O x86_64-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd
+ - mkdir ~/grub2-arm
+ - ( cd ~/grub2-arm; wget -O - http://download.opensuse.org/ports/armv7hl/distribution/leap/42.2/repo/oss/suse/armv7hl/grub2-arm-efi-2.02~beta2-87.1.armv7hl.rpm | rpm2cpio | cpio -di )
+ - mkdir ~/grub2-arm64
+ - ( cd ~/grub2-arm64; wget -O - http://download.opensuse.org/ports/aarch64/distribution/leap/42.2/repo/oss/suse/aarch64/grub2-arm64-efi-2.02~beta2-87.1.aarch64.rpm | rpm2cpio | cpio -di )
+ - if [[ "${QEMU_TARGET}" != "" ]]; then
+ git clone git://git.qemu.org/qemu.git /tmp/qemu;
+ pushd /tmp/qemu;
+ git submodule update --init dtc &&
+ git checkout ${QEMU_VERSION} &&
+ ./configure --prefix=/tmp/qemu-install --target-list=${QEMU_TARGET} &&
+ make -j$(nproc) all install;
+ popd;
+ fi
+ after_script:
+ - rm -rf ~/grub2* /tmp/uboot-test-hooks /tmp/qemu /tmp/venv
+ script:
+ # From buildman, exit code 129 means warnings only. If we've been asked to
+ # use clang only do one configuration.
+ - if [[ "${BUILDMAN}" != "" ]]; then
+ ret=0;
+ tools/buildman/buildman -P -E ${BUILDMAN} ${OVERRIDE}|| ret=$?;
+ if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+ tools/buildman/buildman -sdeP ${BUILDMAN};
+ exit $ret;
+ fi;
+ fi
+ # "not a_test_which_does_not_exist" is a dummy -k parameter which will
+ # never prevent any test from running. That way, we can always pass
+ # "-k something" even when $TEST_PY_TEST_SPEC doesnt need a custom
+ # value.
+ - export UBOOT_TRAVIS_BUILD_DIR=`cd .. && pwd`/.bm-work/${TEST_PY_BD};
+ export PATH=/tmp/qemu-install/bin:/tmp/uboot-test-hooks/bin:/usr/bin:/bin;
+ export PYTHONPATH=/tmp/uboot-test-hooks/py/travis-ci;
+ if [[ "${TEST_PY_BD}" != "" ]]; then
+ ./test/py/test.py --bd ${TEST_PY_BD} ${TEST_PY_ID}
+ -k "${TEST_PY_TEST_SPEC:-not a_test_which_does_not_exist}"
+ --build-dir "$UBOOT_TRAVIS_BUILD_DIR";
+ ret=$?;
+ if [[ $ret -ne 0 ]]; then
+ exit $ret;
+ fi;
+ fi;
+
+build all 32bit ARM plaforms:
+ tags: [ 'all' ]
+ stage: world build
+ script:
+ - ret=0;
+ ./tools/buildman/buildman -P -E arm -x aarch64 || ret=$?;
+ if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+ ./tools/buildman/buildman -sdeP;
+ exit $ret;
+ fi;
+
+build all 64bit ARM plaforms:
+ tags: [ 'all' ]
+ stage: world build
+ script:
+ - virtualenv /tmp/venv
+ - . /tmp/venv/bin/activate
+ - pip install pyelftools
+ - ret=0;
+ ./tools/buildman/buildman -P -E aarch64 || ret=$?;
+ if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+ ./tools/buildman/buildman -sdeP;
+ exit $ret;
+ fi;
+
+build all PowerPC plaforms:
+ tags: [ 'all' ]
+ stage: world build
+ script:
+ - ret=0;
+ ./tools/buildman/buildman -P -E powerpc || ret=$?;
+ if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+ ./tools/buildman/buildman -sdeP;
+ exit $ret;
+ fi;
+
+build all other plaforms:
+ tags: [ 'all' ]
+ stage: world build
+ script:
+ - ret=0;
+ ./tools/buildman/buildman -P -E -x arm,powerpc || ret=$?;
+ if [[ $ret -ne 0 && $ret -ne 129 ]]; then
+ ./tools/buildman/buildman -sdeP;
+ exit $ret;
+ fi;
+
+# QA jobs for code analytics
+# static code analysis with cppcheck (we can add --enable=all later)
+cppcheck:
+ tags: [ 'all' ]
+ stage: testsuites
+ script:
+ - cppcheck --force --quiet --inline-suppr .
+
+# search for TODO within source tree
+grep TODO/FIXME/HACK:
+ tags: [ 'all' ]
+ stage: testsuites
+ script:
+ - grep -r TODO .
+ - grep -r FIXME .
+ # search for HACK within source tree and ignore HACKKIT board
+ - grep -r HACK . | grep -v HACKKIT
+
+# some statistics about the code base
+sloccount:
+ tags: [ 'all' ]
+ stage: testsuites
+ script:
+ - sloccount .
+
+# ensure all configs have MAINTAINERS entries
+Check for configs without MAINTAINERS entry:
+ tags: [ 'all' ]
+ stage: testsuites
+ script:
+ - if [ `./tools/genboardscfg.py -f 2>&1 | wc -l` -ne 0 ]; then exit 1; fi
+
+# Ensure host tools build
+Build tools-only:
+ tags: [ 'all' ]
+ stage: testsuites
+ script:
+ - make tools-only_config tools-only -j$(nproc)
+
+# Run various tool tests
+Run patman testsuite:
+ tags: [ 'all' ]
+ stage: testsuites
+ script:
+ - git config --global user.name "GitLab CI Runner"
+ - git config --global user.email trini@konsulko.com
+ - ./tools/patman/patman --test
+
+Run buildman testsuite:
+ tags: [ 'all' ]
+ stage: testsuites
+ script:
+ - ./tools/buildman/buildman -t
+
+Run binman and dtoc testsuite:
+ tags: [ 'all' ]
+ stage: testsuites
+ script:
+ - virtualenv /tmp/venv
+ - . /tmp/venv/bin/activate
+ - pip install pyelftools
+ - export UBOOT_TRAVIS_BUILD_DIR=`cd .. && pwd`/.bm-work/sandbox_spl;
+ ./tools/buildman/buildman -P sandbox_spl &&
+ export PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt";
+ export PATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}";
+ ./tools/binman/binman --toolpath ${UBOOT_TRAVIS_BUILD_DIR}/tools test &&
+ ./tools/dtoc/dtoc -t
+
+# Test sandbox with test.py
+sandbox test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "sandbox"
+ BUILDMAN: "^sandbox$"
+ <<: *buildman_and_testpy_dfn
+
+sandbox_spl test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "sandbox_spl"
+ BUILDMAN: "^sandbox_spl$"
+ TEST_PY_TEST_SPEC: "test_ofplatdata"
+ <<: *buildman_and_testpy_dfn
+
+evb-ast2500 test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "evb-ast2500"
+ TEST_PY_ID: "--id qemu"
+ QEMU_TARGET: "arm-softmmu"
+ QEMU_VERSION: "506179e42112be77bfd071f050b15762d3b2cd43"
+ BUILDMAN: "^evb-ast2500$"
+ <<: *buildman_and_testpy_dfn
+
+sandbox_flattree test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "sandbox_flattree"
+ BUILDMAN: "^sandbox_flattree$"
+ <<: *buildman_and_testpy_dfn
+
+vexpress_ca15_tc2 test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "vexpress_ca15_tc2"
+ TEST_PY_ID: "--id qemu"
+ QEMU_TARGET: "arm-softmmu"
+ QEMU_VERSION: "v3.0.0"
+ BUILDMAN: "^vexpress_ca15_tc2$"
+ <<: *buildman_and_testpy_dfn
+
+vexpress_ca9x4 test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "vexpress_ca9x4"
+ TEST_PY_ID: "--id qemu"
+ QEMU_TARGET: "arm-softmmu"
+ BUILDMAN: "^vexpress_ca9x4$"
+ <<: *buildman_and_testpy_dfn
+
+integratorcp_cm926ejs test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "integratorcp_cm926ejs"
+ TEST_PY_TEST_SPEC: "not sleep"
+ TEST_PY_ID: "--id qemu"
+ QEMU_TARGET: "arm-softmmu"
+ BUILDMAN: "^integratorcp_cm926ejs$"
+ <<: *buildman_and_testpy_dfn
+
+qemu_arm test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "qemu_arm"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "arm-softmmu"
+ BUILDMAN: "^qemu_arm$"
+ <<: *buildman_and_testpy_dfn
+
+qemu_arm64 test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "qemu_arm64"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "aarch64-softmmu"
+ BUILDMAN: "^qemu_arm64$"
+ <<: *buildman_and_testpy_dfn
+
+qemu_mips test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "qemu_mips"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "mips-softmmu"
+ BUILDMAN: "^qemu_mips$"
+ TOOLCHAIN: "mips"
+ <<: *buildman_and_testpy_dfn
+
+qemu_mipsel test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "qemu_mipsel"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "mipsel-softmmu"
+ BUILDMAN: "^qemu_mipsel$"
+ TOOLCHAIN: "mips"
+ <<: *buildman_and_testpy_dfn
+
+qemu_mips64 test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "qemu_mips64"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "mips64-softmmu"
+ BUILDMAN: "^qemu_mips64$"
+ TOOLCHAIN: "mips"
+ <<: *buildman_and_testpy_dfn
+
+qemu_mips64el test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "qemu_mips64el"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "mips64el-softmmu"
+ BUILDMAN: "^qemu_mips64el$"
+ TOOLCHAIN: "mips"
+ <<: *buildman_and_testpy_dfn
+
+qemu-ppce500 test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "qemu-ppce500"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "ppc-softmmu"
+ BUILDMAN: "^qemu-ppce500$"
+ TOOLCHAIN: "powerpc"
+ <<: *buildman_and_testpy_dfn
+
+qemu-x86 test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "qemu-x86"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "i386-softmmu"
+ BUILDMAN: "^qemu-x86$"
+ TOOLCHAIN: "i386"
+ <<: *buildman_and_testpy_dfn
+
+qemu-x86_64 test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "qemu-x86_64"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "x86_64-softmmu"
+ BUILDMAN: "^qemu-x86_64$"
+ TOOLCHAIN: "i386"
+ <<: *buildman_and_testpy_dfn
+
+zynq_zc702 test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "zynq_zc702"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "arm-softmmu"
+ TEST_PY_ID: "--id qemu"
+ BUILDMAN: "^zynq_zc702$"
+ <<: *buildman_and_testpy_dfn
+
+xilinx_versal_virt test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "xilinx_versal_virt"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "aarch64-softmmu"
+ TEST_PY_ID: "--id qemu"
+ BUILDMAN: "^xilinx_versal_virt$"
+ <<: *buildman_and_testpy_dfn
+
+xtfpga test.py:
+ tags: [ 'all' ]
+ variables:
+ TEST_PY_BD: "xtfpga"
+ TEST_PY_TEST_SPEC: "not sleep"
+ QEMU_TARGET: "xtensa-softmmu"
+ TEST_PY_ID: "--id qemu"
+ BUILDMAN: "^xtfpga$"
+ TOOLCHAIN: "xtensa-dc233c-elf"
+ <<: *buildman_and_testpy_dfn
diff --git a/.travis.yml b/.travis.yml
index c21bbbb..38fc103 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,6 +32,7 @@
- device-tree-compiler
- lzop
- liblz4-tool
+ - lzma-alone
- libisl15
- clang-7
- srecord
@@ -146,7 +147,7 @@
if [[ -n "${TEST_PY_TOOLS}" ]]; then
PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt"
PATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}"
- ./tools/binman/binman -t &&
+ ./tools/binman/binman --toolpath ${UBOOT_TRAVIS_BUILD_DIR}/tools test &&
./tools/patman/patman --test &&
./tools/buildman/buildman -t &&
PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt"
@@ -365,13 +366,11 @@
- name: "test/py sandbox"
env:
- TEST_PY_BD="sandbox"
- TEST_PY_TEST_SPEC="not pci"
BUILDMAN="^sandbox$"
TOOLCHAIN="i386"
- name: "test/py sandbox with clang"
env:
- TEST_PY_BD="sandbox"
- TEST_PY_TEST_SPEC="not pci"
BUILDMAN="^sandbox$"
OVERRIDE="clang-7"
- name: "test/py sandbox_spl"
@@ -384,9 +383,15 @@
- name: "test/py sandbox_flattree"
env:
- TEST_PY_BD="sandbox_flattree"
- TEST_PY_TEST_SPEC="not pci"
BUILDMAN="^sandbox_flattree$"
TOOLCHAIN="i386"
+ - name: "test/py evb-ast2500"
+ env:
+ - TEST_PY_BD="evb-ast2500"
+ TEST_PY_ID="--id qemu"
+ QEMU_TARGET="arm-softmmu"
+ QEMU_VERSION="506179e42112be77bfd071f050b15762d3b2cd43"
+ BUILDMAN="^evb-ast2500$"
- name: "test/py vexpress_ca15_tc2"
env:
- TEST_PY_BD="vexpress_ca15_tc2"
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
index e74fec8..0d20b64 100644
--- a/Documentation/.gitignore
+++ b/Documentation/.gitignore
@@ -1,2 +1 @@
-output
*.pyc
diff --git a/MAINTAINERS b/MAINTAINERS
index e836f505..ffa8e7b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -311,6 +311,7 @@
F: drivers/power/regulator/stm32-vrefbuf.c
F: drivers/power/regulator/stpmic1.c
F: drivers/ram/stm32mp1/
+F: drivers/remoteproc/stm32_copro.c
F: drivers/misc/stm32_rcc.c
F: drivers/reset/stm32-reset.c
F: drivers/spi/stm32_qspi.c
@@ -606,7 +607,7 @@
F: drivers/mtd/nand/raw/
NDS32
-M: Macpaul Lin <macpaul@andestech.com>
+M: Rick Chen <rick@andestech.com>
S: Maintained
T: git https://gitlab.denx.de/u-boot/custodians/u-boot-nds32.git
F: arch/nds32/
@@ -616,6 +617,7 @@
S: Maintained
T: git https://gitlab.denx.de/u-boot/custodians/u-boot-net.git
F: drivers/net/
+F: include/net.h
F: net/
NIOS
diff --git a/Makefile b/Makefile
index 73fdf70..704579b 100644
--- a/Makefile
+++ b/Makefile
@@ -1196,9 +1196,9 @@
# ---------------------------------------------------------------------------
# Use 'make BINMAN_DEBUG=1' to enable debugging
quiet_cmd_binman = BINMAN $@
-cmd_binman = $(srctree)/tools/binman/binman -u -d u-boot.dtb -O . -m \
+cmd_binman = $(srctree)/tools/binman/binman build -u -d u-boot.dtb -O . -m \
-I . -I $(srctree) -I $(srctree)/board/$(BOARDDIR) \
- $(if $(BINMAN_DEBUG),-D) $(BINMAN_$(@F)) $<
+ $(if $(BINMAN_DEBUG),-D) $(BINMAN_$(@F))
OBJCOPYFLAGS_u-boot.ldr.hex := -I binary -O ihex
diff --git a/arch/Kconfig b/arch/Kconfig
index a946af8..949eb28 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -125,6 +125,7 @@
imply PCH
imply PHYLIB
imply DM_MDIO
+ imply DM_MDIO_MUX
config SH
bool "SuperH architecture"
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 05606d9..1cd7aeb 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -840,6 +840,7 @@
config ARCH_QEMU
bool "QEMU Virtual Platform"
+ select ARCH_SUPPORT_TFABOOT
select DM
select DM_SERIAL
select OF_CONTROL
@@ -1100,6 +1101,7 @@
select ARCH_MISC_INIT
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_LATE_INIT
select SUPPORT_SPL
select FSL_DDR_INTERACTIVE if !SD_BOOT
@@ -1115,6 +1117,7 @@
select ARCH_MISC_INIT
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_LATE_INIT
select SUPPORT_SPL
imply SCSI
@@ -1133,6 +1136,7 @@
select ARCH_MISC_INIT
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_LATE_INIT
select SUPPORT_SPL
select FSL_DDR_BIST
@@ -1165,6 +1169,7 @@
select ARCH_MISC_INIT
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_LATE_INIT
help
Support for NXP LX2160ARDB platform.
@@ -1178,6 +1183,7 @@
select ARCH_MISC_INIT
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_LATE_INIT
help
Support for NXP LX2160AQDS platform.
@@ -1218,6 +1224,7 @@
bool "Support ls1012aqds"
select ARCH_LS1012A
select ARM64
+ select ARCH_SUPPORT_TFABOOT
select BOARD_LATE_INIT
help
Support for Freescale LS1012AQDS platform.
@@ -1229,6 +1236,7 @@
bool "Support ls1012ardb"
select ARCH_LS1012A
select ARM64
+ select ARCH_SUPPORT_TFABOOT
select BOARD_LATE_INIT
imply SCSI
imply SCSI_AHCI
@@ -1242,6 +1250,7 @@
bool "Support ls1012a2g5rdb"
select ARCH_LS1012A
select ARM64
+ select ARCH_SUPPORT_TFABOOT
select BOARD_LATE_INIT
imply SCSI
help
@@ -1254,6 +1263,7 @@
bool "Support ls1012afrwy"
select ARCH_LS1012A
select ARM64
+ select ARCH_SUPPORT_TFABOOT
select BOARD_LATE_INIT
imply SCSI
imply SCSI_AHCI
@@ -1267,6 +1277,7 @@
bool "Support ls1012afrdm"
select ARCH_LS1012A
select ARM64
+ select ARCH_SUPPORT_TFABOOT
help
Support for Freescale LS1012AFRDM platform.
The LS1012A Freedom board (FRDM) is a high-performance
@@ -1278,6 +1289,7 @@
select ARCH_LS1028A
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
help
Support for Freescale LS1028AQDS platform
The LS1028A Development System (QDS) is a high-performance
@@ -1289,6 +1301,7 @@
select ARCH_LS1028A
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
help
Support for Freescale LS1028ARDB platform
The LS1028A Development System (RDB) is a high-performance
@@ -1301,6 +1314,7 @@
select ARCH_MISC_INIT
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_LATE_INIT
select SUPPORT_SPL
select FSL_DDR_INTERACTIVE if !SD_BOOT
@@ -1338,6 +1352,19 @@
select SUPPORT_SPL
imply SCSI
+config TARGET_LS1021ATSN
+ bool "Support ls1021atsn"
+ select ARCH_LS1021A
+ select ARCH_SUPPORT_PSCI
+ select BOARD_EARLY_INIT_F
+ select BOARD_LATE_INIT
+ select CPU_V7A
+ select CPU_V7_HAS_NONSEC
+ select CPU_V7_HAS_VIRT
+ select LS1_DEEP_SLEEP
+ select SUPPORT_SPL
+ imply SCSI
+
config TARGET_LS1021AIOT
bool "Support ls1021aiot"
select ARCH_LS1021A
@@ -1359,6 +1386,7 @@
select ARCH_LS1043A
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_EARLY_INIT_F
select BOARD_LATE_INIT
select SUPPORT_SPL
@@ -1373,6 +1401,7 @@
select ARCH_LS1043A
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_EARLY_INIT_F
select BOARD_LATE_INIT
select SUPPORT_SPL
@@ -1384,6 +1413,7 @@
select ARCH_LS1046A
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_EARLY_INIT_F
select BOARD_LATE_INIT
select DM_SPI_FLASH if DM_SPI
@@ -1403,6 +1433,7 @@
select ARCH_LS1046A
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_EARLY_INIT_F
select BOARD_LATE_INIT
select DM_SPI_FLASH if DM_SPI
@@ -1422,6 +1453,7 @@
select ARCH_LS1046A
select ARM64
select ARMV8_MULTIENTRY
+ select ARCH_SUPPORT_TFABOOT
select BOARD_EARLY_INIT_F
select BOARD_LATE_INIT
select DM_SPI_FLASH if DM_SPI
@@ -1565,6 +1597,17 @@
endchoice
+config ARCH_SUPPORT_TFABOOT
+ bool
+
+config TFABOOT
+ bool "Support for booting from TF-A"
+ depends on ARCH_SUPPORT_TFABOOT
+ default n
+ help
+ Enabling this will make a U-Boot binary that is capable of being
+ booted via TF-A.
+
config TI_SECURE_DEVICE
bool "HS Device Type Support"
depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_K3
@@ -1715,6 +1758,7 @@
source "board/freescale/ls1021aqds/Kconfig"
source "board/freescale/ls1043aqds/Kconfig"
source "board/freescale/ls1021atwr/Kconfig"
+source "board/freescale/ls1021atsn/Kconfig"
source "board/freescale/ls1021aiot/Kconfig"
source "board/freescale/ls1046aqds/Kconfig"
source "board/freescale/ls1043ardb/Kconfig"
diff --git a/arch/arm/cpu/armv7/ls102xa/cpu.c b/arch/arm/cpu/armv7/ls102xa/cpu.c
index ecf9e86..9ccfe10 100644
--- a/arch/arm/cpu/armv7/ls102xa/cpu.c
+++ b/arch/arm/cpu/armv7/ls102xa/cpu.c
@@ -296,7 +296,7 @@
int cpu_eth_init(bd_t *bis)
{
-#ifdef CONFIG_TSEC_ENET
+#if defined(CONFIG_TSEC_ENET) && !defined(CONFIG_DM_ETH)
tsec_standard_init(bis);
#endif
diff --git a/arch/arm/cpu/armv7/ls102xa/fdt.c b/arch/arm/cpu/armv7/ls102xa/fdt.c
index 8bf9c42..1aadfff 100644
--- a/arch/arm/cpu/armv7/ls102xa/fdt.c
+++ b/arch/arm/cpu/armv7/ls102xa/fdt.c
@@ -16,12 +16,17 @@
#include <tsec.h>
#include <asm/arch/immap_ls102xa.h>
#include <fsl_sec.h>
+#include <dm.h>
DECLARE_GLOBAL_DATA_PTR;
void ft_fixup_enet_phy_connect_type(void *fdt)
{
+#ifdef CONFIG_DM_ETH
+ struct udevice *dev;
+#else
struct eth_device *dev;
+#endif
struct tsec_private *priv;
const char *enet_path, *phy_path;
char enet[16];
@@ -29,7 +34,12 @@
int phy_node;
int i = 0;
uint32_t ph;
+#ifdef CONFIG_DM_ETH
+ char *name[3] = { "ethernet@2d10000", "ethernet@2d50000",
+ "ethernet@2d90000" };
+#else
char *name[3] = { "eTSEC1", "eTSEC2", "eTSEC3" };
+#endif
for (; i < ARRAY_SIZE(name); i++) {
dev = eth_get_dev_by_name(name[i]);
diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c
index f3e8f99..2c5d99e 100644
--- a/arch/arm/cpu/armv7/sunxi/psci.c
+++ b/arch/arm/cpu/armv7/sunxi/psci.c
@@ -276,7 +276,7 @@
return ARM_PSCI_RET_SUCCESS;
}
-void __secure psci_cpu_off(void)
+s32 __secure psci_cpu_off(void)
{
psci_cpu_off_common();
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig
index 3f6c983..5c32738 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig
+++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig
@@ -623,10 +623,3 @@
help
For some SoC(such as LS1043A and LS1046A), USB and QE-HDLC multiplex use
pins, select it when the pins are assigned to USB.
-
-config TFABOOT
- bool "Support for booting from TFA"
- default n
- help
- Enabling this will make a U-Boot binary that is capable of being
- booted via TFA.
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index f553507..e985884 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -328,7 +328,7 @@
dtb-$(CONFIG_ARCH_LS1021A) += ls1021a-qds-duart.dtb \
ls1021a-qds-lpuart.dtb \
ls1021a-twr-duart.dtb ls1021a-twr-lpuart.dtb \
- ls1021a-iot-duart.dtb
+ ls1021a-iot-duart.dtb ls1021a-tsn.dtb
dtb-$(CONFIG_FSL_LSCH3) += fsl-ls2080a-qds.dtb \
fsl-ls2080a-rdb.dtb \
fsl-ls2081a-rdb.dtb \
diff --git a/arch/arm/dts/fsl-ls1028a-qds.dts b/arch/arm/dts/fsl-ls1028a-qds.dts
index 46a0419..94d0aa0 100644
--- a/arch/arm/dts/fsl-ls1028a-qds.dts
+++ b/arch/arm/dts/fsl-ls1028a-qds.dts
@@ -86,3 +86,16 @@
&usb2 {
status = "okay";
};
+
+&enetc1 {
+ status = "okay";
+ phy-mode = "rgmii";
+ phy-handle = <&qds_phy0>;
+};
+
+&mdio0 {
+ status = "okay";
+ qds_phy0: phy@5 {
+ reg = <5>;
+ };
+};
diff --git a/arch/arm/dts/fsl-ls1028a-rdb.dts b/arch/arm/dts/fsl-ls1028a-rdb.dts
index 932cfa2..0525389 100644
--- a/arch/arm/dts/fsl-ls1028a-rdb.dts
+++ b/arch/arm/dts/fsl-ls1028a-rdb.dts
@@ -86,3 +86,16 @@
&usb2 {
status = "okay";
};
+
+&enetc0 {
+ status = "okay";
+ phy-mode = "sgmii";
+ phy-handle = <&rdb_phy0>;
+};
+
+&mdio0 {
+ status = "okay";
+ rdb_phy0: phy@2 {
+ reg = <2>;
+ };
+};
diff --git a/arch/arm/dts/fsl-ls1028a.dtsi b/arch/arm/dts/fsl-ls1028a.dtsi
index 4907411..43a154e 100644
--- a/arch/arm/dts/fsl-ls1028a.dtsi
+++ b/arch/arm/dts/fsl-ls1028a.dtsi
@@ -117,6 +117,30 @@
#size-cells = <2>;
device_type = "pci";
ranges= <0x82000000 0x0 0x00000000 0x1 0xf8000000 0x0 0x160000>;
+ enetc0: pci@0,0 {
+ reg = <0x000000 0 0 0 0>;
+ status = "disabled";
+ };
+ enetc1: pci@0,1 {
+ reg = <0x000100 0 0 0 0>;
+ status = "disabled";
+ };
+ enetc2: pci@0,2 {
+ reg = <0x000200 0 0 0 0>;
+ status = "okay";
+ phy-mode = "internal";
+ };
+ mdio0: pci@0,3 {
+ #address-cells=<0>;
+ #size-cells=<1>;
+ reg = <0x000300 0 0 0 0>;
+ status = "disabled";
+ };
+ enetc6: pci@0,6 {
+ reg = <0x000600 0 0 0 0>;
+ status = "okay";
+ phy-mode = "internal";
+ };
};
i2c0: i2c@2000000 {
diff --git a/arch/arm/dts/k3-am65-main.dtsi b/arch/arm/dts/k3-am65-main.dtsi
index adcd634..39fec03 100644
--- a/arch/arm/dts/k3-am65-main.dtsi
+++ b/arch/arm/dts/k3-am65-main.dtsi
@@ -69,4 +69,78 @@
clock-frequency = <48000000>;
current-speed = <115200>;
};
+
+ main_pmx0: pinmux@11c000 {
+ compatible = "pinctrl-single";
+ reg = <0x0 0x11c000 0x0 0x2e4>;
+ #pinctrl-cells = <1>;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <0xffffffff>;
+ };
+
+ main_pmx1: pinmux@11c2e8 {
+ compatible = "pinctrl-single";
+ reg = <0x0 0x11c2e8 0x0 0x24>;
+ #pinctrl-cells = <1>;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <0xffffffff>;
+ };
+
+ sdhci0: sdhci@4f80000 {
+ compatible = "ti,am654-sdhci-5.1";
+ reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>;
+ power-domains = <&k3_pds 47>;
+ clocks = <&k3_clks 47 0>, <&k3_clks 47 1>;
+ clock-names = "clk_ahb", "clk_xin";
+ interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+ mmc-ddr-1_8v;
+ mmc-hs200-1_8v;
+ ti,otap-del-sel = <0x2>;
+ ti,trm-icp = <0x8>;
+ dma-coherent;
+ };
+
+ main_i2c0: i2c@2000000 {
+ compatible = "ti,am654-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2000000 0x0 0x100>;
+ interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 110 1>;
+ power-domains = <&k3_pds 110>;
+ };
+
+ main_i2c1: i2c@2010000 {
+ compatible = "ti,am654-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2010000 0x0 0x100>;
+ interrupts = <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 111 1>;
+ power-domains = <&k3_pds 111>;
+ };
+
+ main_i2c2: i2c@2020000 {
+ compatible = "ti,am654-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2020000 0x0 0x100>;
+ interrupts = <GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 112 1>;
+ power-domains = <&k3_pds 112>;
+ };
+
+ main_i2c3: i2c@2030000 {
+ compatible = "ti,am654-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2030000 0x0 0x100>;
+ interrupts = <GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 113 1>;
+ power-domains = <&k3_pds 113>;
+ };
};
diff --git a/arch/arm/dts/k3-am65-mcu.dtsi b/arch/arm/dts/k3-am65-mcu.dtsi
index 8c611d1..1fd0277 100644
--- a/arch/arm/dts/k3-am65-mcu.dtsi
+++ b/arch/arm/dts/k3-am65-mcu.dtsi
@@ -15,4 +15,15 @@
clock-frequency = <96000000>;
current-speed = <115200>;
};
+
+ mcu_i2c0: i2c@40b00000 {
+ compatible = "ti,am654-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x40b00000 0x0 0x100>;
+ interrupts = <GIC_SPI 564 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 114 1>;
+ power-domains = <&k3_pds 114>;
+ };
};
diff --git a/arch/arm/dts/k3-am65-wakeup.dtsi b/arch/arm/dts/k3-am65-wakeup.dtsi
index 1f591ef..1f85006 100644
--- a/arch/arm/dts/k3-am65-wakeup.dtsi
+++ b/arch/arm/dts/k3-am65-wakeup.dtsi
@@ -34,6 +34,14 @@
};
};
+ wkup_pmx0: pinmux@4301c000 {
+ compatible = "pinctrl-single";
+ reg = <0x4301c000 0x118>;
+ #pinctrl-cells = <1>;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <0xffffffff>;
+ };
+
wkup_uart0: serial@42300000 {
compatible = "ti,am654-uart";
reg = <0x42300000 0x100>;
@@ -43,4 +51,15 @@
clock-frequency = <48000000>;
current-speed = <115200>;
};
+
+ wkup_i2c0: i2c@42120000 {
+ compatible = "ti,am654-i2c", "ti,omap4-i2c";
+ reg = <0x42120000 0x100>;
+ interrupts = <GIC_SPI 696 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 115 1>;
+ power-domains = <&k3_pds 115>;
+ };
};
diff --git a/arch/arm/dts/k3-am65.dtsi b/arch/arm/dts/k3-am65.dtsi
index 9d1ed49..4727193 100644
--- a/arch/arm/dts/k3-am65.dtsi
+++ b/arch/arm/dts/k3-am65.dtsi
@@ -8,6 +8,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/pinctrl/k3.h>
/ {
model = "Texas Instruments K3 AM654 SoC";
@@ -22,6 +23,12 @@
serial2 = &main_uart0;
serial3 = &main_uart1;
serial4 = &main_uart2;
+ i2c0 = &wkup_i2c0;
+ i2c1 = &mcu_i2c0;
+ i2c2 = &main_i2c0;
+ i2c3 = &main_i2c1;
+ i2c4 = &main_i2c2;
+ i2c5 = &main_i2c3;
};
chosen { };
diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi
index 844a5cd..449b1dd 100644
--- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi
+++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi
@@ -21,51 +21,21 @@
&cbass_main{
u-boot,dm-spl;
- main_pmx0: pinmux@11c000 {
- compatible = "pinctrl-single";
- reg = <0x0 0x11c000 0x0 0x2e4>;
- #pinctrl-cells = <1>;
- pinctrl-single,register-width = <32>;
- pinctrl-single,function-mask = <0xffffffff>;
- };
-
- main_pmx1: pinmux@11c2e8 {
- compatible = "pinctrl-single";
- reg = <0x0 0x11c2e8 0x0 0x24>;
- #pinctrl-cells = <1>;
- pinctrl-single,register-width = <32>;
- pinctrl-single,function-mask = <0xffffffff>;
- };
-
- sdhci0: sdhci@04F80000 {
- compatible = "arasan,sdhci-5.1";
- reg = <0x0 0x4F80000 0x0 0x1000>,
- <0x0 0x4F90000 0x0 0x400>;
- clocks = <&k3_clks 47 1>;
- power-domains = <&k3_pds 47>;
- max-frequency = <25000000>;
- };
-
sdhci1: sdhci@04FA0000 {
- compatible = "arasan,sdhci-5.1";
+ compatible = "ti,am654-sdhci-5.1";
reg = <0x0 0x4FA0000 0x0 0x1000>,
<0x0 0x4FB0000 0x0 0x400>;
clocks = <&k3_clks 48 1>;
power-domains = <&k3_pds 48>;
max-frequency = <25000000>;
+ ti,otap-del-sel = <0x2>;
+ ti,trm-icp = <0x8>;
};
};
&cbass_mcu {
u-boot,dm-spl;
- wkup_pmx0: pinmux@4301c000 {
- compatible = "pinctrl-single";
- reg = <0x0 0x4301c000 0x0 0x118>;
- #pinctrl-cells = <1>;
- pinctrl-single,register-width = <32>;
- pinctrl-single,function-mask = <0xffffffff>;
- };
navss_mcu: navss-mcu {
compatible = "simple-bus";
@@ -250,6 +220,14 @@
&k3_reset {
u-boot,dm-spl;
+};
+
+&wkup_pmx0 {
+ u-boot,dm-spl;
+
+ wkup_i2c0_pins_default {
+ u-boot,dm-spl;
+ };
};
&main_pmx0 {
@@ -276,7 +254,8 @@
AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */
AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */
AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */
- AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */
+ AM65X_IOPAD(0x01b4, PIN_INPUT_PULLUP, 0) /* (A23) MMC0_SDCD */
+ AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */
>;
u-boot,dm-spl;
};
@@ -336,11 +315,6 @@
&sdhci0 {
u-boot,dm-spl;
- status = "okay";
- non-removable;
- bus-width = <8>;
- pinctrl-names = "default";
- pinctrl-0 = <&main_mmc0_pins_default>;
};
&sdhci1 {
@@ -349,6 +323,7 @@
pinctrl-names = "default";
pinctrl-0 = <&main_mmc1_pins_default>;
sdhci-caps-mask = <0x7 0x0>;
+ ti,driver-strength-ohm = <50>;
};
&mcu_cpsw {
@@ -382,3 +357,7 @@
reg-names = "gmii-sel";
};
};
+
+&wkup_i2c0 {
+ u-boot,dm-spl;
+};
diff --git a/arch/arm/dts/k3-am654-base-board.dts b/arch/arm/dts/k3-am654-base-board.dts
index af6956f..e73b9aa 100644
--- a/arch/arm/dts/k3-am654-base-board.dts
+++ b/arch/arm/dts/k3-am654-base-board.dts
@@ -6,6 +6,7 @@
/dts-v1/;
#include "k3-am654.dtsi"
+#include <dt-bindings/pinctrl/k3.h>
/ {
compatible = "ti,am654-evm", "ti,am654";
@@ -34,3 +35,52 @@
};
};
};
+
+&main_pmx0 {
+ main_mmc0_pins_default: main_mmc0_pins_default {
+ pinctrl-single,pins = <
+ AM65X_IOPAD(0x01a8, PIN_INPUT_PULLDOWN, 0) /* (B25) MMC0_CLK */
+ AM65X_IOPAD(0x01aC, PIN_INPUT_PULLUP, 0) /* (B27) MMC0_CMD */
+ AM65X_IOPAD(0x01a4, PIN_INPUT_PULLUP, 0) /* (A26) MMC0_DAT0 */
+ AM65X_IOPAD(0x01a0, PIN_INPUT_PULLUP, 0) /* (E25) MMC0_DAT1 */
+ AM65X_IOPAD(0x019c, PIN_INPUT_PULLUP, 0) /* (C26) MMC0_DAT2 */
+ AM65X_IOPAD(0x0198, PIN_INPUT_PULLUP, 0) /* (A25) MMC0_DAT3 */
+ AM65X_IOPAD(0x0194, PIN_INPUT_PULLUP, 0) /* (E24) MMC0_DAT4 */
+ AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */
+ AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */
+ AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */
+ AM65X_IOPAD(0x01b4, PIN_INPUT_PULLUP, 0) /* (A23) MMC0_SDCD */
+ AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */
+ >;
+ };
+};
+
+&wkup_pmx0 {
+ wkup_i2c0_pins_default: wkup-i2c0-pins-default {
+ pinctrl-single,pins = <
+ AM65X_WKUP_IOPAD(0x00e0, PIN_INPUT, 0) /* (AC7) WKUP_I2C0_SCL */
+ AM65X_WKUP_IOPAD(0x00e4, PIN_INPUT, 0) /* (AD6) WKUP_I2C0_SDA */
+ >;
+ };
+};
+
+&sdhci0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_mmc0_pins_default>;
+ bus-width = <8>;
+ non-removable;
+ ti,driver-strength-ohm = <50>;
+};
+
+&wkup_i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&wkup_i2c0_pins_default>;
+ clock-frequency = <400000>;
+
+ tca9554: gpio@38 {
+ compatible = "nxp,pca9554";
+ reg = <0x38>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+};
diff --git a/arch/arm/dts/k3-am654-r5-base-board.dts b/arch/arm/dts/k3-am654-r5-base-board.dts
index a07038b..9d9b3d5 100644
--- a/arch/arm/dts/k3-am654-r5-base-board.dts
+++ b/arch/arm/dts/k3-am654-r5-base-board.dts
@@ -96,6 +96,12 @@
u-boot,dm-spl;
};
+ clk_200mhz: dummy_clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <200000000>;
+ u-boot,dm-spl;
+ };
};
&dmsc {
@@ -130,10 +136,56 @@
>;
u-boot,dm-spl;
};
+
+ wkup_i2c0_pins_default: wkup-i2c0-pins-default {
+ pinctrl-single,pins = <
+ AM65X_WKUP_IOPAD(0x00e0, PIN_INPUT, 0) /* (AC7) WKUP_I2C0_SCL */
+ AM65X_WKUP_IOPAD(0x00e4, PIN_INPUT, 0) /* (AD6) WKUP_I2C0_SDA */
+ >;
+ };
};
+&main_pmx0 {
+ u-boot,dm-spl;
+ main_mmc0_pins_default: main_mmc0_pins_default {
+ pinctrl-single,pins = <
+ AM65X_IOPAD(0x01a8, PIN_INPUT_PULLDOWN, 0) /* (B25) MMC0_CLK */
+ AM65X_IOPAD(0x01aC, PIN_INPUT_PULLUP, 0) /* (B27) MMC0_CMD */
+ AM65X_IOPAD(0x01a4, PIN_INPUT_PULLUP, 0) /* (A26) MMC0_DAT0 */
+ AM65X_IOPAD(0x01a0, PIN_INPUT_PULLUP, 0) /* (E25) MMC0_DAT1 */
+ AM65X_IOPAD(0x019c, PIN_INPUT_PULLUP, 0) /* (C26) MMC0_DAT2 */
+ AM65X_IOPAD(0x0198, PIN_INPUT_PULLUP, 0) /* (A25) MMC0_DAT3 */
+ AM65X_IOPAD(0x0194, PIN_INPUT_PULLUP, 0) /* (E24) MMC0_DAT4 */
+ AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */
+ AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */
+ AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */
+ AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */
+ >;
+ };
+};
+
&memorycontroller {
vtt-supply = <&vtt_supply>;
pinctrl-names = "default";
pinctrl-0 = <&wkup_vtt_pins_default>;
};
+
+&sdhci0 {
+ clock-names = "clk_xin";
+ clocks = <&clk_200mhz>;
+ /delete-property/ power-domains;
+ ti,driver-strength-ohm = <50>;
+};
+
+&sdhci1 {
+ clock-names = "clk_xin";
+ clocks = <&clk_200mhz>;
+ /delete-property/ power-domains;
+ ti,driver-strength-ohm = <50>;
+};
+
+&wkup_i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&wkup_i2c0_pins_default>;
+ clock-frequency = <400000>;
+};
diff --git a/arch/arm/dts/ls1021a-tsn.dts b/arch/arm/dts/ls1021a-tsn.dts
new file mode 100644
index 0000000..f633074
--- /dev/null
+++ b/arch/arm/dts/ls1021a-tsn.dts
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2016-2018 NXP Semiconductors
+ * Copyright 2019 Vladimir Oltean <olteanv@gmail.com>
+ */
+
+/dts-v1/;
+#include "ls1021a.dtsi"
+
+/ {
+ model = "NXP LS1021A-TSN Board";
+
+ aliases {
+ enet0-sgmii-phy = &sgmii_phy2;
+ enet1-sgmii-phy = &sgmii_phy1;
+ spi0 = &qspi;
+ spi1 = &dspi1;
+ };
+};
+
+&enet0 {
+ tbi-handle = <&tbi0>;
+ phy-handle = <&sgmii_phy2>;
+ phy-mode = "sgmii";
+ status = "okay";
+};
+
+&enet1 {
+ tbi-handle = <&tbi1>;
+ phy-handle = <&sgmii_phy1>;
+ phy-mode = "sgmii";
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&mdio0 {
+ /* AR8031 */
+ sgmii_phy1: ethernet-phy@1 {
+ reg = <0x1>;
+ };
+
+ /* AR8031 */
+ sgmii_phy2: ethernet-phy@2 {
+ reg = <0x2>;
+ };
+
+ /* SGMII PCS for enet0 */
+ tbi0: tbi-phy@1f {
+ reg = <0x1f>;
+ device_type = "tbi-phy";
+ };
+};
+
+&mdio1 {
+ /* SGMII PCS for enet1 */
+ tbi1: tbi-phy@1f {
+ reg = <0x1f>;
+ device_type = "tbi-phy";
+ };
+};
+
+&qspi {
+ bus-num = <0>;
+ status = "okay";
+
+ flash@0 {
+ compatible = "spi-flash";
+ spi-max-frequency = <20000000>;
+ reg = <0>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/dts/ls1021a-twr.dtsi b/arch/arm/dts/ls1021a-twr.dtsi
index 5d3275c..27c96f9 100644
--- a/arch/arm/dts/ls1021a-twr.dtsi
+++ b/arch/arm/dts/ls1021a-twr.dtsi
@@ -51,6 +51,26 @@
};
};
+&enet0 {
+ tbi-handle = <&tbi0>;
+ phy-handle = <&sgmii_phy2>;
+ phy-connection-type = "sgmii";
+ status = "okay";
+};
+
+&enet1 {
+ tbi-handle = <&tbi1>;
+ phy-handle = <&sgmii_phy0>;
+ phy-connection-type = "sgmii";
+ status = "okay";
+};
+
+&enet2 {
+ phy-handle = <&rgmii_phy1>;
+ phy-connection-type = "rgmii-id";
+ status = "okay";
+};
+
&i2c0 {
status = "okay";
};
@@ -84,12 +104,24 @@
sgmii_phy0: ethernet-phy@0 {
reg = <0x0>;
};
+
rgmii_phy1: ethernet-phy@1 {
reg = <0x1>;
};
+
sgmii_phy2: ethernet-phy@2 {
reg = <0x2>;
};
+
+ /* SGMII PCS for enet0 */
+ tbi0: tbi-phy@1f {
+ reg = <0x1f>;
+ device_type = "tbi-phy";
+ };
+};
+
+&mdio1 {
+ /* SGMII PCS for enet1 */
tbi1: tbi-phy@1f {
reg = <0x1f>;
device_type = "tbi-phy";
diff --git a/arch/arm/dts/ls1021a.dtsi b/arch/arm/dts/ls1021a.dtsi
index 7fb24ab..e419d9c 100644
--- a/arch/arm/dts/ls1021a.dtsi
+++ b/arch/arm/dts/ls1021a.dtsi
@@ -350,12 +350,36 @@
<&platform_clk 1>;
};
+ enet0: ethernet@2d10000 {
+ compatible = "fsl,etsec2";
+ reg = <0x2d10000 0x1000>;
+ status = "disabled";
+ };
+
+ enet1: ethernet@2d50000 {
+ compatible = "fsl,etsec2";
+ reg = <0x2d50000 0x1000>;
+ status = "disabled";
+ };
+
+ enet2: ethernet@2d90000 {
+ compatible = "fsl,etsec2";
+ reg = <0x2d90000 0x1000>;
+ status = "disabled";
+ };
+
mdio0: mdio@2d24000 {
- compatible = "gianfar";
- device_type = "mdio";
+ compatible = "fsl,etsec2-mdio";
+ reg = <0x2d24000 0x4000>;
#address-cells = <1>;
#size-cells = <0>;
- reg = <0x2d24000 0x4000>;
+ };
+
+ mdio1: mdio@2d64000 {
+ compatible = "fsl,etsec2-mdio";
+ reg = <0x2d64000 0x4000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
};
usb@8600000 {
diff --git a/arch/arm/dts/mt7629-rfb.dts b/arch/arm/dts/mt7629-rfb.dts
index 4612218..08c3b59 100644
--- a/arch/arm/dts/mt7629-rfb.dts
+++ b/arch/arm/dts/mt7629-rfb.dts
@@ -18,7 +18,6 @@
chosen {
stdout-path = &uart0;
- tick-timer = &timer0;
};
};
diff --git a/arch/arm/dts/mt7629.dtsi b/arch/arm/dts/mt7629.dtsi
index c87115e..ecbd29d 100644
--- a/arch/arm/dts/mt7629.dtsi
+++ b/arch/arm/dts/mt7629.dtsi
@@ -82,8 +82,8 @@
compatible = "mediatek,timer";
reg = <0x10004000 0x80>;
interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&topckgen CLK_TOP_10M_SEL>,
- <&topckgen CLK_TOP_CLKXTAL_D4>;
+ clocks = <&topckgen CLK_TOP_CLKXTAL_D4>,
+ <&topckgen CLK_TOP_10M_SEL>;
clock-names = "mux", "src";
u-boot,dm-pre-reloc;
};
diff --git a/arch/arm/dts/rk3288-evb-u-boot.dtsi b/arch/arm/dts/rk3288-evb-u-boot.dtsi
new file mode 100644
index 0000000..8ac7840
--- /dev/null
+++ b/arch/arm/dts/rk3288-evb-u-boot.dtsi
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Rockchip Electronics Co., Ltd
+ */
+
+#include "rk3288-u-boot.dtsi"
+
+&pinctrl {
+ u-boot,dm-pre-reloc;
+};
+
+&uart2 {
+ u-boot,dm-pre-reloc;
+};
+
+&sdmmc {
+ u-boot,dm-pre-reloc;
+};
+
+&emmc {
+ u-boot,dm-pre-reloc;
+};
+
+&gpio3 {
+ u-boot,dm-pre-reloc;
+};
+
+&gpio8 {
+ u-boot,dm-pre-reloc;
+};
+
+&sdmmc_bus4 {
+ u-boot,dm-spl;
+};
+
+&sdmmc_clk {
+ u-boot,dm-spl;
+};
+
+&sdmmc_cmd {
+ u-boot,dm-spl;
+};
+
+&sdmmc_pwr {
+ u-boot,dm-spl;
+};
diff --git a/arch/arm/dts/rk3288-evb.dts b/arch/arm/dts/rk3288-evb.dts
index 575de44..eac91a8 100644
--- a/arch/arm/dts/rk3288-evb.dts
+++ b/arch/arm/dts/rk3288-evb.dts
@@ -26,31 +26,6 @@
rockchip,sdram-params = <0x20d266a4 0x5b6 2 533000000 6 9 0>;
};
-&pinctrl {
- u-boot,dm-pre-reloc;
-};
-
&pwm1 {
status = "okay";
};
-
-&uart2 {
- u-boot,dm-pre-reloc;
- reg-shift = <2>;
-};
-
-&sdmmc {
- u-boot,dm-pre-reloc;
-};
-
-&emmc {
- u-boot,dm-pre-reloc;
-};
-
-&gpio3 {
- u-boot,dm-pre-reloc;
-};
-
-&gpio8 {
- u-boot,dm-pre-reloc;
-};
diff --git a/arch/arm/dts/rk3288-fennec-u-boot.dtsi b/arch/arm/dts/rk3288-fennec-u-boot.dtsi
new file mode 100644
index 0000000..2efb309
--- /dev/null
+++ b/arch/arm/dts/rk3288-fennec-u-boot.dtsi
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Rockchip Electronics Co., Ltd
+ */
+
+#include "rk3288-u-boot.dtsi"
+
+&pinctrl {
+ u-boot,dm-pre-reloc;
+};
+
+&uart2 {
+ u-boot,dm-pre-reloc;
+};
+
+&sdmmc {
+ u-boot,dm-pre-reloc;
+};
+
+&emmc {
+ u-boot,dm-pre-reloc;
+};
+
+&gpio3 {
+ u-boot,dm-pre-reloc;
+};
+
+&gpio8 {
+ u-boot,dm-pre-reloc;
+};
+
+&pcfg_pull_none_drv_8ma {
+ u-boot,dm-spl;
+};
+
+&pcfg_pull_up_drv_8ma {
+ u-boot,dm-spl;
+};
+
+&sdmmc_bus4 {
+ u-boot,dm-spl;
+};
+
+&sdmmc_clk {
+ u-boot,dm-spl;
+};
+
+&sdmmc_cmd {
+ u-boot,dm-spl;
+};
+
+&sdmmc_pwr {
+ u-boot,dm-spl;
+};
diff --git a/arch/arm/dts/rk3288-fennec.dts b/arch/arm/dts/rk3288-fennec.dts
index b569307..e1d55e3 100644
--- a/arch/arm/dts/rk3288-fennec.dts
+++ b/arch/arm/dts/rk3288-fennec.dts
@@ -26,31 +26,6 @@
rockchip,sdram-params = <0x20d266a4 0x5b6 2 533000000 6 9 0>;
};
-&pinctrl {
- u-boot,dm-pre-reloc;
-};
-
&pwm1 {
status = "okay";
};
-
-&uart2 {
- u-boot,dm-pre-reloc;
- reg-shift = <2>;
-};
-
-&sdmmc {
- u-boot,dm-pre-reloc;
-};
-
-&emmc {
- u-boot,dm-pre-reloc;
-};
-
-&gpio3 {
- u-boot,dm-pre-reloc;
-};
-
-&gpio8 {
- u-boot,dm-pre-reloc;
-};
diff --git a/arch/arm/dts/rk3288-firefly-u-boot.dtsi b/arch/arm/dts/rk3288-firefly-u-boot.dtsi
new file mode 100644
index 0000000..8b9c383
--- /dev/null
+++ b/arch/arm/dts/rk3288-firefly-u-boot.dtsi
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Rockchip Electronics Co., Ltd
+ */
+
+#include "rk3288-u-boot.dtsi"
+
+&pinctrl {
+ u-boot,dm-pre-reloc;
+};
+
+&uart2 {
+ u-boot,dm-pre-reloc;
+};
+
+&sdmmc {
+ u-boot,dm-pre-reloc;
+};
+
+&emmc {
+ u-boot,dm-pre-reloc;
+};
+
+&gpio3 {
+ u-boot,dm-pre-reloc;
+};
+
+&gpio8 {
+ u-boot,dm-pre-reloc;
+};
+
+&pcfg_pull_up_drv_12ma {
+ u-boot,dm-spl;
+};
+
+&sdmmc_bus4 {
+ u-boot,dm-spl;
+};
+
+&sdmmc_clk {
+ u-boot,dm-spl;
+};
+
+&sdmmc_cmd {
+ u-boot,dm-spl;
+};
+
+&sdmmc_pwr {
+ u-boot,dm-spl;
+};
diff --git a/arch/arm/dts/rk3288-firefly.dts b/arch/arm/dts/rk3288-firefly.dts
index 2e075406..1cff04e 100644
--- a/arch/arm/dts/rk3288-firefly.dts
+++ b/arch/arm/dts/rk3288-firefly.dts
@@ -37,7 +37,6 @@
};
&pinctrl {
- u-boot,dm-pre-reloc;
act8846 {
pmic_vsel: pmic-vsel {
rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_output_low>;
@@ -59,25 +58,3 @@
&pwm1 {
status = "okay";
};
-
-&uart2 {
- u-boot,dm-pre-reloc;
- reg-shift = <2>;
-};
-
-&usb_host1 {
- vbus-supply = <&vcc_host_5v>;
- status = "okay";
-};
-
-&sdmmc {
- u-boot,dm-pre-reloc;
-};
-
-&gpio3 {
- u-boot,dm-pre-reloc;
-};
-
-&gpio8 {
- u-boot,dm-pre-reloc;
-};
diff --git a/arch/arm/dts/rk3288-firefly.dtsi b/arch/arm/dts/rk3288-firefly.dtsi
index 2239ab9..b7f279f 100644
--- a/arch/arm/dts/rk3288-firefly.dtsi
+++ b/arch/arm/dts/rk3288-firefly.dtsi
@@ -320,6 +320,11 @@
output-low;
};
+ pcfg_pull_up_drv_12ma: pcfg-pull-up-drv-12ma {
+ bias-pull-up;
+ drive-strength = <12>;
+ };
+
act8846 {
pwr_hold: pwr-hold {
rockchip,pins = <0 1 RK_FUNC_GPIO &pcfg_output_high>;
@@ -363,8 +368,27 @@
};
sdmmc {
+ /*
+ * Default drive strength isn't enough to achieve even
+ * high-speed mode on firefly board so bump up to 12ma.
+ */
+ sdmmc_bus4: sdmmc-bus4 {
+ rockchip,pins = <6 RK_PC0 1 &pcfg_pull_up_drv_12ma>,
+ <6 RK_PC1 1 &pcfg_pull_up_drv_12ma>,
+ <6 RK_PC2 1 &pcfg_pull_up_drv_12ma>,
+ <6 RK_PC3 1 &pcfg_pull_up_drv_12ma>;
+ };
+
+ sdmmc_clk: sdmmc-clk {
+ rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none_12ma>;
+ };
+
+ sdmmc_cmd: sdmmc-cmd {
+ rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_12ma>;
+ };
+
sdmmc_pwr: sdmmc-pwr {
- rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+ rockchip,pins = <7 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
diff --git a/arch/arm/dts/rk3288-miqi-u-boot.dtsi b/arch/arm/dts/rk3288-miqi-u-boot.dtsi
new file mode 100644
index 0000000..4f63fc9
--- /dev/null
+++ b/arch/arm/dts/rk3288-miqi-u-boot.dtsi
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Rockchip Electronics Co., Ltd
+ */
+
+#include "rk3288-u-boot.dtsi"
+
+&pinctrl {
+ u-boot,dm-pre-reloc;
+};
+
+&uart2 {
+ u-boot,dm-pre-reloc;
+};
+
+&sdmmc {
+ u-boot,dm-pre-reloc;
+};
+
+&emmc {
+ u-boot,dm-pre-reloc;
+};
+
+&sdmmc_bus4 {
+ u-boot,dm-spl;
+};
+
+&sdmmc_clk {
+ u-boot,dm-spl;
+};
+
+&sdmmc_cmd {
+ u-boot,dm-spl;
+};
+
+&sdmmc_pwr {
+ u-boot,dm-spl;
+};
diff --git a/arch/arm/dts/rk3288-miqi.dts b/arch/arm/dts/rk3288-miqi.dts
index 29e60dd..e47170c 100644
--- a/arch/arm/dts/rk3288-miqi.dts
+++ b/arch/arm/dts/rk3288-miqi.dts
@@ -25,21 +25,3 @@
0xa60 0x40 0x10 0x0>;
rockchip,sdram-params = <0x30B25564 0x627 3 666000000 3 9 1>;
};
-
-
-&pinctrl {
- u-boot,dm-pre-reloc;
-};
-
-&uart2 {
- u-boot,dm-pre-reloc;
- reg-shift = <2>;
-};
-
-&sdmmc {
- u-boot,dm-pre-reloc;
-};
-
-&emmc {
- u-boot,dm-pre-reloc;
-};
diff --git a/arch/arm/dts/rk3288-popmetal-u-boot.dtsi b/arch/arm/dts/rk3288-popmetal-u-boot.dtsi
new file mode 100644
index 0000000..8ac7840
--- /dev/null
+++ b/arch/arm/dts/rk3288-popmetal-u-boot.dtsi
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Rockchip Electronics Co., Ltd
+ */
+
+#include "rk3288-u-boot.dtsi"
+
+&pinctrl {
+ u-boot,dm-pre-reloc;
+};
+
+&uart2 {
+ u-boot,dm-pre-reloc;
+};
+
+&sdmmc {
+ u-boot,dm-pre-reloc;
+};
+
+&emmc {
+ u-boot,dm-pre-reloc;
+};
+
+&gpio3 {
+ u-boot,dm-pre-reloc;
+};
+
+&gpio8 {
+ u-boot,dm-pre-reloc;
+};
+
+&sdmmc_bus4 {
+ u-boot,dm-spl;
+};
+
+&sdmmc_clk {
+ u-boot,dm-spl;
+};
+
+&sdmmc_cmd {
+ u-boot,dm-spl;
+};
+
+&sdmmc_pwr {
+ u-boot,dm-spl;
+};
diff --git a/arch/arm/dts/rk3288-popmetal.dts b/arch/arm/dts/rk3288-popmetal.dts
index d1e1cd5..5c6d06f 100644
--- a/arch/arm/dts/rk3288-popmetal.dts
+++ b/arch/arm/dts/rk3288-popmetal.dts
@@ -26,32 +26,6 @@
rockchip,sdram-params = <0x30B25564 0x627 3 666000000 3 9 1>;
};
-
-&pinctrl {
- u-boot,dm-pre-reloc;
-};
-
&pwm1 {
status = "okay";
};
-
-&uart2 {
- u-boot,dm-pre-reloc;
- reg-shift = <2>;
-};
-
-&sdmmc {
- u-boot,dm-pre-reloc;
-};
-
-&emmc {
- u-boot,dm-pre-reloc;
-};
-
-&gpio3 {
- u-boot,dm-pre-reloc;
-};
-
-&gpio8 {
- u-boot,dm-pre-reloc;
-};
diff --git a/arch/arm/dts/rk3288-u-boot.dtsi b/arch/arm/dts/rk3288-u-boot.dtsi
index 4cf75c7..3f00a3b 100644
--- a/arch/arm/dts/rk3288-u-boot.dtsi
+++ b/arch/arm/dts/rk3288-u-boot.dtsi
@@ -3,6 +3,13 @@
* Copyright (C) 2019 Rockchip Electronics Co., Ltd
*/
+/ {
+ chosen {
+ u-boot,spl-boot-order = \
+ "same-as-spl", &emmc, &sdmmc;
+ };
+};
+
&dmc {
u-boot,dm-pre-reloc;
};
diff --git a/arch/arm/dts/rk3368-lion-u-boot.dtsi b/arch/arm/dts/rk3368-lion-u-boot.dtsi
index fb4a4fb..edc93e4 100644
--- a/arch/arm/dts/rk3368-lion-u-boot.dtsi
+++ b/arch/arm/dts/rk3368-lion-u-boot.dtsi
@@ -12,7 +12,6 @@
chosen {
stdout-path = "serial0:115200n8";
u-boot,spl-boot-order = &emmc, &sdmmc;
- tick-timer = "/timer@ff810000";
};
};
diff --git a/arch/arm/dts/rk3368-px5-evb-u-boot.dtsi b/arch/arm/dts/rk3368-px5-evb-u-boot.dtsi
index f5406d4..002767a 100644
--- a/arch/arm/dts/rk3368-px5-evb-u-boot.dtsi
+++ b/arch/arm/dts/rk3368-px5-evb-u-boot.dtsi
@@ -5,7 +5,6 @@
/ {
chosen {
u-boot,spl-boot-order = &emmc;
- tick-timer = "/timer@ff810000";
};
};
diff --git a/arch/arm/dts/rk3399-ficus.dts b/arch/arm/dts/rk3399-ficus.dts
index 4b2dd82..6b059bd 100644
--- a/arch/arm/dts/rk3399-ficus.dts
+++ b/arch/arm/dts/rk3399-ficus.dts
@@ -23,6 +23,52 @@
clock-output-names = "clkin_gmac";
#clock-cells = <0>;
};
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&user_led1>, <&user_led2>, <&user_led3>,
+ <&user_led4>, <&wlan_led>, <&bt_led>;
+
+ user_led1 {
+ label = "red:user1";
+ gpios = <&gpio4 25 0>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ user_led2 {
+ label = "red:user2";
+ gpios = <&gpio4 26 0>;
+ linux,default-trigger = "mmc0";
+ };
+
+ user_led3 {
+ label = "red:user3";
+ gpios = <&gpio4 30 0>;
+ linux,default-trigger = "mmc1";
+ };
+
+ user_led4 {
+ label = "red:user4";
+ gpios = <&gpio1 0 0>;
+ panic-indicator;
+ linux,default-trigger = "none";
+ };
+
+ wlan_active_led {
+ label = "red:wlan";
+ gpios = <&gpio1 1 0>;
+ linux,default-trigger = "phy0tx";
+ default-state = "off";
+ };
+
+ bt_active_led {
+ label = "red:bt";
+ gpios = <&gpio1 4 0>;
+ linux,default-trigger = "hci0-power";
+ default-state = "off";
+ };
+ };
};
&gmac {
@@ -49,23 +95,63 @@
gmac {
rgmii_sleep_pins: rgmii-sleep-pins {
rockchip,pins =
- <3 15 RK_FUNC_GPIO &pcfg_output_low>;
+ <3 RK_PB7 RK_FUNC_GPIO &pcfg_output_low>;
};
};
pcie {
pcie_drv: pcie-drv {
rockchip,pins =
- <1 24 RK_FUNC_GPIO &pcfg_pull_none>;
+ <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
usb2 {
host_vbus_drv: host-vbus-drv {
rockchip,pins =
- <4 27 RK_FUNC_GPIO &pcfg_pull_none>;
+ <4 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
+
+ leds {
+ user_led1: user_led1 {
+ rockchip,pins =
+ <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ user_led2: user_led2 {
+ rockchip,pins =
+ <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ user_led3: user_led3 {
+ rockchip,pins =
+ <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ user_led4: user_led4 {
+ rockchip,pins =
+ <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ wlan_led: wlan_led {
+ rockchip,pins =
+ <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_led: bt_led {
+ rockchip,pins =
+ <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&usbdrd_dwc3_0 {
+ dr_mode = "host";
+};
+
+&usbdrd_dwc3_1 {
+ dr_mode = "host";
};
&vcc3v3_pcie {
diff --git a/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi b/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi
index 7d22528..eb0aca4 100644
--- a/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi
+++ b/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi
@@ -4,3 +4,4 @@
*/
#include "rk3399-nanopi4-u-boot.dtsi"
+#include "rk3399-sdram-ddr3-1866.dtsi"
diff --git a/arch/arm/dts/rk3399-rock-pi-4-u-boot.dtsi b/arch/arm/dts/rk3399-rock-pi-4-u-boot.dtsi
index 7bddc3a..5bd8696 100644
--- a/arch/arm/dts/rk3399-rock-pi-4-u-boot.dtsi
+++ b/arch/arm/dts/rk3399-rock-pi-4-u-boot.dtsi
@@ -4,3 +4,10 @@
*/
#include "rk3399-u-boot.dtsi"
+#include "rk3399-sdram-lpddr4-100.dtsi"
+
+/ {
+ chosen {
+ u-boot,spl-boot-order = "same-as-spl", &sdhci, &sdmmc;
+ };
+};
diff --git a/arch/arm/dts/rk3399-rock960.dts b/arch/arm/dts/rk3399-rock960.dts
index 7e06bc9..12285c5 100644
--- a/arch/arm/dts/rk3399-rock960.dts
+++ b/arch/arm/dts/rk3399-rock960.dts
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
- * Copyright (C) 2018 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ * Copyright (c) 2018 Linaro Ltd.
*/
/dts-v1/;
@@ -13,6 +13,53 @@
chosen {
stdout-path = "serial2:1500000n8";
};
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&user_led1>, <&user_led2>, <&user_led3>,
+ <&user_led4>, <&wlan_led>, <&bt_led>;
+
+ user_led1 {
+ label = "green:user1";
+ gpios = <&gpio4 RK_PC2 0>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ user_led2 {
+ label = "green:user2";
+ gpios = <&gpio4 RK_PC6 0>;
+ linux,default-trigger = "mmc0";
+ };
+
+ user_led3 {
+ label = "green:user3";
+ gpios = <&gpio4 RK_PD0 0>;
+ linux,default-trigger = "mmc1";
+ };
+
+ user_led4 {
+ label = "green:user4";
+ gpios = <&gpio4 RK_PD4 0>;
+ panic-indicator;
+ linux,default-trigger = "none";
+ };
+
+ wlan_active_led {
+ label = "yellow:wlan";
+ gpios = <&gpio4 RK_PD5 0>;
+ linux,default-trigger = "phy0tx";
+ default-state = "off";
+ };
+
+ bt_active_led {
+ label = "blue:bt";
+ gpios = <&gpio4 RK_PD6 0>;
+ linux,default-trigger = "hci0-power";
+ default-state = "off";
+ };
+ };
+
};
&pcie0 {
@@ -20,6 +67,38 @@
};
&pinctrl {
+ leds {
+ user_led1: user_led1 {
+ rockchip,pins =
+ <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ user_led2: user_led2 {
+ rockchip,pins =
+ <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ user_led3: user_led3 {
+ rockchip,pins =
+ <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ user_led4: user_led4 {
+ rockchip,pins =
+ <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ wlan_led: wlan_led {
+ rockchip,pins =
+ <4 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_led: bt_led {
+ rockchip,pins =
+ <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
pcie {
pcie_drv: pcie-drv {
rockchip,pins =
@@ -35,6 +114,14 @@
};
};
+&usbdrd_dwc3_0 {
+ dr_mode = "otg";
+};
+
+&usbdrd_dwc3_1 {
+ dr_mode = "host";
+};
+
&vcc3v3_pcie {
gpio = <&gpio2 5 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/dts/rk3399-rock960.dtsi b/arch/arm/dts/rk3399-rock960.dtsi
index 51644d6..c7d48d4 100644
--- a/arch/arm/dts/rk3399-rock960.dtsi
+++ b/arch/arm/dts/rk3399-rock960.dtsi
@@ -1,13 +1,32 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
+ * Copyright (c) 2018 Collabora Ltd.
+ * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd.
* Copyright (c) 2018 Linaro Ltd.
*/
-#include <dt-bindings/pwm/pwm.h>
-#include <dt-bindings/pinctrl/rockchip.h>
#include "rk3399.dtsi"
+#include "rk3399-opp.dtsi"
/ {
+ sdio_pwrseq: sdio-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&rk808 1>;
+ clock-names = "ext_clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_enable_h>;
+ reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
+ };
+
+ vcc12v_dcin: vcc12v-dcin {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc12v_dcin";
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
vcc1v8_s0: vcc1v8-s0 {
compatible = "regulator-fixed";
regulator-name = "vcc1v8_s0";
@@ -16,12 +35,13 @@
regulator-always-on;
};
- vcc_sys: vcc-sys {
+ vcc5v0_sys: vcc5v0-sys {
compatible = "regulator-fixed";
- regulator-name = "vcc_sys";
+ regulator-name = "vcc5v0_sys";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-always-on;
+ vin-supply = <&vcc12v_dcin>;
};
vcc3v3_sys: vcc3v3-sys {
@@ -30,7 +50,7 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
- vin-supply = <&vcc_sys>;
+ vin-supply = <&vcc5v0_sys>;
};
vcc3v3_pcie: vcc3v3-pcie-regulator {
@@ -54,20 +74,8 @@
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-always-on;
- vin-supply = <&vcc_sys>;
- };
-
- vdd_log: vdd-log {
- compatible = "pwm-regulator";
- pwms = <&pwm2 0 25000 0>;
- regulator-name = "vdd_log";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1400000>;
- regulator-always-on;
- regulator-boot-on;
- vin-supply = <&vcc_sys>;
+ vin-supply = <&vcc5v0_sys>;
};
-
};
&cpu_l0 {
@@ -98,10 +106,22 @@
status = "okay";
};
+&gpu {
+ mali-supply = <&vdd_gpu>;
+ status = "okay";
+};
+
&hdmi {
+ ddc-i2c-bus = <&i2c3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_cec>;
status = "okay";
};
+&hdmi_sound {
+ status = "okay";
+};
+
&i2c0 {
clock-frequency = <400000>;
i2c-scl-rising-time-ns = <168>;
@@ -118,7 +138,7 @@
regulator-ramp-delay = <1000>;
regulator-always-on;
regulator-boot-on;
- vin-supply = <&vcc_sys>;
+ vin-supply = <&vcc5v0_sys>;
status = "okay";
regulator-state-mem {
@@ -136,7 +156,7 @@
regulator-ramp-delay = <1000>;
regulator-always-on;
regulator-boot-on;
- vin-supply = <&vcc_sys>;
+ vin-supply = <&vcc5v0_sys>;
regulator-state-mem {
regulator-off-in-suspend;
};
@@ -154,16 +174,16 @@
#clock-cells = <1>;
clock-output-names = "xin32k", "rk808-clkout2";
- vcc1-supply = <&vcc_sys>;
- vcc2-supply = <&vcc_sys>;
- vcc3-supply = <&vcc_sys>;
- vcc4-supply = <&vcc_sys>;
- vcc6-supply = <&vcc_sys>;
- vcc7-supply = <&vcc_sys>;
+ vcc1-supply = <&vcc5v0_sys>;
+ vcc2-supply = <&vcc5v0_sys>;
+ vcc3-supply = <&vcc5v0_sys>;
+ vcc4-supply = <&vcc5v0_sys>;
+ vcc6-supply = <&vcc5v0_sys>;
+ vcc7-supply = <&vcc5v0_sys>;
vcc8-supply = <&vcc3v3_sys>;
- vcc9-supply = <&vcc_sys>;
- vcc10-supply = <&vcc_sys>;
- vcc11-supply = <&vcc_sys>;
+ vcc9-supply = <&vcc5v0_sys>;
+ vcc10-supply = <&vcc5v0_sys>;
+ vcc11-supply = <&vcc5v0_sys>;
vcc12-supply = <&vcc3v3_sys>;
vddio-supply = <&vcc_1v8>;
@@ -344,6 +364,10 @@
status = "okay";
};
+&i2s2 {
+ status = "okay";
+};
+
&io_domains {
bt656-supply = <&vcc1v8_s0>; /* bt656_gpio2ab_ms */
audio-supply = <&vcc1v8_s0>; /* audio_gpio3d4a_ms */
@@ -370,47 +394,94 @@
};
&pinctrl {
+ bt {
+ bt_enable_h: bt-enable-h {
+ rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_host_wake_l: bt-host-wake-l {
+ rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_wake_l: bt-wake-l {
+ rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
sdmmc {
sdmmc_bus1: sdmmc-bus1 {
rockchip,pins =
- <4 8 RK_FUNC_1 &pcfg_pull_up_8ma>;
+ <4 RK_PB0 1 &pcfg_pull_up_8ma>;
};
sdmmc_bus4: sdmmc-bus4 {
rockchip,pins =
- <4 8 RK_FUNC_1 &pcfg_pull_up_8ma>,
- <4 9 RK_FUNC_1 &pcfg_pull_up_8ma>,
- <4 10 RK_FUNC_1 &pcfg_pull_up_8ma>,
- <4 11 RK_FUNC_1 &pcfg_pull_up_8ma>;
+ <4 RK_PB0 1 &pcfg_pull_up_8ma>,
+ <4 RK_PB1 1 &pcfg_pull_up_8ma>,
+ <4 RK_PB2 1 &pcfg_pull_up_8ma>,
+ <4 RK_PB3 1 &pcfg_pull_up_8ma>;
};
sdmmc_clk: sdmmc-clk {
rockchip,pins =
- <4 12 RK_FUNC_1 &pcfg_pull_none_18ma>;
+ <4 RK_PB4 1 &pcfg_pull_none_18ma>;
};
sdmmc_cmd: sdmmc-cmd {
rockchip,pins =
+ <4 RK_PB5 1 &pcfg_pull_up_8ma>;
+ };
+ };
+
+ sdio0 {
+ sdio0_bus4: sdio0-bus4 {
+ rockchip,pins =
- <4 13 RK_FUNC_1 &pcfg_pull_up_8ma>;
+ <2 RK_PC4 1 &pcfg_pull_up_20ma>,
+ <2 RK_PC5 1 &pcfg_pull_up_20ma>,
+ <2 RK_PC6 1 &pcfg_pull_up_20ma>,
+ <2 RK_PC7 1 &pcfg_pull_up_20ma>;
+ };
+
+ sdio0_cmd: sdio0-cmd {
+ rockchip,pins =
+ <2 RK_PD0 1 &pcfg_pull_up_20ma>;
+ };
+
+ sdio0_clk: sdio0-clk {
+ rockchip,pins =
+ <2 RK_PD1 1 &pcfg_pull_none_20ma>;
};
};
pmic {
pmic_int_l: pmic-int-l {
rockchip,pins =
- <1 21 RK_FUNC_GPIO &pcfg_pull_up>;
+ <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
};
vsel1_gpio: vsel1-gpio {
rockchip,pins =
- <1 17 RK_FUNC_GPIO &pcfg_pull_down>;
+ <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>;
};
vsel2_gpio: vsel2-gpio {
rockchip,pins =
- <1 14 RK_FUNC_GPIO &pcfg_pull_down>;
+ <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
};
};
+
+ sdio-pwrseq {
+ wifi_enable_h: wifi-enable-h {
+ rockchip,pins =
+ <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ wifi {
+ wifi_host_wake_l: wifi-host-wake-l {
+ rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
};
&pwm2 {
@@ -421,6 +492,32 @@
status = "okay";
};
+&sdio0 {
+ bus-width = <4>;
+ clock-frequency = <50000000>;
+ cap-sdio-irq;
+ cap-sd-highspeed;
+ keep-power-in-suspend;
+ mmc-pwrseq = <&sdio_pwrseq>;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
+ sd-uhs-sdr104;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ compatible = "brcm,bcm4329-fmac";
+ reg = <1>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>;
+ interrupt-names = "host-wake";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_host_wake_l>;
+ };
+};
+
&sdhci {
bus-width = <8>;
mmc-hs400-1_8v;
@@ -445,16 +542,42 @@
status = "okay";
};
+&tsadc {
+ rockchip,hw-tshut-mode = <1>;
+ rockchip,hw-tshut-polarity = <1>;
+ rockchip,hw-tshut-temp = <110000>;
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
- pinctrl-0 = <&uart0_xfer &uart0_cts>;
+ pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rk808 1>;
+ clock-names = "ext_clock";
+ device-wakeup-gpios = <&gpio2 RK_PD3 GPIO_ACTIVE_HIGH>;
+ host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;
+ shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>;
+ };
};
&uart2 {
status = "okay";
};
+&tcphy0 {
+ status = "okay";
+};
+
+&tcphy1 {
+ status = "okay";
+};
+
&u2phy0 {
status = "okay";
};
@@ -497,10 +620,34 @@
status = "okay";
};
+&usbdrd3_0 {
+ status = "okay";
+};
+
+&usbdrd_dwc3_0 {
+ status = "okay";
+};
+
+&usbdrd3_1 {
+ status = "okay";
+};
+
+&usbdrd_dwc3_1 {
+ status = "okay";
+};
+
&vopb {
status = "okay";
};
+&vopb_mmu {
+ status = "okay";
+};
+
&vopl {
status = "okay";
};
+
+&vopl_mmu {
+ status = "okay";
+};
diff --git a/arch/arm/dts/rk3399-rockpro64-u-boot.dtsi b/arch/arm/dts/rk3399-rockpro64-u-boot.dtsi
index 50b0ca0..f7f26d5 100644
--- a/arch/arm/dts/rk3399-rockpro64-u-boot.dtsi
+++ b/arch/arm/dts/rk3399-rockpro64-u-boot.dtsi
@@ -4,6 +4,7 @@
*/
#include "rk3399-u-boot.dtsi"
+#include "rk3399-sdram-lpddr4-100.dtsi"
&vdd_log {
regulator-init-microvolt = <950000>;
diff --git a/arch/arm/dts/rk3399-sdram-lpddr4-100.dtsi b/arch/arm/dts/rk3399-sdram-lpddr4-100.dtsi
new file mode 100644
index 0000000..4a4414a
--- /dev/null
+++ b/arch/arm/dts/rk3399-sdram-lpddr4-100.dtsi
@@ -0,0 +1,1537 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
+ * (C) Copyright 2019 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+&dmc {
+ rockchip,sdram-params = <
+ 0x2
+ 0xa
+ 0x3
+ 0x2
+ 0x1
+ 0x0
+ 0xf
+ 0xf
+ 1
+ 0x80241d22
+ 0x15050f08
+ 0x00000602
+ 0x00002122
+ 0x0000004c
+ 0x00000000
+ 0x2
+ 0xa
+ 0x3
+ 0x2
+ 0x1
+ 0x0
+ 0xf
+ 0xf
+ 1
+ 0x80241d22
+ 0x15050f08
+ 0x00000602
+ 0x00002122
+ 0x0000004c
+ 0x00000000
+ 50
+ 7
+ 2
+ 13
+ 1
+ 0x00000b00
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00013880
+ 0x000c3500
+ 0x00000005
+ 0x00000320
+ 0x00027100
+ 0x00186a00
+ 0x00000005
+ 0x00000640
+ 0x00002710
+ 0x000186a0
+ 0x00000005
+ 0x01000064
+ 0x00000000
+ 0x02020101
+ 0x00000102
+ 0x00000050
+ 0x000000c8
+ 0x00000000
+ 0x06140000
+ 0x00081c00
+ 0x0400040c
+ 0x19042008
+ 0x10080a11
+ 0x22310800
+ 0x00200f0a
+ 0x0a030704
+ 0x08000204
+ 0x00000a0a
+ 0x04006db0
+ 0x0a0a0804
+ 0x0600db60
+ 0x0a0a0806
+ 0x04000db6
+ 0x02030404
+ 0x0f0a0800
+ 0x08040411
+ 0x1400640a
+ 0x02010a0a
+ 0x00010001
+ 0x04082012
+ 0x00041109
+ 0x00000000
+ 0x03010000
+ 0x06100048
+ 0x0c280090
+ 0x00bb0009
+ 0x00000000
+ 0x00060005
+ 0x000a0005
+ 0x000a0014
+ 0x01000000
+ 0x030a0000
+ 0x0c000002
+ 0x00000103
+ 0x0005030a
+ 0x00060037
+ 0x0005006e
+ 0x05050007
+ 0x03030605
+ 0x06050301
+ 0x06030c05
+ 0x05050302
+ 0x03030305
+ 0x00000301
+ 0x00000301
+ 0x00000001
+ 0x00000000
+ 0x00000000
+ 0x01000000
+ 0x80104002
+ 0x00040003
+ 0x00040005
+ 0x00030000
+ 0x00050004
+ 0x00000004
+ 0x00040003
+ 0x00040005
+ 0x18400000
+ 0x00000c20
+ 0x185030a0
+ 0x02ec0000
+ 0x00000176
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x06030300
+ 0x00030303
+ 0x02030200
+ 0x00040703
+ 0x03020302
+ 0x02000407
+ 0x07030203
+ 0x00030f04
+ 0x00070004
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00010000
+ 0x20040020
+ 0x00200400
+ 0x01000400
+ 0x00000b80
+ 0x00000000
+ 0x00000001
+ 0x00000002
+ 0x0000000e
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00500000
+ 0x00640028
+ 0x00640404
+ 0x005000a0
+ 0x060600c8
+ 0x000a00c8
+ 0x000d0005
+ 0x000d0404
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x001400a3
+ 0x00e30009
+ 0x00120024
+ 0x00040063
+ 0x00000000
+ 0x00310031
+ 0x00000031
+ 0x004d0000
+ 0x004d004d
+ 0x004d0000
+ 0x004d004d
+ 0x00010101
+ 0x00000000
+ 0x00000000
+ 0x001400a3
+ 0x00e30009
+ 0x00120024
+ 0x00040063
+ 0x00000000
+ 0x00310031
+ 0x00000031
+ 0x004d0000
+ 0x004d004d
+ 0x004d0000
+ 0x004d004d
+ 0x00010101
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000001
+ 0x00000000
+ 0x18151100
+ 0x0000000c
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00020003
+ 0x00400100
+ 0x000c0190
+ 0x01000200
+ 0x03200040
+ 0x00020018
+ 0x00400100
+ 0x00080032
+ 0x00140000
+ 0x00030028
+ 0x01010100
+ 0x02000202
+ 0x0b000002
+ 0x01000f0f
+ 0x00000000
+ 0x00000000
+ 0x00010003
+ 0x00000c03
+ 0x00040101
+ 0x04010100
+ 0x01000000
+ 0x02010000
+ 0x00000001
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00010000
+ 0x00000001
+ 0x01010001
+ 0x05040001
+ 0x040a0703
+ 0x02080808
+ 0x020e000a
+ 0x020f010b
+ 0x000d0008
+ 0x00080b0a
+ 0x03000200
+ 0x00000100
+ 0x00000000
+ 0x00000000
+ 0x0d000001
+ 0x00000028
+ 0x00010000
+ 0x00000003
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00010100
+ 0x01000000
+ 0x00000001
+ 0x00000303
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x000556aa
+ 0x000aaaaa
+ 0x000aa955
+ 0x00055555
+ 0x000b3133
+ 0x0004cd33
+ 0x0004cecc
+ 0x000b32cc
+ 0x00010300
+ 0x03000100
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00ffff00
+ 0x1a160000
+ 0x08000012
+ 0x00000c20
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00000c20
+ 0x00007940
+ 0x18500409
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00001850
+ 0x0000f320
+ 0x0176060c
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00000176
+ 0x00000e9c
+ 0x02020205
+ 0x03030202
+ 0x00000018
+ 0x00000000
+ 0x00000000
+ 0x00001403
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00030000
+ 0x000a001c
+ 0x000e0020
+ 0x00060018
+ 0x00000000
+ 0x00000000
+ 0x02000000
+ 0x00090305
+ 0x00050101
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x01000001
+ 0x01010101
+ 0x01000101
+ 0x01000100
+ 0x00010001
+ 0x00010002
+ 0x00020100
+ 0x00000002
+ 0x00000b00
+ 0x00000000
+ 0x000002ec
+ 0x00000176
+ 0x000030a0
+ 0x00001850
+ 0x00001840
+ 0x01760c20
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00001850
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00000c20
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00000200
+ 0x00010000
+ 0x00000007
+ 0x01000001
+ 0x00000000
+ 0x3fffffff
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x0f000101
+ 0x082b3223
+ 0x080c0004
+ 0x00061c00
+ 0x00000214
+ 0x00bb0009
+ 0x0c280090
+ 0x06100048
+ 0x00000500
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x04040100
+ 0x0a000004
+ 0x00000128
+ 0x00000000
+ 0x0003000f
+ 0x00000018
+ 0x00000000
+ 0x00000000
+ 0x00060002
+ 0x00010001
+ 0x00000101
+ 0x00020001
+ 0x00080004
+ 0x00000000
+ 0x05030000
+ 0x070a0404
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x000f0f00
+ 0x0000001e
+ 0x00000000
+ 0x01010300
+ 0x00000000
+ 0x00000000
+ 0x01000000
+ 0x00000101
+ 0x55555a5a
+ 0x55555a5a
+ 0x55555a5a
+ 0x55555a5a
+ 0x0c050001
+ 0x06020009
+ 0x00010004
+ 0x00000203
+ 0x00030000
+ 0x170f0000
+ 0x00060018
+ 0x000e0020
+ 0x000a001c
+ 0x00000000
+ 0x00000000
+ 0x00000100
+ 0x140a0000
+ 0x000d010a
+ 0x0100c802
+ 0x010a0064
+ 0x000e0100
+ 0x0100000e
+ 0x00c900c9
+ 0x00650100
+ 0x1e1a0065
+ 0x10010204
+ 0x06070605
+ 0x20000202
+ 0x00201000
+ 0x00201000
+ 0x04041000
+ 0x10020100
+ 0x0003010c
+ 0x004b004a
+ 0x1a0f0000
+ 0x0102041e
+ 0x34000000
+ 0x00000000
+ 0x00000000
+ 0x00010000
+ 0x00000400
+ 0x00310000
+ 0x004d4d00
+ 0x00120024
+ 0x4d000031
+ 0x0000144d
+ 0x00310009
+ 0x004d4d00
+ 0x00000004
+ 0x4d000031
+ 0x0000244d
+ 0x00310012
+ 0x004d4d00
+ 0x00090014
+ 0x4d000031
+ 0x0004004d
+ 0x00310000
+ 0x004d4d00
+ 0x00120024
+ 0x4d000031
+ 0x0000144d
+ 0x00310009
+ 0x004d4d00
+ 0x00000004
+ 0x4d000031
+ 0x0000244d
+ 0x00310012
+ 0x004d4d00
+ 0x00090014
+ 0x4d000031
+ 0x0200004d
+ 0x00c8000d
+ 0x08080064
+ 0x040a0404
+ 0x03000d92
+ 0x010a2001
+ 0x0f11080a
+ 0x0000110a
+ 0x2200d92e
+ 0x080c2003
+ 0x0809080a
+ 0x00000a0a
+ 0x11006c97
+ 0x040a2002
+ 0x0200020a
+ 0x02000200
+ 0x02000200
+ 0x02000200
+ 0x02000200
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x01000400
+ 0x00017600
+ 0x00000e9c
+ 0x00001850
+ 0x0000f320
+ 0x00000c20
+ 0x00007940
+ 0x08000000
+ 0x00000100
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000002
+ 0x76543210
+ 0x0004f008
+ 0x00020159
+ 0x00000000
+ 0x00000000
+ 0x00010000
+ 0x01665555
+ 0x03665555
+ 0x00010f00
+ 0x04000100
+ 0x00000000
+ 0x00170180
+ 0x00cc0201
+ 0x00030066
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x04080000
+ 0x04080400
+ 0x30000000
+ 0x0c00c007
+ 0x00000100
+ 0x00000000
+ 0xfd02fe01
+ 0xf708fb04
+ 0xdf20ef10
+ 0x7f80bf40
+ 0x0001aaaa
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00200000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x02800280
+ 0x02800280
+ 0x02800280
+ 0x02800280
+ 0x00000280
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00800000
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x01590080
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000200
+ 0x00000000
+ 0x51315152
+ 0xc0003150
+ 0x010000c0
+ 0x00100c00
+ 0x07044204
+ 0x000f0c18
+ 0x01000140
+ 0x00000c10
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x76543210
+ 0x0004f008
+ 0x00020159
+ 0x00000000
+ 0x00000000
+ 0x00010000
+ 0x01665555
+ 0x03665555
+ 0x00010f00
+ 0x04000100
+ 0x00000000
+ 0x00170180
+ 0x00cc0201
+ 0x00030066
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x04080000
+ 0x04080400
+ 0x30000000
+ 0x0c00c007
+ 0x00000100
+ 0x00000000
+ 0xfd02fe01
+ 0xf708fb04
+ 0xdf20ef10
+ 0x7f80bf40
+ 0x0000aaaa
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00200000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x02800280
+ 0x02800280
+ 0x02800280
+ 0x02800280
+ 0x00000280
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00800000
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x01590080
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000200
+ 0x00000000
+ 0x51315152
+ 0xc0003150
+ 0x010000c0
+ 0x00100c00
+ 0x07044204
+ 0x000f0c18
+ 0x01000140
+ 0x00000c10
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x76543210
+ 0x0004f008
+ 0x00020159
+ 0x00000000
+ 0x00000000
+ 0x00010000
+ 0x01665555
+ 0x03665555
+ 0x00010f00
+ 0x04000100
+ 0x00000000
+ 0x00170180
+ 0x00cc0201
+ 0x00030066
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x04080000
+ 0x04080400
+ 0x30000000
+ 0x0c00c007
+ 0x00000100
+ 0x00000000
+ 0xfd02fe01
+ 0xf708fb04
+ 0xdf20ef10
+ 0x7f80bf40
+ 0x0001aaaa
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00200000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x02800280
+ 0x02800280
+ 0x02800280
+ 0x02800280
+ 0x00000280
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00800000
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x01590080
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000200
+ 0x00000000
+ 0x51315152
+ 0xc0003150
+ 0x010000c0
+ 0x00100c00
+ 0x07044204
+ 0x000f0c18
+ 0x01000140
+ 0x00000c10
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x76543210
+ 0x0004f008
+ 0x00020159
+ 0x00000000
+ 0x00000000
+ 0x00010000
+ 0x01665555
+ 0x03665555
+ 0x00010f00
+ 0x04000100
+ 0x00000000
+ 0x00170180
+ 0x00cc0201
+ 0x00030066
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x04080000
+ 0x04080400
+ 0x30000000
+ 0x0c00c007
+ 0x00000100
+ 0x00000000
+ 0xfd02fe01
+ 0xf708fb04
+ 0xdf20ef10
+ 0x7f80bf40
+ 0x0000aaaa
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00200000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x02800280
+ 0x02800280
+ 0x02800280
+ 0x02800280
+ 0x00000280
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00800000
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x00800080
+ 0x01590080
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000200
+ 0x00000000
+ 0x51315152
+ 0xc0003150
+ 0x010000c0
+ 0x00100c00
+ 0x07044204
+ 0x000f0c18
+ 0x01000140
+ 0x00000c10
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000002
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00400320
+ 0x00000040
+ 0x00dcba98
+ 0x00000000
+ 0x00dcba98
+ 0x01000000
+ 0x00020003
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x0000002a
+ 0x00000015
+ 0x00000015
+ 0x0000002a
+ 0x00000033
+ 0x0000000c
+ 0x0000000c
+ 0x00000033
+ 0x0a418820
+ 0x003f0000
+ 0x0000003f
+ 0x00030055
+ 0x03000300
+ 0x03000300
+ 0x000c0300
+ 0x42080010
+ 0x00000003
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000002
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00400320
+ 0x00000040
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x01000000
+ 0x00020003
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x0000002a
+ 0x00000015
+ 0x00000015
+ 0x0000002a
+ 0x00000033
+ 0x0000000c
+ 0x0000000c
+ 0x00000033
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00030055
+ 0x03000300
+ 0x03000300
+ 0x000c0300
+ 0x42080010
+ 0x00000003
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000002
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00400320
+ 0x00000040
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x01000000
+ 0x00020003
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x0000002a
+ 0x00000015
+ 0x00000015
+ 0x0000002a
+ 0x00000033
+ 0x0000000c
+ 0x0000000c
+ 0x00000033
+ 0x1ee6b16a
+ 0x10000000
+ 0x00000000
+ 0x00030055
+ 0x03000300
+ 0x03000300
+ 0x000c0300
+ 0x42080010
+ 0x00000003
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000005
+ 0x04000f01
+ 0x00020040
+ 0x00020055
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000050
+ 0x00000000
+ 0x01010100
+ 0x00000600
+ 0x00000000
+ 0x00006400
+ 0x09221902
+ 0x00000000
+ 0x000d1f01
+ 0x0d1f0d1f
+ 0x0d1f0d1f
+ 0x00030003
+ 0x03000300
+ 0x00000300
+ 0x09221902
+ 0x00000000
+ 0x00000000
+ 0x01020000
+ 0x00000001
+ 0x00000411
+ 0x00000411
+ 0x00000040
+ 0x00000040
+ 0x00000411
+ 0x00000411
+ 0x00004410
+ 0x00004410
+ 0x00004410
+ 0x00004410
+ 0x00004410
+ 0x00000411
+ 0x00004410
+ 0x00000411
+ 0x00004410
+ 0x00000411
+ 0x00004410
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x64000000
+ 0x00000000
+ 0x00000000
+ 0x00000108
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0x00000000
+ 0xe4000000
+ 0x00000000
+ 0x00000000
+ 0x01010000
+ 0x00000000
+ >;
+};
diff --git a/arch/arm/dts/rk3399-u-boot.dtsi b/arch/arm/dts/rk3399-u-boot.dtsi
index fcfce9a..2738a38 100644
--- a/arch/arm/dts/rk3399-u-boot.dtsi
+++ b/arch/arm/dts/rk3399-u-boot.dtsi
@@ -3,6 +3,10 @@
* Copyright (C) 2019 Jagan Teki <jagan@amarulasolutions.com>
*/
+&pmu {
+ u-boot,dm-pre-reloc;
+};
+
&sdmmc {
u-boot,dm-pre-reloc;
};
diff --git a/arch/arm/dts/stm32f469-disco-u-boot.dtsi b/arch/arm/dts/stm32f469-disco-u-boot.dtsi
index 2409cf7..5a89f13 100644
--- a/arch/arm/dts/stm32f469-disco-u-boot.dtsi
+++ b/arch/arm/dts/stm32f469-disco-u-boot.dtsi
@@ -67,7 +67,7 @@
};
qspi: quadspi@A0001000 {
- compatible = "st,stm32-qspi";
+ compatible = "st,stm32f469-qspi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xA0001000 0x1000>, <0x90000000 0x10000000>;
diff --git a/arch/arm/dts/stm32f7-u-boot.dtsi b/arch/arm/dts/stm32f7-u-boot.dtsi
index 3ba7f84..32613c9 100644
--- a/arch/arm/dts/stm32f7-u-boot.dtsi
+++ b/arch/arm/dts/stm32f7-u-boot.dtsi
@@ -44,7 +44,7 @@
};
qspi: quadspi@A0001000 {
- compatible = "st,stm32-qspi";
+ compatible = "st,stm32f469-qspi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xA0001000 0x1000>, <0x90000000 0x10000000>;
diff --git a/arch/arm/include/asm/arch-rockchip/pmu_rk3399.h b/arch/arm/include/asm/arch-rockchip/pmu_rk3399.h
new file mode 100644
index 0000000..f1096dc
--- /dev/null
+++ b/arch/arm/include/asm/arch-rockchip/pmu_rk3399.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
+ *
+ */
+
+#ifndef __SOC_ROCKCHIP_RK3399_PMU_H__
+#define __SOC_ROCKCHIP_RK3399_PMU_H__
+
+struct rk3399_pmu_regs {
+ u32 pmu_wakeup_cfg[5];
+ u32 pmu_pwrdn_con;
+ u32 pmu_pwrdn_st;
+ u32 pmu_pll_con;
+ u32 pmu_pwrmode_con;
+ u32 pmu_sft_con;
+ u32 pmu_int_con;
+ u32 pmu_int_st;
+ u32 pmu_gpio0_pos_int_con;
+ u32 pmu_gpio0_net_int_con;
+ u32 pmu_gpio1_pos_int_con;
+ u32 pmu_gpio1_net_int_con;
+ u32 pmu_gpio0_pos_int_st;
+ u32 pmu_gpio0_net_int_st;
+ u32 pmu_gpio1_pos_int_st;
+ u32 pmu_gpio1_net_int_st;
+ u32 pmu_pwrdn_inten;
+ u32 pmu_pwrdn_status;
+ u32 pmu_wakeup_status;
+ u32 pmu_bus_clr;
+ u32 pmu_bus_idle_req;
+ u32 pmu_bus_idle_st;
+ u32 pmu_bus_idle_ack;
+ u32 pmu_cci500_con;
+ u32 pmu_adb400_con;
+ u32 pmu_adb400_st;
+ u32 pmu_power_st;
+ u32 pmu_core_pwr_st;
+ u32 pmu_osc_cnt;
+ u32 pmu_plllock_cnt;
+ u32 pmu_pllrst_cnt;
+ u32 pmu_stable_cnt;
+ u32 pmu_ddrio_pwron_cnt;
+ u32 pmu_wakeup_rst_clr_cnt;
+ u32 pmu_ddr_sref_st;
+ u32 pmu_scu_l_pwrdn_cnt;
+ u32 pmu_scu_l_pwrup_cnt;
+ u32 pmu_scu_b_pwrdn_cnt;
+ u32 pmu_scu_b_pwrup_cnt;
+ u32 pmu_gpu_pwrdn_cnt;
+ u32 pmu_gpu_pwrup_cnt;
+ u32 pmu_center_pwrdn_cnt;
+ u32 pmu_center_pwrup_cnt;
+ u32 pmu_timeout_cnt;
+ u32 pmu_cpu0apm_con;
+ u32 pmu_cpu1apm_con;
+ u32 pmu_cpu2apm_con;
+ u32 pmu_cpu3apm_con;
+ u32 pmu_cpu0bpm_con;
+ u32 pmu_cpu1bpm_con;
+ u32 pmu_noc_auto_ena;
+ u32 pmu_pwrdn_con1;
+ u32 reserved0[0x4];
+ u32 pmu_sys_reg_reg0;
+ u32 pmu_sys_reg_reg1;
+ u32 pmu_sys_reg_reg2;
+ u32 pmu_sys_reg_reg3;
+};
+
+check_member(rk3399_pmu_regs, pmu_sys_reg_reg3, 0xfc);
+
+#endif /* __SOC_ROCKCHIP_RK3399_PMU_H__ */
diff --git a/arch/arm/include/asm/arch-rockchip/sdram.h b/arch/arm/include/asm/arch-rockchip/sdram.h
index bbe425d..9220763 100644
--- a/arch/arm/include/asm/arch-rockchip/sdram.h
+++ b/arch/arm/include/asm/arch-rockchip/sdram.h
@@ -8,12 +8,6 @@
#ifndef _ASM_ARCH_RK3288_SDRAM_H__
#define _ASM_ARCH_RK3288_SDRAM_H__
-enum {
- DDR3 = 3,
- LPDDR3 = 6,
- UNUSED = 0xFF,
-};
-
struct rk3288_sdram_channel {
/*
* bit width in address, eg:
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_common.h b/arch/arm/include/asm/arch-rockchip/sdram_common.h
index 671c318..8027b53 100644
--- a/arch/arm/include/asm/arch-rockchip/sdram_common.h
+++ b/arch/arm/include/asm/arch-rockchip/sdram_common.h
@@ -5,6 +5,44 @@
#ifndef _ASM_ARCH_SDRAM_COMMON_H
#define _ASM_ARCH_SDRAM_COMMON_H
+
+enum {
+ DDR4 = 0,
+ DDR3 = 0x3,
+ LPDDR2 = 0x5,
+ LPDDR3 = 0x6,
+ LPDDR4 = 0x7,
+ UNUSED = 0xFF
+};
+
+struct sdram_cap_info {
+ unsigned int rank;
+ /* dram column number, 0 means this channel is invalid */
+ unsigned int col;
+ /* dram bank number, 3:8bank, 2:4bank */
+ unsigned int bk;
+ /* channel buswidth, 2:32bit, 1:16bit, 0:8bit */
+ unsigned int bw;
+ /* die buswidth, 2:32bit, 1:16bit, 0:8bit */
+ unsigned int dbw;
+ /*
+ * row_3_4 = 1: 6Gb or 12Gb die
+ * row_3_4 = 0: normal die, power of 2
+ */
+ unsigned int row_3_4;
+ unsigned int cs0_row;
+ unsigned int cs1_row;
+ unsigned int ddrconfig;
+};
+
+struct sdram_base_params {
+ unsigned int ddr_freq;
+ unsigned int dramtype;
+ unsigned int num_channels;
+ unsigned int stride;
+ unsigned int odt;
+};
+
/*
* sys_reg bitfield struct
* [31] row_3_4_ch1
@@ -28,30 +66,82 @@
* [1:0] dbw_ch0
*/
#define SYS_REG_DDRTYPE_SHIFT 13
+#define DDR_SYS_REG_VERSION 2
#define SYS_REG_DDRTYPE_MASK 7
#define SYS_REG_NUM_CH_SHIFT 12
#define SYS_REG_NUM_CH_MASK 1
#define SYS_REG_ROW_3_4_SHIFT(ch) (30 + (ch))
#define SYS_REG_ROW_3_4_MASK 1
+#define SYS_REG_ENC_ROW_3_4(n, ch) ((n) << (30 + (ch)))
#define SYS_REG_CHINFO_SHIFT(ch) (28 + (ch))
+#define SYS_REG_ENC_CHINFO(ch) (1 << SYS_REG_CHINFO_SHIFT(ch))
+#define SYS_REG_ENC_DDRTYPE(n) ((n) << SYS_REG_DDRTYPE_SHIFT)
+#define SYS_REG_ENC_NUM_CH(n) (((n) - SYS_REG_NUM_CH_MASK) << \
+ SYS_REG_NUM_CH_SHIFT)
#define SYS_REG_RANK_SHIFT(ch) (11 + (ch) * 16)
#define SYS_REG_RANK_MASK 1
+#define SYS_REG_ENC_RANK(n, ch) (((n) - SYS_REG_RANK_MASK) << \
+ SYS_REG_RANK_SHIFT(ch))
#define SYS_REG_COL_SHIFT(ch) (9 + (ch) * 16)
#define SYS_REG_COL_MASK 3
+#define SYS_REG_ENC_COL(n, ch) (((n) - 9) << SYS_REG_COL_SHIFT(ch))
#define SYS_REG_BK_SHIFT(ch) (8 + (ch) * 16)
#define SYS_REG_BK_MASK 1
+#define SYS_REG_ENC_BK(n, ch) (((n) == 3 ? 0 : 1) << \
+ SYS_REG_BK_SHIFT(ch))
#define SYS_REG_CS0_ROW_SHIFT(ch) (6 + (ch) * 16)
#define SYS_REG_CS0_ROW_MASK 3
#define SYS_REG_CS1_ROW_SHIFT(ch) (4 + (ch) * 16)
#define SYS_REG_CS1_ROW_MASK 3
#define SYS_REG_BW_SHIFT(ch) (2 + (ch) * 16)
#define SYS_REG_BW_MASK 3
+#define SYS_REG_ENC_BW(n, ch) ((2 >> (n)) << SYS_REG_BW_SHIFT(ch))
#define SYS_REG_DBW_SHIFT(ch) ((ch) * 16)
#define SYS_REG_DBW_MASK 3
+#define SYS_REG_ENC_DBW(n, ch) ((2 >> (n)) << SYS_REG_DBW_SHIFT(ch))
+
+#define SYS_REG_ENC_VERSION(n) ((n) << 28)
+#define SYS_REG_ENC_CS0_ROW(n, os_reg2, os_reg3, ch) do { \
+ (os_reg2) |= (((n) - 13) & 0x3) << (6 + 16 * (ch)); \
+ (os_reg3) |= ((((n) - 13) & 0x4) >> 2) << \
+ (5 + 2 * (ch)); \
+ } while (0)
+
+#define SYS_REG_ENC_CS1_ROW(n, os_reg2, os_reg3, ch) do { \
+ (os_reg2) &= (~(0x3 << (4 + 16 * (ch)))); \
+ (os_reg3) &= (~(0x1 << (4 + 2 * (ch)))); \
+ (os_reg2) |= (((n) - 13) & 0x3) << (4 + 16 * (ch)); \
+ (os_reg3) |= ((((n) - 13) & 0x4) >> 2) << \
+ (4 + 2 * (ch)); \
+ } while (0)
+
+#define SYS_REG_CS1_COL_SHIFT(ch) (0 + 2 * (ch))
+#define SYS_REG_ENC_CS1_COL(n, ch) (((n) - 9) << SYS_REG_CS1_COL_SHIFT(ch))
/* Get sdram size decode from reg */
size_t rockchip_sdram_size(phys_addr_t reg);
/* Called by U-Boot board_init_r for Rockchip SoCs */
int dram_init(void);
+
+#if !defined(CONFIG_RAM_ROCKCHIP_DEBUG)
+inline void sdram_print_dram_type(unsigned char dramtype)
+{
+}
+
+inline void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
+ struct sdram_base_params *base)
+{
+}
+
+inline void sdram_print_stride(unsigned int stride)
+{
+}
+#else
+void sdram_print_dram_type(unsigned char dramtype);
+void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
+ struct sdram_base_params *base);
+void sdram_print_stride(unsigned int stride);
+#endif /* CONFIG_RAM_ROCKCHIP_DEBUG */
+
#endif
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_rk322x.h b/arch/arm/include/asm/arch-rockchip/sdram_rk322x.h
index d0091a7..336c5d7 100644
--- a/arch/arm/include/asm/arch-rockchip/sdram_rk322x.h
+++ b/arch/arm/include/asm/arch-rockchip/sdram_rk322x.h
@@ -7,13 +7,6 @@
#include <common.h>
-enum {
- DDR3 = 3,
- LPDDR2 = 5,
- LPDDR3 = 6,
- UNUSED = 0xFF,
-};
-
struct rk322x_sdram_channel {
/*
* bit width in address, eg:
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h b/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
index c6a260b..dc65ae7 100644
--- a/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
+++ b/arch/arm/include/asm/arch-rockchip/sdram_rk3399.h
@@ -6,14 +6,6 @@
#ifndef _ASM_ARCH_SDRAM_RK3399_H
#define _ASM_ARCH_SDRAM_RK3399_H
-enum {
- DDR3 = 0x3,
- LPDDR2 = 0x5,
- LPDDR3 = 0x6,
- LPDDR4 = 0x7,
- UNUSED = 0xFF
-};
-
struct rk3399_ddr_pctl_regs {
u32 denali_ctl[332];
};
@@ -26,6 +18,31 @@
u32 denali_pi[200];
};
+union noc_ddrtimingc0 {
+ u32 d32;
+ struct {
+ unsigned burstpenalty : 4;
+ unsigned reserved0 : 4;
+ unsigned wrtomwr : 6;
+ unsigned reserved1 : 18;
+ } b;
+};
+
+union noc_ddrmode {
+ u32 d32;
+ struct {
+ unsigned autoprecharge : 1;
+ unsigned bypassfiltering : 1;
+ unsigned fawbank : 1;
+ unsigned burstsize : 2;
+ unsigned mwrsize : 2;
+ unsigned reserved2 : 1;
+ unsigned forceorder : 8;
+ unsigned forceorderstate : 8;
+ unsigned reserved3 : 8;
+ } b;
+};
+
struct rk3399_msch_regs {
u32 coreid;
u32 revisionid;
@@ -44,9 +61,9 @@
struct rk3399_msch_timings {
u32 ddrtiminga0;
u32 ddrtimingb0;
- u32 ddrtimingc0;
+ union noc_ddrtimingc0 ddrtimingc0;
u32 devtodev0;
- u32 ddrmode;
+ union noc_ddrmode ddrmode;
u32 agingx0;
};
@@ -72,37 +89,13 @@
#define MEM_RST_VALID 1
struct rk3399_sdram_channel {
- unsigned int rank;
- /* dram column number, 0 means this channel is invalid */
- unsigned int col;
- /* dram bank number, 3:8bank, 2:4bank */
- unsigned int bk;
- /* channel buswidth, 2:32bit, 1:16bit, 0:8bit */
- unsigned int bw;
- /* die buswidth, 2:32bit, 1:16bit, 0:8bit */
- unsigned int dbw;
- /*
- * row_3_4 = 1: 6Gb or 12Gb die
- * row_3_4 = 0: normal die, power of 2
- */
- unsigned int row_3_4;
- unsigned int cs0_row;
- unsigned int cs1_row;
- unsigned int ddrconfig;
+ struct sdram_cap_info cap_info;
struct rk3399_msch_timings noc_timings;
};
-struct rk3399_base_params {
- unsigned int ddr_freq;
- unsigned int dramtype;
- unsigned int num_channels;
- unsigned int stride;
- unsigned int odt;
-};
-
struct rk3399_sdram_params {
struct rk3399_sdram_channel ch[2];
- struct rk3399_base_params base;
+ struct sdram_base_params base;
struct rk3399_ddr_pctl_regs pctl_regs;
struct rk3399_ddr_pi_regs pi_regs;
struct rk3399_ddr_publ_regs phy_regs;
diff --git a/arch/arm/include/asm/arch-rockchip/sys_proto.h b/arch/arm/include/asm/arch-rockchip/sys_proto.h
index 928e4f2..905c774 100644
--- a/arch/arm/include/asm/arch-rockchip/sys_proto.h
+++ b/arch/arm/include/asm/arch-rockchip/sys_proto.h
@@ -6,28 +6,6 @@
#ifndef _ASM_ARCH_SYS_PROTO_H
#define _ASM_ARCH_SYS_PROTO_H
-#ifdef CONFIG_ROCKCHIP_RK3288
-#include <asm/armv7.h>
-
-static void configure_l2ctlr(void)
-{
- uint32_t l2ctlr;
-
- l2ctlr = read_l2ctlr();
- l2ctlr &= 0xfffc0000; /* clear bit0~bit17 */
-
- /*
- * Data RAM write latency: 2 cycles
- * Data RAM read latency: 2 cycles
- * Data RAM setup latency: 1 cycle
- * Tag RAM write latency: 1 cycle
- * Tag RAM read latency: 1 cycle
- * Tag RAM setup latency: 1 cycle
- */
- l2ctlr |= (1 << 3 | 1 << 0);
- write_l2ctlr(l2ctlr);
-}
-#endif /* CONFIG_ROCKCHIP_RK3288 */
/* provided to defeat compiler optimisation in board_init_f() */
void gru_dummy_function(int i);
diff --git a/arch/arm/include/asm/arch-rockchip/timer.h b/arch/arm/include/asm/arch-rockchip/timer.h
index a8379be..77b5422 100644
--- a/arch/arm/include/asm/arch-rockchip/timer.h
+++ b/arch/arm/include/asm/arch-rockchip/timer.h
@@ -15,7 +15,4 @@
u32 timer_int_status;
};
-void rockchip_timer_init(void);
-void rockchip_udelay(unsigned int usec);
-
#endif
diff --git a/arch/arm/include/asm/omap_i2c.h b/arch/arm/include/asm/omap_i2c.h
index c1695cb..a697540 100644
--- a/arch/arm/include/asm/omap_i2c.h
+++ b/arch/arm/include/asm/omap_i2c.h
@@ -3,8 +3,6 @@
#ifndef _OMAP_I2C_H
#define _OMAP_I2C_H
-#include <asm/arch/cpu.h>
-
#ifdef CONFIG_DM_I2C
/* Information about a GPIO bank */
diff --git a/arch/arm/include/asm/proc-armv/ptrace.h b/arch/arm/include/asm/proc-armv/ptrace.h
index 183b00a..e37ad8f 100644
--- a/arch/arm/include/asm/proc-armv/ptrace.h
+++ b/arch/arm/include/asm/proc-armv/ptrace.h
@@ -86,7 +86,7 @@
#define user_mode(regs) \
(((regs)->ARM_cpsr & 0xf) == 0)
-#ifdef CONFIG_ARM_THUMB
+#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
#define thumb_mode(regs) \
(((regs)->ARM_cpsr & T_BIT))
#else
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index aed2e3c..a1a5e35 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -516,6 +516,21 @@
*/
void mmu_page_table_flush(unsigned long start, unsigned long stop);
+#ifdef CONFIG_ARMV7_PSCI
+void psci_arch_cpu_entry(void);
+u32 psci_version(void);
+s32 psci_features(u32 function_id, u32 psci_fid);
+s32 psci_cpu_off(void);
+s32 psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
+ u32 context_id);
+s32 psci_affinity_info(u32 function_id, u32 target_affinity,
+ u32 lowest_affinity_level);
+u32 psci_migrate_info_type(void);
+void psci_system_off(void);
+void psci_system_reset(void);
+s32 psci_features(u32 function_id, u32 psci_fid);
+#endif
+
#endif /* __ASSEMBLY__ */
#define arch_align_stack(x) (x)
diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S
index 30fba20..c74641d 100644
--- a/arch/arm/lib/crt0.S
+++ b/arch/arm/lib/crt0.S
@@ -58,6 +58,33 @@
*/
/*
+ * Macro for clearing BSS during SPL execution. Usually called during the
+ * relocation process for most boards before entering board_init_r(), but
+ * can also be done early before entering board_init_f() on plaforms that
+ * can afford it due to sufficient memory being available early.
+ */
+
+.macro SPL_CLEAR_BSS
+ ldr r0, =__bss_start /* this is auto-relocated! */
+
+#ifdef CONFIG_USE_ARCH_MEMSET
+ ldr r3, =__bss_end /* this is auto-relocated! */
+ mov r1, #0x00000000 /* prepare zero to clear BSS */
+
+ subs r2, r3, r0 /* r2 = memset len */
+ bl memset
+#else
+ ldr r1, =__bss_end /* this is auto-relocated! */
+ mov r2, #0x00000000 /* prepare zero to clear BSS */
+
+clbss_l:cmp r0, r1 /* while not at end of BSS */
+ strlo r2, [r0] /* clear 32-bit BSS word */
+ addlo r0, r0, #4 /* move to next */
+ blo clbss_l
+#endif
+.endm
+
+/*
* entry point of crt0 sequence
*/
@@ -82,6 +109,10 @@
mov r9, r0
bl board_init_f_init_reserve
+#if defined(CONFIG_SPL_EARLY_BSS)
+ SPL_CLEAR_BSS
+#endif
+
mov r0, #0
bl board_init_f
@@ -119,6 +150,11 @@
bl c_runtime_cpu_setup /* we still call old routine here */
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
+
+#if !defined(CONFIG_SPL_EARLY_BSS)
+ SPL_CLEAR_BSS
+#endif
+
# ifdef CONFIG_SPL_BUILD
/* Use a DRAM stack for the rest of SPL, if requested */
bl spl_relocate_stack_gd
@@ -126,23 +162,6 @@
movne sp, r0
movne r9, r0
# endif
- ldr r0, =__bss_start /* this is auto-relocated! */
-
-#ifdef CONFIG_USE_ARCH_MEMSET
- ldr r3, =__bss_end /* this is auto-relocated! */
- mov r1, #0x00000000 /* prepare zero to clear BSS */
-
- subs r2, r3, r0 /* r2 = memset len */
- bl memset
-#else
- ldr r1, =__bss_end /* this is auto-relocated! */
- mov r2, #0x00000000 /* prepare zero to clear BSS */
-
-clbss_l:cmp r0, r1 /* while not at end of BSS */
- strlo r2, [r0] /* clear 32-bit BSS word */
- addlo r0, r0, #4 /* move to next */
- blo clbss_l
-#endif
#if ! defined(CONFIG_SPL_BUILD)
bl coloured_LED_init
diff --git a/arch/arm/lib/crt0_aarch64_efi.S b/arch/arm/lib/crt0_aarch64_efi.S
index cb205fa..368933e 100644
--- a/arch/arm/lib/crt0_aarch64_efi.S
+++ b/arch/arm/lib/crt0_aarch64_efi.S
@@ -17,14 +17,13 @@
*/
.globl ImageBase
ImageBase:
- .ascii "MZ"
+ .short IMAGE_DOS_SIGNATURE /* 'MZ' */
.skip 58 /* 'MZ' + pad + offset == 64 */
.long pe_header - ImageBase /* Offset to the PE header */
pe_header:
- .ascii "PE"
- .short 0
+ .long IMAGE_NT_SIGNATURE /* 'PE' */
coff_header:
- .short 0xaa64 /* AArch64 */
+ .short IMAGE_FILE_MACHINE_ARM64 /* AArch64 */
.short 2 /* nr_sections */
.long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */
@@ -36,7 +35,7 @@
IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
IMAGE_FILE_DEBUG_STRIPPED)
optional_header:
- .short 0x20b /* PE32+ format */
+ .short IMAGE_NT_OPTIONAL_HDR64_MAGIC /* PE32+ format */
.byte 0x02 /* MajorLinkerVersion */
.byte 0x14 /* MinorLinkerVersion */
.long _edata - _start /* SizeOfCode */
diff --git a/arch/arm/lib/crt0_arm_efi.S b/arch/arm/lib/crt0_arm_efi.S
index 5470e2f..cc8a115 100644
--- a/arch/arm/lib/crt0_arm_efi.S
+++ b/arch/arm/lib/crt0_arm_efi.S
@@ -16,14 +16,13 @@
*/
.globl image_base
image_base:
- .ascii "MZ"
+ .short IMAGE_DOS_SIGNATURE /* 'MZ' */
.skip 58 /* 'MZ' + pad + offset == 64 */
.long pe_header - image_base /* Offset to the PE header */
pe_header:
- .ascii "PE"
- .short 0
+ .long IMAGE_NT_SIGNATURE /* 'PE' */
coff_header:
- .short 0x1c2 /* Mixed ARM/Thumb */
+ .short IMAGE_FILE_MACHINE_THUMB /* Mixed ARM/Thumb */
.short 2 /* nr_sections */
.long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */
@@ -36,7 +35,7 @@
IMAGE_FILE_32BIT_MACHINE | \
IMAGE_FILE_DEBUG_STRIPPED)
optional_header:
- .short 0x10b /* PE32 format */
+ .short IMAGE_NT_OPTIONAL_HDR32_MAGIC /* PE32 format */
.byte 0x02 /* MajorLinkerVersion */
.byte 0x14 /* MinorLinkerVersion */
.long _edata - _start /* SizeOfCode */
diff --git a/arch/arm/mach-davinci/cpu.c b/arch/arm/mach-davinci/cpu.c
index f97ad3f..9fd6564 100644
--- a/arch/arm/mach-davinci/cpu.c
+++ b/arch/arm/mach-davinci/cpu.c
@@ -5,7 +5,6 @@
*/
#include <common.h>
-#include <netdev.h>
#include <asm/arch/hardware.h>
#include <asm/io.h>
@@ -90,15 +89,3 @@
gd->bd->bi_dsp_freq = 0;
return 0;
}
-
-/*
- * Initializes on-chip ethernet controllers.
- * to override, implement board_eth_init()
- */
-int cpu_eth_init(bd_t *bis)
-{
-#if defined(CONFIG_DRIVER_TI_EMAC)
- davinci_emac_initialize();
-#endif
- return 0;
-}
diff --git a/arch/arm/mach-imx/mx7/psci-mx7.c b/arch/arm/mach-imx/mx7/psci-mx7.c
index 34ba0a9..c98d2e9 100644
--- a/arch/arm/mach-imx/mx7/psci-mx7.c
+++ b/arch/arm/mach-imx/mx7/psci-mx7.c
@@ -298,7 +298,7 @@
return psci_state[cpu];
}
-__secure s32 psci_migrate_info_type(u32 function_id)
+__secure u32 psci_migrate_info_type(void)
{
/* Trusted OS is either not present or does not require migration */
return 2;
diff --git a/arch/arm/mach-k3/Kconfig b/arch/arm/mach-k3/Kconfig
index e677a2e..f25f822 100644
--- a/arch/arm/mach-k3/Kconfig
+++ b/arch/arm/mach-k3/Kconfig
@@ -58,6 +58,45 @@
int
default 16
+config K3_LOAD_SYSFW
+ bool
+ depends on SPL
+
+config K3_SYSFW_IMAGE_NAME
+ string "File name of SYSFW firmware and configuration blob"
+ depends on K3_LOAD_SYSFW
+ default "sysfw.itb"
+ help
+ Filename of the combined System Firmware and configuration image tree
+ blob to be loaded when booting from a filesystem.
+
+config K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT
+ hex "MMC sector to load SYSFW firmware and configuration blob from"
+ depends on K3_LOAD_SYSFW && SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+ default 0x3600
+ help
+ Address on the MMC to load the combined System Firmware and
+ configuration image tree blob from, when the MMC is being used
+ in raw mode. Units: MMC sectors (1 sector = 512 bytes).
+
+config K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART
+ hex "MMC partition to load SYSFW firmware and configuration blob from"
+ depends on K3_LOAD_SYSFW && SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+ default 2
+ help
+ Partition on the MMC to the combined System Firmware and configuration
+ image tree blob from, when the MMC is being used in raw mode.
+
+config K3_SYSFW_IMAGE_SIZE_MAX
+ int "Amount of memory dynamically allocated for loading SYSFW blob"
+ depends on K3_LOAD_SYSFW
+ default 269000
+ help
+ Amount of memory (in bytes) reserved through dynamic allocation at
+ runtime for loading the combined System Firmware and configuration image
+ tree blob. Keep it as tight as possible, as this directly affects the
+ overall SPL memory footprint.
+
config SYS_K3_SPL_ATF
bool "Start Cortex-A from SPL"
depends on SPL && CPU_V7R
diff --git a/arch/arm/mach-k3/Makefile b/arch/arm/mach-k3/Makefile
index 0c3a4f7..3af7f2e 100644
--- a/arch/arm/mach-k3/Makefile
+++ b/arch/arm/mach-k3/Makefile
@@ -7,4 +7,7 @@
obj-$(CONFIG_ARM64) += arm64-mmu.o
obj-$(CONFIG_CPU_V7R) += r5_mpu.o lowlevel_init.o
obj-$(CONFIG_TI_SECURE_DEVICE) += security.o
+ifeq ($(CONFIG_SPL_BUILD),y)
+obj-$(CONFIG_K3_LOAD_SYSFW) += sysfw-loader.o
+endif
obj-y += common.o
diff --git a/arch/arm/mach-k3/am6_init.c b/arch/arm/mach-k3/am6_init.c
index 60a5803..cb96581 100644
--- a/arch/arm/mach-k3/am6_init.c
+++ b/arch/arm/mach-k3/am6_init.c
@@ -10,8 +10,12 @@
#include <asm/io.h>
#include <spl.h>
#include <asm/arch/hardware.h>
+#include <asm/arch/sysfw-loader.h>
+#include <asm/arch/sys_proto.h>
#include "common.h"
#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <dm/pinctrl.h>
#ifdef CONFIG_SPL_BUILD
static void mmr_unlock(u32 base, u32 partition)
@@ -63,7 +67,7 @@
void board_init_f(ulong dummy)
{
-#if defined(CONFIG_K3_AM654_DDRSS)
+#if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM654_DDRSS)
struct udevice *dev;
int ret;
#endif
@@ -83,8 +87,33 @@
/* Init DM early in-order to invoke system controller */
spl_early_init();
+#ifdef CONFIG_K3_LOAD_SYSFW
+ /*
+ * Process pinctrl for the serial0 a.k.a. WKUP_UART0 module and continue
+ * regardless of the result of pinctrl. Do this without probing the
+ * device, but instead by searching the device that would request the
+ * given sequence number if probed. The UART will be used by the system
+ * firmware (SYSFW) image for various purposes and SYSFW depends on us
+ * to initialize its pin settings.
+ */
+ ret = uclass_find_device_by_seq(UCLASS_SERIAL, 0, true, &dev);
+ if (!ret)
+ pinctrl_select_state(dev, "default");
+
+ /*
+ * Load, start up, and configure system controller firmware. Provide
+ * the U-Boot console init function to the SYSFW post-PM configuration
+ * callback hook, effectively switching on (or over) the console
+ * output.
+ */
+ k3_sysfw_loader(preloader_console_init);
+#else
/* Prepare console output */
preloader_console_init();
+#endif
+
+ /* Perform EEPROM-based board detection */
+ do_board_detect();
#ifdef CONFIG_K3_AM654_DDRSS
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
diff --git a/arch/arm/mach-k3/include/mach/am6_hardware.h b/arch/arm/mach-k3/include/mach/am6_hardware.h
index 3343233..6df7631 100644
--- a/arch/arm/mach-k3/include/mach/am6_hardware.h
+++ b/arch/arm/mach-k3/include/mach/am6_hardware.h
@@ -44,4 +44,7 @@
#define CTRLMMR_LOCK_KICK1 0x0100c
#define CTRLMMR_LOCK_KICK1_UNLOCK_VAL 0xd172bc5a
+/* MCU SCRATCHPAD usage */
+#define TI_SRAM_SCRATCH_BOARD_EEPROM_START CONFIG_SYS_K3_MCU_SCRATCHPAD_BASE
+
#endif /* __ASM_ARCH_AM6_HARDWARE_H */
diff --git a/arch/arm/mach-k3/include/mach/sys_proto.h b/arch/arm/mach-k3/include/mach/sys_proto.h
index 018725b..787a274 100644
--- a/arch/arm/mach-k3/include/mach/sys_proto.h
+++ b/arch/arm/mach-k3/include/mach/sys_proto.h
@@ -12,4 +12,6 @@
u32 bound);
struct ti_sci_handle *get_ti_sci_handle(void);
int fdt_fixup_msmc_ram(void *blob, char *parent_path, char *node_name);
+int do_board_detect(void);
+
#endif
diff --git a/arch/arm/mach-k3/include/mach/sysfw-loader.h b/arch/arm/mach-k3/include/mach/sysfw-loader.h
new file mode 100644
index 0000000..36eb265
--- /dev/null
+++ b/arch/arm/mach-k3/include/mach/sysfw-loader.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Andreas Dannenberg <dannenberg@ti.com>
+ */
+
+#ifndef _SYSFW_LOADER_H_
+#define _SYSFW_LOADER_H_
+
+void k3_sysfw_loader(void (*config_pm_done_callback)(void));
+
+#endif
diff --git a/arch/arm/mach-k3/sysfw-loader.c b/arch/arm/mach-k3/sysfw-loader.c
new file mode 100644
index 0000000..2ede820
--- /dev/null
+++ b/arch/arm/mach-k3/sysfw-loader.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * K3: System Firmware Loader
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Andreas Dannenberg <dannenberg@ti.com>
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <malloc.h>
+#include <remoteproc.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+#include <asm/arch/sys_proto.h>
+
+/* Name of the FIT image nodes for SYSFW and its config data */
+#define SYSFW_FIRMWARE "sysfw.bin"
+#define SYSFW_CFG_BOARD "board-cfg.bin"
+#define SYSFW_CFG_PM "pm-cfg.bin"
+#define SYSFW_CFG_RM "rm-cfg.bin"
+#define SYSFW_CFG_SEC "sec-cfg.bin"
+
+static bool sysfw_loaded;
+static void *sysfw_load_address;
+
+/*
+ * Populate SPL hook to override the default load address used by the SPL
+ * loader function with a custom address for SYSFW loading.
+ */
+struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+{
+ if (sysfw_loaded)
+ return (struct image_header *)(CONFIG_SYS_TEXT_BASE + offset);
+ else if (sysfw_load_address)
+ return sysfw_load_address;
+ else
+ panic("SYSFW load address not defined!");
+}
+
+/*
+ * Populate SPL hook to skip the default SPL loader FIT post-processing steps
+ * during SYSFW loading and return to the calling function so we can perform
+ * our own custom processing.
+ */
+bool spl_load_simple_fit_skip_processing(void)
+{
+ return !sysfw_loaded;
+}
+
+static int fit_get_data_by_name(const void *fit, int images, const char *name,
+ const void **addr, size_t *size)
+{
+ int node_offset;
+
+ node_offset = fdt_subnode_offset(fit, images, name);
+ if (node_offset < 0)
+ return -ENOENT;
+
+ return fit_image_get_data(fit, node_offset, addr, size);
+}
+
+static void k3_sysfw_load_using_fit(void *fit)
+{
+ int images;
+ const void *sysfw_addr;
+ size_t sysfw_size;
+ int ret;
+
+ /* Find the node holding the images information */
+ images = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images < 0)
+ panic("Cannot find /images node (%d)\n", images);
+
+ /* Extract System Firmware (SYSFW) image from FIT */
+ ret = fit_get_data_by_name(fit, images, SYSFW_FIRMWARE,
+ &sysfw_addr, &sysfw_size);
+ if (ret < 0)
+ panic("Error accessing %s node in FIT (%d)\n", SYSFW_FIRMWARE,
+ ret);
+
+ /*
+ * Start up system controller firmware
+ *
+ * It is assumed that remoteproc device 0 is the corresponding
+ * system-controller that runs SYSFW. Make sure DT reflects the same.
+ */
+ ret = rproc_dev_init(0);
+ if (ret)
+ panic("rproc failed to be initialized (%d)\n", ret);
+
+ ret = rproc_load(0, (ulong)sysfw_addr, (ulong)sysfw_size);
+ if (ret)
+ panic("Firmware failed to start on rproc (%d)\n", ret);
+
+ ret = rproc_start(0);
+ if (ret)
+ panic("Firmware init failed on rproc (%d)\n", ret);
+}
+
+static void k3_sysfw_configure_using_fit(void *fit,
+ struct ti_sci_handle *ti_sci)
+{
+ struct ti_sci_board_ops *board_ops = &ti_sci->ops.board_ops;
+ int images;
+ const void *cfg_fragment_addr;
+ size_t cfg_fragment_size;
+ int ret;
+
+ /* Find the node holding the images information */
+ images = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images < 0)
+ panic("Cannot find /images node (%d)\n", images);
+
+ /* Extract board configuration from FIT */
+ ret = fit_get_data_by_name(fit, images, SYSFW_CFG_BOARD,
+ &cfg_fragment_addr, &cfg_fragment_size);
+ if (ret < 0)
+ panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_BOARD,
+ ret);
+
+ /* Apply board configuration to SYSFW */
+ ret = board_ops->board_config(ti_sci,
+ (u64)(u32)cfg_fragment_addr,
+ (u32)cfg_fragment_size);
+ if (ret)
+ panic("Failed to set board configuration (%d)\n", ret);
+
+ /* Extract power/clock (PM) specific configuration from FIT */
+ ret = fit_get_data_by_name(fit, images, SYSFW_CFG_PM,
+ &cfg_fragment_addr, &cfg_fragment_size);
+ if (ret < 0)
+ panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_PM,
+ ret);
+
+ /* Apply power/clock (PM) specific configuration to SYSFW */
+ ret = board_ops->board_config_pm(ti_sci,
+ (u64)(u32)cfg_fragment_addr,
+ (u32)cfg_fragment_size);
+ if (ret)
+ panic("Failed to set board PM configuration (%d)\n", ret);
+
+ /* Extract resource management (RM) specific configuration from FIT */
+ ret = fit_get_data_by_name(fit, images, SYSFW_CFG_RM,
+ &cfg_fragment_addr, &cfg_fragment_size);
+ if (ret < 0)
+ panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_RM,
+ ret);
+
+ /* Apply resource management (RM) configuration to SYSFW */
+ ret = board_ops->board_config_rm(ti_sci,
+ (u64)(u32)cfg_fragment_addr,
+ (u32)cfg_fragment_size);
+ if (ret)
+ panic("Failed to set board RM configuration (%d)\n", ret);
+
+ /* Extract security specific configuration from FIT */
+ ret = fit_get_data_by_name(fit, images, SYSFW_CFG_SEC,
+ &cfg_fragment_addr, &cfg_fragment_size);
+ if (ret < 0)
+ panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_SEC,
+ ret);
+
+ /* Apply security configuration to SYSFW */
+ ret = board_ops->board_config_security(ti_sci,
+ (u64)(u32)cfg_fragment_addr,
+ (u32)cfg_fragment_size);
+ if (ret)
+ panic("Failed to set board security configuration (%d)\n",
+ ret);
+}
+
+void k3_sysfw_loader(void (*config_pm_done_callback)(void))
+{
+ struct spl_image_info spl_image = { 0 };
+ struct spl_boot_device bootdev = { 0 };
+ struct ti_sci_handle *ti_sci;
+ int ret;
+
+ /* Reserve a block of aligned memory for loading the SYSFW image */
+ sysfw_load_address = memalign(ARCH_DMA_MINALIGN,
+ CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
+ if (!sysfw_load_address)
+ panic("Error allocating %u bytes of memory for SYSFW image\n",
+ CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
+
+ debug("%s: allocated %u bytes at 0x%p\n", __func__,
+ CONFIG_K3_SYSFW_IMAGE_SIZE_MAX, sysfw_load_address);
+
+ /* Set load address for legacy modes that bypass spl_get_load_buffer */
+ spl_image.load_addr = (uintptr_t)sysfw_load_address;
+
+ bootdev.boot_device = spl_boot_device();
+
+ /* Load combined System Controller firmware and config data image */
+ switch (bootdev.boot_device) {
+#if CONFIG_IS_ENABLED(MMC_SUPPORT)
+ case BOOT_DEVICE_MMC1:
+ case BOOT_DEVICE_MMC2:
+ case BOOT_DEVICE_MMC2_2:
+ ret = spl_mmc_load(&spl_image, &bootdev,
+#ifdef CONFIG_K3_SYSFW_IMAGE_NAME
+ CONFIG_K3_SYSFW_IMAGE_NAME,
+#else
+ NULL,
+#endif
+#ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART
+ CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART,
+#else
+ 0,
+#endif
+#ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT
+ CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT);
+#else
+ 0);
+#endif
+ break;
+#endif
+ default:
+ panic("Loading SYSFW image from device %u not supported!\n",
+ bootdev.boot_device);
+ }
+
+ if (ret)
+ panic("Error %d occurred during loading SYSFW image!\n", ret);
+
+ /*
+ * Now that SYSFW got loaded set helper flag to restore regular SPL
+ * loader behavior so we can later boot into the next stage as expected.
+ */
+ sysfw_loaded = true;
+
+ /* Ensure the SYSFW image is in FIT format */
+ if (image_get_magic((const image_header_t *)sysfw_load_address) !=
+ FDT_MAGIC)
+ panic("SYSFW image not in FIT format!\n");
+
+ /* Extract and start SYSFW */
+ k3_sysfw_load_using_fit(sysfw_load_address);
+
+ /* Get handle for accessing SYSFW services */
+ ti_sci = get_ti_sci_handle();
+
+ /* Parse and apply the different SYSFW configuration fragments */
+ k3_sysfw_configure_using_fit(sysfw_load_address, ti_sci);
+
+ /*
+ * Now that all clocks and PM aspects are setup, invoke a user-
+ * provided callback function. Usually this callback would be used
+ * to setup or re-configure the U-Boot console UART.
+ */
+ if (config_pm_done_callback)
+ config_pm_done_callback();
+
+ /* Output System Firmware version info */
+ printf("SYSFW ABI: %d.%d (firmware rev 0x%04x '%.*s')\n",
+ ti_sci->version.abi_major, ti_sci->version.abi_minor,
+ ti_sci->version.firmware_revision,
+ sizeof(ti_sci->version.firmware_description),
+ ti_sci->version.firmware_description);
+}
diff --git a/arch/arm/mach-mediatek/mt7629/lowlevel_init.S b/arch/arm/mach-mediatek/mt7629/lowlevel_init.S
index 3375796..0a0672c 100644
--- a/arch/arm/mach-mediatek/mt7629/lowlevel_init.S
+++ b/arch/arm/mach-mediatek/mt7629/lowlevel_init.S
@@ -4,6 +4,7 @@
*/
#include <linux/linkage.h>
+#include <asm/proc-armv/ptrace.h>
#define WAIT_CODE_SRAM_BASE 0x0010ff00
@@ -27,6 +28,18 @@
movt r0, #0x131
mcr p15, 0, r0, c14, c0, 0
+ cps #MON_MODE
+ mrc p15, 0, r1, c1, c1, 0 @ Get Secure Config
+ orr r0, r1, #1
+ mcr p15, 0, r0, c1, c1, 0 @ Set Non Secure bit
+ isb
+ mov r0, #0
+ mcrr p15, 4, r0, r0, c14 @ CNTVOFF = 0
+ isb
+ mcr p15, 0, r1, c1, c1, 0 @ Set Secure bit
+ isb
+ cps #SVC_MODE
+
/* enable SMP bit */
mrc p15, 0, r0, c1, c0, 1
orr r0, r0, #0x40
diff --git a/arch/arm/mach-omap2/omap3/emac.c b/arch/arm/mach-omap2/omap3/emac.c
index c79e870..fb0c918 100644
--- a/arch/arm/mach-omap2/omap3/emac.c
+++ b/arch/arm/mach-omap2/omap3/emac.c
@@ -7,7 +7,6 @@
*/
#include <common.h>
-#include <netdev.h>
#include <asm/io.h>
#include <asm/arch/am35x_def.h>
@@ -24,5 +23,5 @@
reset &= ~CPGMACSS_SW_RST;
writel(reset, &am35x_scm_general_regs->ip_sw_reset);
- return davinci_emac_initialize();
+ return 0;
}
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 1090d21..17f31e8 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -59,6 +59,8 @@
select SPL_DRIVERS_MISC_SUPPORT
imply SPL_SERIAL_SUPPORT
imply TPL_SERIAL_SUPPORT
+ imply TPL_BOOTROM_SUPPORT
+ imply TPL_ROCKCHIP_COMMON_BOARD
select ROCKCHIP_BROM_HELPER
select TPL_LIBCOMMON_SUPPORT
select TPL_LIBGENERIC_SUPPORT
@@ -68,19 +70,6 @@
and video codec support. Peripherals include Gigabit Ethernet,
USB2 host and OTG, SDIO, I2S, UART, SPI, I2C and PWMs.
-if ROCKCHIP_RK322X
-
-config TPL_TEXT_BASE
- default 0x10081000
-
-config TPL_MAX_SIZE
- default 28672
-
-config TPL_STACK
- default 0x10088000
-
-endif
-
config ROCKCHIP_RK3288
bool "Support Rockchip RK3288"
select CPU_V7A
@@ -100,6 +89,7 @@
imply TPL_OF_PLATDATA
imply TPL_RAM
imply TPL_REGMAP
+ imply TPL_ROCKCHIP_COMMON_BOARD
imply TPL_SERIAL_SUPPORT
imply TPL_SYSCON
imply USB_FUNCTION_ROCKUSB
@@ -111,19 +101,6 @@
and video codec support. Peripherals include Gigabit Ethernet,
USB2 host and OTG, SDIO, I2S, UARTs, SPI, I2C and PWMs.
-if ROCKCHIP_RK3288
-
-config TPL_TEXT_BASE
- default 0xff704000
-
-config TPL_MAX_SIZE
- default 32768
-
-config TPL_STACK
- default 0xff718000
-
-endif
-
config ROCKCHIP_RK3328
bool "Support Rockchip RK3328"
select ARM64
@@ -151,6 +128,7 @@
imply SPL_SEPARATE_BSS
imply SPL_SERIAL_SUPPORT
imply TPL_SERIAL_SUPPORT
+ imply TPL_ROCKCHIP_COMMON_BOARD
help
The Rockchip RK3368 is a ARM-based SoC with a octa-core (organised
into a big and little cluster with 4 cores each) Cortex-A53 including
@@ -162,19 +140,6 @@
On-chip peripherals include Gigabit Ethernet, USB2 host and OTG, SDIO,
I2S, UARTs, SPI, I2C and PWMs.
-if ROCKCHIP_RK3368
-
-config TPL_TEXT_BASE
- default 0xff8c1000
-
-config TPL_MAX_SIZE
- default 28672
-
-config TPL_STACK
- default 0xff8cffff
-
-endif
-
config ROCKCHIP_RK3399
bool "Support Rockchip RK3399"
select ARM64
@@ -209,7 +174,6 @@
imply TPL_LIBCOMMON_SUPPORT
imply TPL_LIBGENERIC_SUPPORT
imply TPL_SYS_MALLOC_SIMPLE
- imply TPL_BOARD_INIT
imply TPL_BOOTROM_SUPPORT
imply TPL_DRIVERS_MISC_SUPPORT
imply TPL_OF_CONTROL
@@ -219,6 +183,7 @@
imply TPL_RAM
imply TPL_CLK
imply TPL_TINY_MEMSET
+ imply TPL_ROCKCHIP_COMMON_BOARD
help
The Rockchip RK3399 is a ARM-based SoC with a dual-core Cortex-A72
and quad-core Cortex-A53.
@@ -227,22 +192,6 @@
and video codec support. Peripherals include Gigabit Ethernet,
USB2 host and OTG, SDIO, I2S, UARTs, SPI, I2C and PWMs.
-if ROCKCHIP_RK3399
-
-config TPL_LDSCRIPT
- default "arch/arm/mach-rockchip/u-boot-tpl-v8.lds"
-
-config TPL_TEXT_BASE
- default 0xff8c2000
-
-config TPL_MAX_SIZE
- default 188416
-
-config TPL_STACK
- default 0xff8effff
-
-endif
-
config ROCKCHIP_RV1108
bool "Support Rockchip RV1108"
select CPU_V7A
@@ -278,16 +227,17 @@
SPL will return to the boot rom, which will then load the U-Boot
binary to keep going on.
+config TPL_ROCKCHIP_COMMON_BOARD
+ bool ""
+ depends on TPL
+ help
+ Rockchip SoCs have similar boot process, prefer to use TPL for DRAM
+ init and back to bootrom, and SPL as Trust ATF/U-Boot loader. TPL
+ common board is a basic TPL board init which can be shared for most
+ of SoCs to avoid copy-pase for different SoCs.
+
config ROCKCHIP_BOOT_MODE_REG
hex "Rockchip boot mode flag register address"
- default 0x200081c8 if ROCKCHIP_RK3036
- default 0x20004040 if ROCKCHIP_RK3188
- default 0x110005c8 if ROCKCHIP_RK322X
- default 0xff730094 if ROCKCHIP_RK3288
- default 0xff738200 if ROCKCHIP_RK3368
- default 0xff320300 if ROCKCHIP_RK3399
- default 0x10300580 if ROCKCHIP_RV1108
- default 0
help
The Soc will enter to different boot mode(defined in asm/arch-rockchip/boot_mode.h)
according to the value from this register.
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 23760a9..a12b8d4 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -8,16 +8,12 @@
# the stack-pointer is valid before switching to the U-Boot stack).
obj-spl-$(CONFIG_ROCKCHIP_BROM_HELPER) += bootrom.o
obj-tpl-$(CONFIG_ROCKCHIP_BROM_HELPER) += bootrom.o
-
-obj-tpl-$(CONFIG_ROCKCHIP_RK3288) += rk3288-board-tpl.o
-obj-tpl-$(CONFIG_ROCKCHIP_RK3368) += rk3368-board-tpl.o
-obj-tpl-$(CONFIG_ROCKCHIP_RK322X) += rk322x-board-tpl.o
-obj-tpl-$(CONFIG_ROCKCHIP_RK3399) += rk3399-board-tpl.o
+obj-tpl-$(CONFIG_TPL_ROCKCHIP_COMMON_BOARD) += tpl.o
obj-spl-$(CONFIG_ROCKCHIP_RK3036) += rk3036-board-spl.o
obj-spl-$(CONFIG_ROCKCHIP_RK3188) += rk3188-board-spl.o
obj-spl-$(CONFIG_ROCKCHIP_RK322X) += rk322x-board-spl.o spl-boot-order.o
-obj-spl-$(CONFIG_ROCKCHIP_RK3288) += rk3288-board-spl.o
+obj-spl-$(CONFIG_ROCKCHIP_RK3288) += rk3288-board-spl.o spl-boot-order.o
obj-spl-$(CONFIG_ROCKCHIP_RK3328) += rk3328-board-spl.o
obj-spl-$(CONFIG_ROCKCHIP_RK3368) += rk3368-board-spl.o spl-boot-order.o
obj-spl-$(CONFIG_ROCKCHIP_RK3399) += rk3399-board-spl.o spl-boot-order.o
@@ -41,12 +37,6 @@
obj-$(CONFIG_$(SPL_TPL_)RAM) += sdram_common.o
-ifndef CONFIG_ARM64
-ifndef CONFIG_ROCKCHIP_RK3188
-obj-y += rk_timer.o
-endif
-endif
-
obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036/
obj-$(CONFIG_ROCKCHIP_RK3128) += rk3128/
ifndef CONFIG_TPL_BUILD
diff --git a/arch/arm/mach-rockchip/make_fit_atf.py b/arch/arm/mach-rockchip/make_fit_atf.py
index db0ae96..b9a1988 100755
--- a/arch/arm/mach-rockchip/make_fit_atf.py
+++ b/arch/arm/mach-rockchip/make_fit_atf.py
@@ -13,16 +13,7 @@
import sys
import getopt
import logging
-
-# pip install pyelftools
-from elftools.elf.elffile import ELFFile
-
-ELF_SEG_P_TYPE = 'p_type'
-ELF_SEG_P_PADDR = 'p_paddr'
-ELF_SEG_P_VADDR = 'p_vaddr'
-ELF_SEG_P_OFFSET = 'p_offset'
-ELF_SEG_P_FILESZ = 'p_filesz'
-ELF_SEG_P_MEMSZ = 'p_memsz'
+import struct
DT_HEADER = """
/*
@@ -118,33 +109,19 @@
file.write('\n')
def generate_atf_fit_dts_uboot(fit_file, uboot_file_name):
- num_load_seg = 0
- p_paddr = 0xFFFFFFFF
- with open(uboot_file_name, 'rb') as uboot_file:
- uboot = ELFFile(uboot_file)
- for i in range(uboot.num_segments()):
- seg = uboot.get_segment(i)
- if seg.__getitem__(ELF_SEG_P_TYPE) == 'PT_LOAD':
- p_paddr = seg.__getitem__(ELF_SEG_P_PADDR)
- num_load_seg = num_load_seg + 1
-
- assert (p_paddr != 0xFFFFFFFF and num_load_seg == 1)
-
+ segments = unpack_elf(uboot_file_name)
+ if len(segments) != 1:
+ raise ValueError("Invalid u-boot ELF image '%s'" % uboot_file_name)
+ index, entry, p_paddr, data = segments[0]
fit_file.write(DT_UBOOT % p_paddr)
def generate_atf_fit_dts_bl31(fit_file, bl31_file_name, dtbs_file_name):
- with open(bl31_file_name, 'rb') as bl31_file:
- bl31 = ELFFile(bl31_file)
- elf_entry = bl31.header['e_entry']
- segments = bl31.num_segments()
- for i in range(segments):
- seg = bl31.get_segment(i)
- if seg.__getitem__(ELF_SEG_P_TYPE) == 'PT_LOAD':
- paddr = seg.__getitem__(ELF_SEG_P_PADDR)
- append_bl31_node(fit_file, i + 1, paddr, elf_entry)
+ segments = unpack_elf(bl31_file_name)
+ for index, entry, paddr, data in segments:
+ append_bl31_node(fit_file, index + 1, paddr, entry)
append_fdt_node(fit_file, dtbs_file_name)
fit_file.write(DT_IMAGES_NODE_END)
- append_conf_node(fit_file, dtbs_file_name, segments)
+ append_conf_node(fit_file, dtbs_file_name, len(segments))
def generate_atf_fit_dts(fit_file_name, bl31_file_name, uboot_file_name, dtbs_file_name):
# Generate FIT script for ATF image.
@@ -162,17 +139,29 @@
fit_file.close()
def generate_atf_binary(bl31_file_name):
- with open(bl31_file_name, 'rb') as bl31_file:
- bl31 = ELFFile(bl31_file)
+ for index, entry, paddr, data in unpack_elf(bl31_file_name):
+ file_name = 'bl31_0x%08x.bin' % paddr
+ with open(file_name, "wb") as atf:
+ atf.write(data)
+
+def unpack_elf(filename):
+ with open(filename, 'rb') as file:
+ elf = file.read()
+ if elf[0:7] != b'\x7fELF\x02\x01\x01' or elf[18:20] != b'\xb7\x00':
+ raise ValueError("Invalid arm64 ELF file '%s'" % filename)
+
+ e_entry, e_phoff = struct.unpack_from('<2Q', elf, 0x18)
+ e_phentsize, e_phnum = struct.unpack_from('<2H', elf, 0x36)
+ segments = []
- num = bl31.num_segments()
- for i in range(num):
- seg = bl31.get_segment(i)
- if seg.__getitem__(ELF_SEG_P_TYPE) == 'PT_LOAD':
- paddr = seg.__getitem__(ELF_SEG_P_PADDR)
- file_name = 'bl31_0x%08x.bin' % paddr
- with open(file_name, "wb") as atf:
- atf.write(seg.data())
+ for index in range(e_phnum):
+ offset = e_phoff + e_phentsize * index
+ p_type, p_flags, p_offset = struct.unpack_from('<LLQ', elf, offset)
+ if p_type == 1: # PT_LOAD
+ p_paddr, p_filesz = struct.unpack_from('<2Q', elf, offset + 0x18)
+ p_data = elf[p_offset:p_offset + p_filesz]
+ segments.append((index, e_entry, p_paddr, p_data))
+ return segments
def main():
uboot_elf = "./u-boot"
diff --git a/arch/arm/mach-rockchip/rk3036-board-spl.c b/arch/arm/mach-rockchip/rk3036-board-spl.c
index 110d06d..fbc89b6 100644
--- a/arch/arm/mach-rockchip/rk3036-board-spl.c
+++ b/arch/arm/mach-rockchip/rk3036-board-spl.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * (C) Copyright 2015 Rockchip Electronics Co., Ltd
+ * (C) Copyright 2015-2019 Rockchip Electronics Co., Ltd
*/
#include <common.h>
@@ -8,14 +8,37 @@
#include <asm/io.h>
#include <asm/arch-rockchip/bootrom.h>
#include <asm/arch-rockchip/sdram_rk3036.h>
-#include <asm/arch-rockchip/timer.h>
+
+#define TIMER_LOAD_COUNT_L 0x00
+#define TIMER_LOAD_COUNT_H 0x04
+#define TIMER_CONTROL_REG 0x10
+#define TIMER_EN 0x1
+#define TIMER_FMODE (0 << 1)
+#define TIMER_RMODE (1 << 1)
+
+void rockchip_stimer_init(void)
+{
+ asm volatile("mcr p15, 0, %0, c14, c0, 0"
+ : : "r"(COUNTER_FREQUENCY));
+
+ writel(0, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + 4);
+ writel(TIMER_EN | TIMER_FMODE, CONFIG_ROCKCHIP_STIMER_BASE +
+ TIMER_CONTROL_REG);
+}
void board_init_f(ulong dummy)
{
#ifdef CONFIG_DEBUG_UART
debug_uart_init();
#endif
- rockchip_timer_init();
+
+ /* Init secure timer */
+ rockchip_stimer_init();
+ /* Init ARM arch timer in arch/arm/cpu/armv7/arch_timer.c */
+ timer_init();
+
sdram_init();
/* return to maskrom */
diff --git a/arch/arm/mach-rockchip/rk3036-board.c b/arch/arm/mach-rockchip/rk3036-board.c
index e6ea0e9..c594c4d 100644
--- a/arch/arm/mach-rockchip/rk3036-board.c
+++ b/arch/arm/mach-rockchip/rk3036-board.c
@@ -14,7 +14,6 @@
#include <asm/arch-rockchip/grf_rk3036.h>
#include <asm/arch-rockchip/boot_mode.h>
#include <asm/arch-rockchip/sdram_rk3036.h>
-#include <dm/pinctrl.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/arch/arm/mach-rockchip/rk3036/Kconfig b/arch/arm/mach-rockchip/rk3036/Kconfig
index 5e04d20..51cd43b 100644
--- a/arch/arm/mach-rockchip/rk3036/Kconfig
+++ b/arch/arm/mach-rockchip/rk3036/Kconfig
@@ -1,5 +1,8 @@
if ROCKCHIP_RK3036
+choice
+ prompt "RK3036 board select"
+
config TARGET_EVB_RK3036
bool "EVB_RK3036"
select BOARD_LATE_INIT
@@ -8,6 +11,11 @@
bool "KYLIN_RK3036"
select BOARD_LATE_INIT
+endchoice
+
+config ROCKCHIP_BOOT_MODE_REG
+ default 0x200081c8
+
config SYS_SOC
default "rk3036"
diff --git a/arch/arm/mach-rockchip/rk3036/sdram_rk3036.c b/arch/arm/mach-rockchip/rk3036/sdram_rk3036.c
index 1d940a0..c39cbb8 100644
--- a/arch/arm/mach-rockchip/rk3036/sdram_rk3036.c
+++ b/arch/arm/mach-rockchip/rk3036/sdram_rk3036.c
@@ -9,7 +9,6 @@
#include <asm/arch-rockchip/grf_rk3036.h>
#include <asm/arch-rockchip/hardware.h>
#include <asm/arch-rockchip/sdram_rk3036.h>
-#include <asm/arch-rockchip/timer.h>
#include <asm/arch-rockchip/uart.h>
/*
@@ -345,7 +344,7 @@
/* waiting for pll lock */
while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT))
- rockchip_udelay(1);
+ udelay(1);
/* PLL enter normal-mode */
rk_clrsetreg(&priv->cru->cru_mode_con, DPLL_MODE_MASK,
@@ -373,25 +372,25 @@
1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT |
1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRPHY_PSRST_SHIFT |
1 << DDRPHY_SRST_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT |
1 << DDRCTRL_SRST_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
clrsetbits_le32(&ddr_phy->ddrphy_reg1,
SOFT_RESET_MASK << SOFT_RESET_SHIFT,
0 << SOFT_RESET_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
clrsetbits_le32(&ddr_phy->ddrphy_reg1,
SOFT_RESET_MASK << SOFT_RESET_SHIFT,
3 << SOFT_RESET_SHIFT);
- rockchip_udelay(1);
+ udelay(1);
}
void phy_dll_bypass_set(struct rk3036_sdram_priv *priv, unsigned int freq)
@@ -444,7 +443,7 @@
u32 rank, u32 cmd, u32 arg)
{
writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd);
- rockchip_udelay(1);
+ udelay(1);
while (readl(&pctl->mcmd) & START_CMD)
;
}
@@ -454,7 +453,7 @@
struct rk3036_ddr_pctl *pctl = priv->pctl;
send_command(pctl, 3, DESELECT_CMD, 0);
- rockchip_udelay(1);
+ udelay(1);
send_command(pctl, 3, PREA_CMD, 0);
send_command(pctl, 3, MRS_CMD,
(0x02 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
@@ -492,7 +491,7 @@
clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03,
DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_CAL_START);
- rockchip_udelay(1);
+ udelay(1);
while ((readl(&ddr_phy->ddrphy_reg62) & CAL_DONE_MASK) !=
(HIGH_8BIT_CAL_DONE | LOW_8BIT_CAL_DONE)) {
;
diff --git a/arch/arm/mach-rockchip/rk3128-board.c b/arch/arm/mach-rockchip/rk3128-board.c
index fa71685..0945829 100644
--- a/arch/arm/mach-rockchip/rk3128-board.c
+++ b/arch/arm/mach-rockchip/rk3128-board.c
@@ -12,7 +12,6 @@
#include <asm/arch-rockchip/periph.h>
#include <asm/arch-rockchip/grf_rk3128.h>
#include <asm/arch-rockchip/boot_mode.h>
-#include <asm/arch-rockchip/timer.h>
#include <power/regulator.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -33,8 +32,6 @@
{
int ret = 0;
- rockchip_timer_init();
-
ret = regulators_enable_boot_on(false);
if (ret) {
debug("%s: Cannot enable boot on regulator\n", __func__);
diff --git a/arch/arm/mach-rockchip/rk3128/Kconfig b/arch/arm/mach-rockchip/rk3128/Kconfig
index a82b7dc..b867401 100644
--- a/arch/arm/mach-rockchip/rk3128/Kconfig
+++ b/arch/arm/mach-rockchip/rk3128/Kconfig
@@ -13,6 +13,9 @@
endchoice
+config ROCKCHIP_BOOT_MODE_REG
+ default 0x100a0038
+
config SYS_SOC
default "rk3128"
diff --git a/arch/arm/mach-rockchip/rk3188-board-spl.c b/arch/arm/mach-rockchip/rk3188-board-spl.c
index 77b9b36..c3efe0d 100644
--- a/arch/arm/mach-rockchip/rk3188-board-spl.c
+++ b/arch/arm/mach-rockchip/rk3188-board-spl.c
@@ -22,8 +22,6 @@
#include <asm/arch-rockchip/periph.h>
#include <asm/arch-rockchip/pmu_rk3188.h>
#include <asm/arch-rockchip/sdram.h>
-#include <asm/arch-rockchip/timer.h>
-#include <dm/pinctrl.h>
#include <dm/root.h>
#include <dm/test.h>
#include <dm/util.h>
diff --git a/arch/arm/mach-rockchip/rk3188-board.c b/arch/arm/mach-rockchip/rk3188-board.c
index 80d8c42..94fd6c0 100644
--- a/arch/arm/mach-rockchip/rk3188-board.c
+++ b/arch/arm/mach-rockchip/rk3188-board.c
@@ -15,7 +15,6 @@
#include <asm/arch-rockchip/periph.h>
#include <asm/arch-rockchip/pmu_rk3288.h>
#include <asm/arch-rockchip/boot_mode.h>
-#include <dm/pinctrl.h>
__weak int rk_board_late_init(void)
{
@@ -42,37 +41,7 @@
int board_init(void)
{
-#if CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM)
- struct udevice *pinctrl;
- int ret;
-
- /*
- * We need to implement sdcard iomux here for the further
- * initialization, otherwise, it'll hit sdcard command sending
- * timeout exception.
- */
- ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
- if (ret) {
- debug("%s: Cannot find pinctrl device\n", __func__);
- goto err;
- }
- ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD);
- if (ret) {
- debug("%s: Failed to set up SD card\n", __func__);
- goto err;
- }
-
- return 0;
-err:
- printf("board_init: Error %d\n", ret);
-
- /* No way to report error here */
- hang();
-
- return -1;
-#else
return 0;
-#endif
}
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
diff --git a/arch/arm/mach-rockchip/rk3188/Kconfig b/arch/arm/mach-rockchip/rk3188/Kconfig
index a6fc691..e24e68e 100644
--- a/arch/arm/mach-rockchip/rk3188/Kconfig
+++ b/arch/arm/mach-rockchip/rk3188/Kconfig
@@ -9,6 +9,9 @@
Expansion connectors provide access to display pins, I2C, SPI,
UART and GPIOs.
+config ROCKCHIP_BOOT_MODE_REG
+ default 0x20004040
+
config SYS_SOC
default "rk3188"
diff --git a/arch/arm/mach-rockchip/rk322x-board-spl.c b/arch/arm/mach-rockchip/rk322x-board-spl.c
index c9b41c6..c825e31 100644
--- a/arch/arm/mach-rockchip/rk322x-board-spl.c
+++ b/arch/arm/mach-rockchip/rk322x-board-spl.c
@@ -19,6 +19,31 @@
return MMCSD_MODE_RAW;
}
+#define TIMER_LOAD_COUNT_L 0x00
+#define TIMER_LOAD_COUNT_H 0x04
+#define TIMER_CONTROL_REG 0x10
+#define TIMER_EN 0x1
+#define TIMER_FMODE BIT(0)
+#define TIMER_RMODE BIT(1)
+
+void rockchip_stimer_init(void)
+{
+ /* If Timer already enabled, don't re-init it */
+ u32 reg = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+
+ if (reg & TIMER_EN)
+ return;
+
+ asm volatile("mcr p15, 0, %0, c14, c0, 0"
+ : : "r"(COUNTER_FREQUENCY));
+
+ writel(0, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + 4);
+ writel(TIMER_EN | TIMER_FMODE, CONFIG_ROCKCHIP_STIMER_BASE +
+ TIMER_CONTROL_REG);
+}
+
#define SGRF_DDR_CON0 0x10150000
void board_init_f(ulong dummy)
{
@@ -31,6 +56,11 @@
}
preloader_console_init();
+ /* Init secure timer */
+ rockchip_stimer_init();
+ /* Init ARM arch timer in arch/arm/cpu/armv7/arch_timer.c */
+ timer_init();
+
/* Disable the ddr secure region setting to make it non-secure */
rk_clrreg(SGRF_DDR_CON0, 0x4000);
}
diff --git a/arch/arm/mach-rockchip/rk322x-board-tpl.c b/arch/arm/mach-rockchip/rk322x-board-tpl.c
deleted file mode 100644
index 92d40ee..0000000
--- a/arch/arm/mach-rockchip/rk322x-board-tpl.c
+++ /dev/null
@@ -1,53 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2019 Rockchip Electronics Co., Ltd
- */
-
-#include <common.h>
-#include <debug_uart.h>
-#include <dm.h>
-#include <ram.h>
-#include <spl.h>
-#include <asm/io.h>
-#include <asm/arch-rockchip/bootrom.h>
-#include <asm/arch-rockchip/timer.h>
-
-u32 spl_boot_device(void)
-{
- return BOOT_DEVICE_MMC1;
-}
-
-void board_init_f(ulong dummy)
-{
- struct udevice *dev;
- int ret;
-
- /*
- * Debug UART can be used from here if required:
- *
- * debug_uart_init();
- * printch('a');
- * printhex8(0x1234);
- * printascii("string");
- */
- debug_uart_init();
- printascii("TPL Init");
-
- ret = spl_early_init();
- if (ret) {
- debug("spl_early_init() failed: %d\n", ret);
- hang();
- }
-
- rockchip_timer_init();
- printf("timer init done\n");
- ret = uclass_get_device(UCLASS_RAM, 0, &dev);
- if (ret) {
- printf("DRAM init failed: %d\n", ret);
- return;
- }
-
-#if defined(CONFIG_TPL_ROCKCHIP_BACK_TO_BROM) && !defined(CONFIG_TPL_BOARD_INIT)
- back_to_bootrom(BROM_BOOT_NEXTSTAGE);
-#endif
-}
diff --git a/arch/arm/mach-rockchip/rk322x/Kconfig b/arch/arm/mach-rockchip/rk322x/Kconfig
index 8a1f95f..2fc6f6e 100644
--- a/arch/arm/mach-rockchip/rk322x/Kconfig
+++ b/arch/arm/mach-rockchip/rk322x/Kconfig
@@ -1,18 +1,37 @@
if ROCKCHIP_RK322X
+
config TARGET_EVB_RK3229
bool "EVB_RK3229"
select BOARD_LATE_INIT
+config ROCKCHIP_BOOT_MODE_REG
+ default 0x110005c8
+
config SYS_SOC
default "rk322x"
config SYS_MALLOC_F_LEN
- default 0x400
+ default 0x800
+
+config SPL_LIBCOMMON_SUPPORT
+ default y
+
+config SPL_LIBGENERIC_SUPPORT
+ default y
config SPL_SERIAL_SUPPORT
default y
+config TPL_MAX_SIZE
+ default 28672
+
+config TPL_STACK
+ default 0x10088000
+
+config TPL_TEXT_BASE
+ default 0x10081000
+
source "board/rockchip/evb_rk3229/Kconfig"
endif
diff --git a/arch/arm/mach-rockchip/rk3288-board-spl.c b/arch/arm/mach-rockchip/rk3288-board-spl.c
index d8d215d..c2e1681 100644
--- a/arch/arm/mach-rockchip/rk3288-board-spl.c
+++ b/arch/arm/mach-rockchip/rk3288-board-spl.c
@@ -22,8 +22,6 @@
#include <asm/arch-rockchip/sdram.h>
#include <asm/arch-rockchip/sdram_common.h>
#include <asm/arch-rockchip/sys_proto.h>
-#include <asm/arch-rockchip/timer.h>
-#include <dm/pinctrl.h>
#include <dm/root.h>
#include <dm/test.h>
#include <dm/util.h>
@@ -104,6 +102,36 @@
}
#endif
+__weak int arch_cpu_init(void)
+{
+ return 0;
+}
+
+#define TIMER_LOAD_COUNT_L 0x00
+#define TIMER_LOAD_COUNT_H 0x04
+#define TIMER_CONTROL_REG 0x10
+#define TIMER_EN 0x1
+#define TIMER_FMODE BIT(0)
+#define TIMER_RMODE BIT(1)
+
+void rockchip_stimer_init(void)
+{
+ /* If Timer already enabled, don't re-init it */
+ u32 reg = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+
+ if (reg & TIMER_EN)
+ return;
+
+ asm volatile("mcr p15, 0, %0, c14, c0, 0"
+ : : "r"(COUNTER_FREQUENCY));
+
+ writel(0, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + 4);
+ writel(TIMER_EN | TIMER_FMODE, CONFIG_ROCKCHIP_STIMER_BASE +
+ TIMER_CONTROL_REG);
+}
+
void board_init_f(ulong dummy)
{
struct udevice *dev;
@@ -127,8 +155,12 @@
hang();
}
- rockchip_timer_init();
- configure_l2ctlr();
+ /* Init secure timer */
+ rockchip_stimer_init();
+ /* Init ARM arch timer in arch/arm/cpu/armv7/arch_timer.c */
+ timer_init();
+
+ arch_cpu_init();
ret = rockchip_get_clk(&dev);
if (ret) {
diff --git a/arch/arm/mach-rockchip/rk3288-board-tpl.c b/arch/arm/mach-rockchip/rk3288-board-tpl.c
deleted file mode 100644
index 787129b..0000000
--- a/arch/arm/mach-rockchip/rk3288-board-tpl.c
+++ /dev/null
@@ -1,70 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2017 Amarula Solutions
- */
-
-#include <common.h>
-#include <debug_uart.h>
-#include <dm.h>
-#include <ram.h>
-#include <spl.h>
-#include <version.h>
-#include <asm/io.h>
-#include <asm/arch-rockchip/bootrom.h>
-#include <asm/arch-rockchip/clock.h>
-#include <asm/arch-rockchip/sys_proto.h>
-#include <asm/arch-rockchip/timer.h>
-
-void board_init_f(ulong dummy)
-{
- struct udevice *dev;
- int ret;
-
-#ifdef CONFIG_DEBUG_UART
- /*
- * Debug UART can be used from here if required:
- *
- * debug_uart_init();
- * printch('a');
- * printhex8(0x1234);
- * printascii("string");
- */
- debug_uart_init();
-#endif
- ret = spl_early_init();
- if (ret) {
- debug("spl_early_init() failed: %d\n", ret);
- hang();
- }
-
- rockchip_timer_init();
- configure_l2ctlr();
-
- ret = rockchip_get_clk(&dev);
- if (ret) {
- debug("CLK init failed: %d\n", ret);
- return;
- }
-
- ret = uclass_get_device(UCLASS_RAM, 0, &dev);
- if (ret) {
- debug("DRAM init failed: %d\n", ret);
- return;
- }
-}
-
-void board_return_to_bootrom(void)
-{
- back_to_bootrom(BROM_BOOT_NEXTSTAGE);
-}
-
-u32 spl_boot_device(void)
-{
- return BOOT_DEVICE_BOOTROM;
-}
-
-void spl_board_init(void)
-{
- puts("\nU-Boot TPL " PLAIN_VERSION " (" U_BOOT_DATE " - " \
- U_BOOT_TIME ")\n");
-}
diff --git a/arch/arm/mach-rockchip/rk3288-board.c b/arch/arm/mach-rockchip/rk3288-board.c
index e2de5b2..a250d50 100644
--- a/arch/arm/mach-rockchip/rk3288-board.c
+++ b/arch/arm/mach-rockchip/rk3288-board.c
@@ -16,7 +16,6 @@
#include <asm/arch-rockchip/qos_rk3288.h>
#include <asm/arch-rockchip/boot_mode.h>
#include <asm/gpio.h>
-#include <dm/pinctrl.h>
#include <dt-bindings/clock/rk3288-cru.h>
#include <power/regulator.h>
@@ -145,33 +144,7 @@
int board_init(void)
{
#if CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM)
- struct udevice *pinctrl;
- int ret;
-
- /*
- * We need to implement sdcard iomux here for the further
- * initlization, otherwise, it'll hit sdcard command sending
- * timeout exception.
- */
- ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
- if (ret) {
- debug("%s: Cannot find pinctrl device\n", __func__);
- goto err;
- }
- ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD);
- if (ret) {
- debug("%s: Failed to set up SD card\n", __func__);
- goto err;
- }
-
return 0;
-err:
- printf("board_init: Error %d\n", ret);
-
- /* No way to report error here */
- hang();
-
- return -1;
#else
int ret;
diff --git a/arch/arm/mach-rockchip/rk3288/Kconfig b/arch/arm/mach-rockchip/rk3288/Kconfig
index c5dcd06..de8d9c2 100644
--- a/arch/arm/mach-rockchip/rk3288/Kconfig
+++ b/arch/arm/mach-rockchip/rk3288/Kconfig
@@ -1,5 +1,8 @@
if ROCKCHIP_RK3288
+choice
+ prompt "RK3288 board select"
+
config TARGET_CHROMEBOOK_JERRY
bool "Google/Rockchip Veyron-Jerry Chromebook"
select BOARD_LATE_INIT
@@ -44,6 +47,7 @@
config TARGET_EVB_RK3288
bool "Evb-RK3288"
select BOARD_LATE_INIT
+ select TPL
help
EVB-RK3288 is a RK3288-based development board with 2 USB ports,
HDMI, VGA, micro-SD card, audio, WiFi and Gigabit Ethernet, It
@@ -125,6 +129,8 @@
8GB eMMC and 2GB of SDRAM. Expansion connectors provide access to
I2C, SPI, UART, GPIOs.
+endchoice
+
config ROCKCHIP_FAST_SPL
bool "Change the CPU to full speed in SPL"
depends on TARGET_CHROMEBOOK_JERRY
@@ -134,11 +140,14 @@
voltage. This option is only available on boards which support it
and have the required PMIC code.
+config ROCKCHIP_BOOT_MODE_REG
+ default 0xff730094
+
config SYS_SOC
default "rk3288"
config SYS_MALLOC_F_LEN
- default 0x0800
+ default 0x2000
config SPL_DRIVERS_MISC_SUPPORT
default y
@@ -152,6 +161,18 @@
config SPL_SERIAL_SUPPORT
default y
+config TPL_LDSCRIPT
+ default "arch/arm/mach-rockchip/u-boot-tpl.lds"
+
+config TPL_MAX_SIZE
+ default 32768
+
+config TPL_STACK
+ default 0xff718000
+
+config TPL_TEXT_BASE
+ default 0xff704000
+
source "board/amarula/vyasa-rk3288/Kconfig"
source "board/chipspark/popmetal_rk3288/Kconfig"
diff --git a/arch/arm/mach-rockchip/rk3288/rk3288.c b/arch/arm/mach-rockchip/rk3288/rk3288.c
index 7941ca6..7552472 100644
--- a/arch/arm/mach-rockchip/rk3288/rk3288.c
+++ b/arch/arm/mach-rockchip/rk3288/rk3288.c
@@ -2,19 +2,45 @@
/*
* Copyright (c) 2016 Rockchip Electronics Co., Ltd
*/
+#include <asm/armv7.h>
#include <asm/io.h>
#include <asm/arch-rockchip/hardware.h>
#include <asm/arch-rockchip/grf_rk3288.h>
#define GRF_BASE 0xff770000
+#ifdef CONFIG_SPL_BUILD
+static void configure_l2ctlr(void)
+{
+ u32 l2ctlr;
+
+ l2ctlr = read_l2ctlr();
+ l2ctlr &= 0xfffc0000; /* clear bit0~bit17 */
+
+ /*
+ * Data RAM write latency: 2 cycles
+ * Data RAM read latency: 2 cycles
+ * Data RAM setup latency: 1 cycle
+ * Tag RAM write latency: 1 cycle
+ * Tag RAM read latency: 1 cycle
+ * Tag RAM setup latency: 1 cycle
+ */
+ l2ctlr |= (1 << 3 | 1 << 0);
+ write_l2ctlr(l2ctlr);
+}
+#endif
+
int arch_cpu_init(void)
{
+#ifdef CONFIG_SPL_BUILD
+ configure_l2ctlr();
+#else
/* We do some SoC one time setting here. */
struct rk3288_grf * const grf = (void *)GRF_BASE;
/* Use rkpwm by default */
rk_setreg(&grf->soc_con2, 1 << 0);
+#endif
return 0;
}
diff --git a/arch/arm/mach-rockchip/rk3328-board-spl.c b/arch/arm/mach-rockchip/rk3328-board-spl.c
index 7f49d05..f24fd89 100644
--- a/arch/arm/mach-rockchip/rk3328-board-spl.c
+++ b/arch/arm/mach-rockchip/rk3328-board-spl.c
@@ -7,7 +7,6 @@
#include <common.h>
#include <debug_uart.h>
#include <dm.h>
-#include <dm/pinctrl.h>
#include <ram.h>
#include <spl.h>
#include <asm/io.h>
diff --git a/arch/arm/mach-rockchip/rk3328/Kconfig b/arch/arm/mach-rockchip/rk3328/Kconfig
index 6c5c430..f8e1528 100644
--- a/arch/arm/mach-rockchip/rk3328/Kconfig
+++ b/arch/arm/mach-rockchip/rk3328/Kconfig
@@ -12,11 +12,20 @@
endchoice
+config ROCKCHIP_BOOT_MODE_REG
+ default 0xff1005c8
+
config SYS_SOC
default "rk3328"
config SYS_MALLOC_F_LEN
- default 0x0800
+ default 0x2000
+
+config SPL_LIBCOMMON_SUPPORT
+ default y
+
+config SPL_LIBGENERIC_SUPPORT
+ default y
source "board/rockchip/evb_rk3328/Kconfig"
diff --git a/arch/arm/mach-rockchip/rk3368-board-spl.c b/arch/arm/mach-rockchip/rk3368-board-spl.c
index c651193..6ba106c6 100644
--- a/arch/arm/mach-rockchip/rk3368-board-spl.c
+++ b/arch/arm/mach-rockchip/rk3368-board-spl.c
@@ -11,6 +11,33 @@
#include <asm/io.h>
#include <asm/arch-rockchip/periph.h>
+__weak int arch_cpu_init(void)
+{
+ return 0;
+}
+
+#define TIMER_LOAD_COUNT_L 0x00
+#define TIMER_LOAD_COUNT_H 0x04
+#define TIMER_CONTROL_REG 0x10
+#define TIMER_EN 0x1
+#define TIMER_FMODE BIT(0)
+#define TIMER_RMODE BIT(1)
+
+void rockchip_stimer_init(void)
+{
+ /* If Timer already enabled, don't re-init it */
+ u32 reg = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+
+ if (reg & TIMER_EN)
+ return;
+
+ writel(0, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + 4);
+ writel(TIMER_EN | TIMER_FMODE, CONFIG_ROCKCHIP_STIMER_BASE +
+ TIMER_CONTROL_REG);
+}
+
void board_init_f(ulong dummy)
{
struct udevice *dev;
@@ -22,6 +49,12 @@
hang();
}
+ /* Init secure timer */
+ rockchip_stimer_init();
+ /* Init ARM arch timer in arch/arm/cpu/armv7/arch_timer.c */
+ timer_init();
+
+ arch_cpu_init();
preloader_console_init();
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
diff --git a/arch/arm/mach-rockchip/rk3368-board-tpl.c b/arch/arm/mach-rockchip/rk3368-board-tpl.c
deleted file mode 100644
index dc65a02..0000000
--- a/arch/arm/mach-rockchip/rk3368-board-tpl.c
+++ /dev/null
@@ -1,123 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH
- */
-
-#include <common.h>
-#include <debug_uart.h>
-#include <dm.h>
-#include <ram.h>
-#include <spl.h>
-#include <syscon.h>
-#include <asm/io.h>
-#include <asm/arch-rockchip/bootrom.h>
-#include <asm/arch-rockchip/clock.h>
-#include <asm/arch-rockchip/cru_rk3368.h>
-#include <asm/arch-rockchip/hardware.h>
-#include <asm/arch-rockchip/timer.h>
-
-/*
- * The SPL (and also the full U-Boot stage on the RK3368) will run in
- * secure mode (i.e. EL3) and an ATF will eventually be booted before
- * starting up the operating system... so we can initialize the SGRF
- * here and rely on the ATF installing the final (secure) policy
- * later.
- */
-static inline uintptr_t sgrf_soc_con_addr(unsigned no)
-{
- const uintptr_t SGRF_BASE =
- (uintptr_t)syscon_get_first_range(ROCKCHIP_SYSCON_SGRF);
-
- return SGRF_BASE + sizeof(u32) * no;
-}
-
-static inline uintptr_t sgrf_busdmac_addr(unsigned no)
-{
- const uintptr_t SGRF_BASE =
- (uintptr_t)syscon_get_first_range(ROCKCHIP_SYSCON_SGRF);
- const uintptr_t SGRF_BUSDMAC_OFFSET = 0x100;
- const uintptr_t SGRF_BUSDMAC_BASE = SGRF_BASE + SGRF_BUSDMAC_OFFSET;
-
- return SGRF_BUSDMAC_BASE + sizeof(u32) * no;
-}
-
-static void sgrf_init(void)
-{
- struct rk3368_cru * const cru =
- (struct rk3368_cru * const)rockchip_get_cru();
- const u16 SGRF_SOC_CON_SEC = GENMASK(15, 0);
- const u16 SGRF_BUSDMAC_CON0_SEC = BIT(2);
- const u16 SGRF_BUSDMAC_CON1_SEC = GENMASK(15, 12);
-
- /* Set all configurable IP to 'non secure'-mode */
- rk_setreg(sgrf_soc_con_addr(5), SGRF_SOC_CON_SEC);
- rk_setreg(sgrf_soc_con_addr(6), SGRF_SOC_CON_SEC);
- rk_setreg(sgrf_soc_con_addr(7), SGRF_SOC_CON_SEC);
-
- /*
- * From rockchip-uboot/arch/arm/cpu/armv8/rk33xx/cpu.c
- * Original comment: "ddr space set no secure mode"
- */
- rk_clrreg(sgrf_soc_con_addr(8), SGRF_SOC_CON_SEC);
- rk_clrreg(sgrf_soc_con_addr(9), SGRF_SOC_CON_SEC);
- rk_clrreg(sgrf_soc_con_addr(10), SGRF_SOC_CON_SEC);
-
- /* Set 'secure dma' to 'non secure'-mode */
- rk_setreg(sgrf_busdmac_addr(0), SGRF_BUSDMAC_CON0_SEC);
- rk_setreg(sgrf_busdmac_addr(1), SGRF_BUSDMAC_CON1_SEC);
-
- dsb(); /* barrier */
-
- rk_setreg(&cru->softrst_con[1], DMA1_SRST_REQ);
- rk_setreg(&cru->softrst_con[4], DMA2_SRST_REQ);
-
- dsb(); /* barrier */
- udelay(10);
-
- rk_clrreg(&cru->softrst_con[1], DMA1_SRST_REQ);
- rk_clrreg(&cru->softrst_con[4], DMA2_SRST_REQ);
-}
-
-void board_init_f(ulong dummy)
-{
- struct udevice *dev;
- int ret;
-
-#ifdef CONFIG_DEBUG_UART
- /*
- * Debug UART can be used from here if required:
- *
- * debug_uart_init();
- * printch('a');
- * printhex8(0x1234);
- * printascii("string");
- */
- debug_uart_init();
- printascii("U-Boot TPL board init\n");
-#endif
-
- ret = spl_early_init();
- if (ret) {
- debug("spl_early_init() failed: %d\n", ret);
- hang();
- }
-
- /* Reset security, so we can use DMA in the MMC drivers */
- sgrf_init();
-
- ret = uclass_get_device(UCLASS_RAM, 0, &dev);
- if (ret) {
- debug("DRAM init failed: %d\n", ret);
- return;
- }
-}
-
-void board_return_to_bootrom(void)
-{
- back_to_bootrom(BROM_BOOT_NEXTSTAGE);
-}
-
-u32 spl_boot_device(void)
-{
- return BOOT_DEVICE_BOOTROM;
-}
diff --git a/arch/arm/mach-rockchip/rk3368/Kconfig b/arch/arm/mach-rockchip/rk3368/Kconfig
index 325572a..d6ca5f1 100644
--- a/arch/arm/mach-rockchip/rk3368/Kconfig
+++ b/arch/arm/mach-rockchip/rk3368/Kconfig
@@ -42,9 +42,21 @@
sensor STK3410.
endchoice
+config ROCKCHIP_BOOT_MODE_REG
+ default 0xff738200
+
config SYS_SOC
default "rk3368"
+config SYS_MALLOC_F_LEN
+ default 0x2000
+
+config SPL_LIBCOMMON_SUPPORT
+ default y
+
+config SPL_LIBGENERIC_SUPPORT
+ default y
+
source "board/theobroma-systems/lion_rk3368/Kconfig"
source "board/rockchip/sheep_rk3368/Kconfig"
source "board/geekbuying/geekbox/Kconfig"
@@ -53,4 +65,13 @@
config SPL_LDSCRIPT
default "arch/arm/cpu/armv8/u-boot-spl.lds"
+config TPL_MAX_SIZE
+ default 28672
+
+config TPL_STACK
+ default 0xff8cffff
+
+config TPL_TEXT_BASE
+ default 0xff8c1000
+
endif
diff --git a/arch/arm/mach-rockchip/rk3368/rk3368.c b/arch/arm/mach-rockchip/rk3368/rk3368.c
index f06d277..47786f5 100644
--- a/arch/arm/mach-rockchip/rk3368/rk3368.c
+++ b/arch/arm/mach-rockchip/rk3368/rk3368.c
@@ -5,12 +5,13 @@
*/
#include <common.h>
+#include <syscon.h>
#include <asm/armv8/mmu.h>
#include <asm/io.h>
#include <asm/arch-rockchip/clock.h>
#include <asm/arch-rockchip/cru_rk3368.h>
#include <asm/arch-rockchip/grf_rk3368.h>
-#include <syscon.h>
+#include <asm/arch-rockchip/hardware.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -97,6 +98,78 @@
}
#endif
+#ifdef CONFIG_SPL_BUILD
+/*
+ * The SPL (and also the full U-Boot stage on the RK3368) will run in
+ * secure mode (i.e. EL3) and an ATF will eventually be booted before
+ * starting up the operating system... so we can initialize the SGRF
+ * here and rely on the ATF installing the final (secure) policy
+ * later.
+ */
+static inline uintptr_t sgrf_soc_con_addr(unsigned int no)
+{
+ const uintptr_t SGRF_BASE =
+ (uintptr_t)syscon_get_first_range(ROCKCHIP_SYSCON_SGRF);
+
+ return SGRF_BASE + sizeof(u32) * no;
+}
+
+static inline uintptr_t sgrf_busdmac_addr(unsigned int no)
+{
+ const uintptr_t SGRF_BASE =
+ (uintptr_t)syscon_get_first_range(ROCKCHIP_SYSCON_SGRF);
+ const uintptr_t SGRF_BUSDMAC_OFFSET = 0x100;
+ const uintptr_t SGRF_BUSDMAC_BASE = SGRF_BASE + SGRF_BUSDMAC_OFFSET;
+
+ return SGRF_BUSDMAC_BASE + sizeof(u32) * no;
+}
+
+static void sgrf_init(void)
+{
+ struct rk3368_cru * const cru =
+ (struct rk3368_cru * const)rockchip_get_cru();
+ const u16 SGRF_SOC_CON_SEC = GENMASK(15, 0);
+ const u16 SGRF_BUSDMAC_CON0_SEC = BIT(2);
+ const u16 SGRF_BUSDMAC_CON1_SEC = GENMASK(15, 12);
+
+ /* Set all configurable IP to 'non secure'-mode */
+ rk_setreg(sgrf_soc_con_addr(5), SGRF_SOC_CON_SEC);
+ rk_setreg(sgrf_soc_con_addr(6), SGRF_SOC_CON_SEC);
+ rk_setreg(sgrf_soc_con_addr(7), SGRF_SOC_CON_SEC);
+
+ /*
+ * From rockchip-uboot/arch/arm/cpu/armv8/rk33xx/cpu.c
+ * Original comment: "ddr space set no secure mode"
+ */
+ rk_clrreg(sgrf_soc_con_addr(8), SGRF_SOC_CON_SEC);
+ rk_clrreg(sgrf_soc_con_addr(9), SGRF_SOC_CON_SEC);
+ rk_clrreg(sgrf_soc_con_addr(10), SGRF_SOC_CON_SEC);
+
+ /* Set 'secure dma' to 'non secure'-mode */
+ rk_setreg(sgrf_busdmac_addr(0), SGRF_BUSDMAC_CON0_SEC);
+ rk_setreg(sgrf_busdmac_addr(1), SGRF_BUSDMAC_CON1_SEC);
+
+ dsb(); /* barrier */
+
+ rk_setreg(&cru->softrst_con[1], DMA1_SRST_REQ);
+ rk_setreg(&cru->softrst_con[4], DMA2_SRST_REQ);
+
+ dsb(); /* barrier */
+ udelay(10);
+
+ rk_clrreg(&cru->softrst_con[1], DMA1_SRST_REQ);
+ rk_clrreg(&cru->softrst_con[4], DMA2_SRST_REQ);
+}
+
+int arch_cpu_init(void)
+{
+ /* Reset security, so we can use DMA in the MMC drivers */
+ sgrf_init();
+
+ return 0;
+}
+#endif
+
#ifdef CONFIG_DEBUG_UART_BOARD_INIT
void board_debug_uart_init(void)
{
diff --git a/arch/arm/mach-rockchip/rk3399-board-spl.c b/arch/arm/mach-rockchip/rk3399-board-spl.c
index 890d800..7154d8e 100644
--- a/arch/arm/mach-rockchip/rk3399-board-spl.c
+++ b/arch/arm/mach-rockchip/rk3399-board-spl.c
@@ -21,7 +21,6 @@
#include <asm/arch-rockchip/periph.h>
#include <asm/arch-rockchip/sys_proto.h>
#include <power/regulator.h>
-#include <dm/pinctrl.h>
void board_return_to_bootrom(void)
{
@@ -110,30 +109,12 @@
"u-boot,spl-boot-device", boot_ofpath);
}
-#define TIMER_CHN10_BASE 0xff8680a0
-#define TIMER_END_COUNT_L 0x00
-#define TIMER_END_COUNT_H 0x04
-#define TIMER_INIT_COUNT_L 0x10
-#define TIMER_INIT_COUNT_H 0x14
-#define TIMER_CONTROL_REG 0x1c
-
-#define TIMER_EN 0x1
-#define TIMER_FMODE (0 << 1)
-#define TIMER_RMODE (1 << 1)
-
-void secure_timer_init(void)
+__weak void rockchip_stimer_init(void)
{
- writel(0xffffffff, TIMER_CHN10_BASE + TIMER_END_COUNT_L);
- writel(0xffffffff, TIMER_CHN10_BASE + TIMER_END_COUNT_H);
- writel(0, TIMER_CHN10_BASE + TIMER_INIT_COUNT_L);
- writel(0, TIMER_CHN10_BASE + TIMER_INIT_COUNT_H);
- writel(TIMER_EN | TIMER_FMODE, TIMER_CHN10_BASE + TIMER_CONTROL_REG);
}
-
void board_init_f(ulong dummy)
{
- struct udevice *pinctrl;
struct udevice *dev;
struct rk3399_pmusgrf_regs *sgrf;
struct rk3399_grf_regs *grf;
@@ -190,13 +171,7 @@
grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
rk_clrreg(&grf->emmccore_con[11], 0x0ff);
- secure_timer_init();
-
- ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
- if (ret) {
- pr_err("Pinctrl init failed: %d\n", ret);
- return;
- }
+ rockchip_stimer_init();
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
if (ret) {
diff --git a/arch/arm/mach-rockchip/rk3399-board-tpl.c b/arch/arm/mach-rockchip/rk3399-board-tpl.c
deleted file mode 100644
index 4a30124..0000000
--- a/arch/arm/mach-rockchip/rk3399-board-tpl.c
+++ /dev/null
@@ -1,91 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2019 Rockchip Electronics Co., Ltd
- */
-
-#include <common.h>
-#include <debug_uart.h>
-#include <dm.h>
-#include <ram.h>
-#include <spl.h>
-#include <version.h>
-#include <asm/io.h>
-#include <asm/arch-rockchip/bootrom.h>
-
-#define TIMER_CHN10_BASE 0xff8680a0
-#define TIMER_END_COUNT_L 0x00
-#define TIMER_END_COUNT_H 0x04
-#define TIMER_INIT_COUNT_L 0x10
-#define TIMER_INIT_COUNT_H 0x14
-#define TIMER_CONTROL_REG 0x1c
-
-#define TIMER_EN 0x1
-#define TIMER_FMODE (0 << 1)
-#define TIMER_RMODE (1 << 1)
-
-void secure_timer_init(void)
-{
- writel(0xffffffff, TIMER_CHN10_BASE + TIMER_END_COUNT_L);
- writel(0xffffffff, TIMER_CHN10_BASE + TIMER_END_COUNT_H);
- writel(0, TIMER_CHN10_BASE + TIMER_INIT_COUNT_L);
- writel(0, TIMER_CHN10_BASE + TIMER_INIT_COUNT_H);
- writel(TIMER_EN | TIMER_FMODE, TIMER_CHN10_BASE + TIMER_CONTROL_REG);
-}
-
-void board_init_f(ulong dummy)
-{
- struct udevice *dev;
- int ret;
-
-#ifdef CONFIG_DEBUG_UART
- debug_uart_init();
- /*
- * Debug UART can be used from here if required:
- *
- * debug_uart_init();
- * printch('a');
- * printhex8(0x1234);
- * printascii("string");
- */
- debug("U-Boot TPL board init\n");
-#endif
- ret = spl_early_init();
- if (ret) {
- debug("spl_early_init() failed: %d\n", ret);
- hang();
- }
-
- secure_timer_init();
-
- ret = uclass_get_device(UCLASS_RAM, 0, &dev);
- if (ret) {
- pr_err("DRAM init failed: %d\n", ret);
- return;
- }
-}
-
-void board_return_to_bootrom(void)
-{
- back_to_bootrom(BROM_BOOT_NEXTSTAGE);
-}
-
-u32 spl_boot_device(void)
-{
- return BOOT_DEVICE_BOOTROM;
-}
-
-void spl_board_init(void)
-{
- puts("\nU-Boot TPL " PLAIN_VERSION " (" U_BOOT_DATE " - "
- U_BOOT_TIME " " U_BOOT_TZ ")\n");
-}
-
-#ifdef CONFIG_SPL_LOAD_FIT
-int board_fit_config_name_match(const char *name)
-{
- /* Just empty function now - can't decide what to choose */
- debug("%s: %s\n", __func__, name);
-
- return 0;
-}
-#endif
diff --git a/arch/arm/mach-rockchip/rk3399/Kconfig b/arch/arm/mach-rockchip/rk3399/Kconfig
index 2c5c93c..6660d05 100644
--- a/arch/arm/mach-rockchip/rk3399/Kconfig
+++ b/arch/arm/mach-rockchip/rk3399/Kconfig
@@ -64,11 +64,32 @@
endchoice
+config ROCKCHIP_BOOT_MODE_REG
+ default 0xff320300
+
config SYS_SOC
default "rk3399"
config SYS_MALLOC_F_LEN
- default 0x0800
+ default 0x4000
+
+config SPL_LIBCOMMON_SUPPORT
+ default y
+
+config SPL_LIBGENERIC_SUPPORT
+ default y
+
+config TPL_LDSCRIPT
+ default "arch/arm/mach-rockchip/u-boot-tpl-v8.lds"
+
+config TPL_MAX_SIZE
+ default 188416
+
+config TPL_STACK
+ default 0xff8effff
+
+config TPL_TEXT_BASE
+ default 0xff8c2000
source "board/rockchip/evb_rk3399/Kconfig"
source "board/theobroma-systems/puma_rk3399/Kconfig"
diff --git a/arch/arm/mach-rockchip/rk3399/rk3399.c b/arch/arm/mach-rockchip/rk3399/rk3399.c
index e1f9f8b..0f09ea5 100644
--- a/arch/arm/mach-rockchip/rk3399/rk3399.c
+++ b/arch/arm/mach-rockchip/rk3399/rk3399.c
@@ -38,6 +38,35 @@
struct mm_region *mem_map = rk3399_mem_map;
+#ifdef CONFIG_SPL_BUILD
+
+#define TIMER_END_COUNT_L 0x00
+#define TIMER_END_COUNT_H 0x04
+#define TIMER_INIT_COUNT_L 0x10
+#define TIMER_INIT_COUNT_H 0x14
+#define TIMER_CONTROL_REG 0x1c
+
+#define TIMER_EN 0x1
+#define TIMER_FMODE BIT(0)
+#define TIMER_RMODE BIT(1)
+
+void rockchip_stimer_init(void)
+{
+ /* If Timer already enabled, don't re-init it */
+ u32 reg = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+
+ if (reg & TIMER_EN)
+ return;
+
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_END_COUNT_L);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_END_COUNT_H);
+ writel(0, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_INIT_COUNT_L);
+ writel(0, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_INIT_COUNT_H);
+ writel(TIMER_EN | TIMER_FMODE, CONFIG_ROCKCHIP_STIMER_BASE + \
+ TIMER_CONTROL_REG);
+}
+#endif
+
int dram_init_banksize(void)
{
size_t max_size = min((unsigned long)gd->ram_size, gd->ram_top);
diff --git a/arch/arm/mach-rockchip/rk3399/syscon_rk3399.c b/arch/arm/mach-rockchip/rk3399/syscon_rk3399.c
index a8bb5b1..259ca44 100644
--- a/arch/arm/mach-rockchip/rk3399/syscon_rk3399.c
+++ b/arch/arm/mach-rockchip/rk3399/syscon_rk3399.c
@@ -13,6 +13,7 @@
{ .compatible = "rockchip,rk3399-pmugrf", .data = ROCKCHIP_SYSCON_PMUGRF },
{ .compatible = "rockchip,rk3399-pmusgrf", .data = ROCKCHIP_SYSCON_PMUSGRF },
{ .compatible = "rockchip,rk3399-cic", .data = ROCKCHIP_SYSCON_CIC },
+ { .compatible = "rockchip,rk3399-pmu", .data = ROCKCHIP_SYSCON_PMU },
{ }
};
@@ -58,4 +59,11 @@
.of_match = rk3399_syscon_ids + 3,
.bind = rk3399_syscon_bind_of_platdata,
};
+
+U_BOOT_DRIVER(rockchip_rk3399_pmu) = {
+ .name = "rockchip_rk3399_pmu",
+ .id = UCLASS_SYSCON,
+ .of_match = rk3399_syscon_ids + 4,
+ .bind = rk3399_syscon_bind_of_platdata,
+};
#endif
diff --git a/arch/arm/mach-rockchip/rk_timer.c b/arch/arm/mach-rockchip/rk_timer.c
deleted file mode 100644
index 29d379f..0000000
--- a/arch/arm/mach-rockchip/rk_timer.c
+++ /dev/null
@@ -1,40 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2015 Rockchip Electronics Co., Ltd
- */
-
-#include <common.h>
-#include <asm/arch-rockchip/timer.h>
-#include <asm/io.h>
-#include <linux/types.h>
-
-struct rk_timer * const timer_ptr = (void *)CONFIG_SYS_TIMER_BASE;
-
-static uint64_t rockchip_get_ticks(void)
-{
- uint64_t timebase_h, timebase_l;
-
- timebase_l = readl(&timer_ptr->timer_curr_value0);
- timebase_h = readl(&timer_ptr->timer_curr_value1);
-
- return timebase_h << 32 | timebase_l;
-}
-
-void rockchip_udelay(unsigned int usec)
-{
- uint64_t tmp;
-
- /* get timestamp */
- tmp = rockchip_get_ticks() + usec_to_tick(usec);
-
- /* loop till event */
- while (rockchip_get_ticks() < tmp+1)
- ;
-}
-
-void rockchip_timer_init(void)
-{
- writel(0xffffffff, &timer_ptr->timer_load_count0);
- writel(0xffffffff, &timer_ptr->timer_load_count1);
- writel(1, &timer_ptr->timer_ctrl_reg);
-}
diff --git a/arch/arm/mach-rockchip/rv1108/Kconfig b/arch/arm/mach-rockchip/rv1108/Kconfig
index e3a63b8..a12216d 100644
--- a/arch/arm/mach-rockchip/rv1108/Kconfig
+++ b/arch/arm/mach-rockchip/rv1108/Kconfig
@@ -1,5 +1,8 @@
if ROCKCHIP_RV1108
+choice
+ prompt "RV1108 board select"
+
config TARGET_EVB_RV1108
bool "EVB_RV1108"
help
@@ -22,6 +25,11 @@
help
RV1108 ELGIN is a board based on the Rockchip RV1108.
+endchoice
+
+config ROCKCHIP_BOOT_MODE_REG
+ default 0x10300580
+
config SYS_SOC
default "rv1108"
diff --git a/arch/arm/mach-rockchip/spl-boot-order.c b/arch/arm/mach-rockchip/spl-boot-order.c
index 0e485de..c19c285 100644
--- a/arch/arm/mach-rockchip/spl-boot-order.c
+++ b/arch/arm/mach-rockchip/spl-boot-order.c
@@ -8,7 +8,7 @@
#include <mmc.h>
#include <spl.h>
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_LIBFDT)
/**
* spl_node_to_boot_device() - maps from a DT-node to a SPL boot device
* @node: of_offset of the node
diff --git a/arch/arm/mach-rockchip/tpl.c b/arch/arm/mach-rockchip/tpl.c
new file mode 100644
index 0000000..55f6e92
--- /dev/null
+++ b/arch/arm/mach-rockchip/tpl.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <ram.h>
+#include <spl.h>
+#include <version.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/bootrom.h>
+
+#define TIMER_LOAD_COUNT_L 0x00
+#define TIMER_LOAD_COUNT_H 0x04
+#define TIMER_CONTROL_REG 0x10
+#define TIMER_EN 0x1
+#define TIMER_FMODE BIT(0)
+#define TIMER_RMODE BIT(1)
+
+__weak void rockchip_stimer_init(void)
+{
+ /* If Timer already enabled, don't re-init it */
+ u32 reg = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+
+ if (reg & TIMER_EN)
+ return;
+
+#ifndef CONFIG_ARM64
+ asm volatile("mcr p15, 0, %0, c14, c0, 0"
+ : : "r"(COUNTER_FREQUENCY));
+#endif
+
+ writel(0, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE);
+ writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + 4);
+ writel(TIMER_EN | TIMER_FMODE, CONFIG_ROCKCHIP_STIMER_BASE +
+ TIMER_CONTROL_REG);
+}
+
+void board_init_f(ulong dummy)
+{
+ struct udevice *dev;
+ int ret;
+
+#if defined(CONFIG_DEBUG_UART) && defined(CONFIG_TPL_SERIAL_SUPPORT)
+ /*
+ * Debug UART can be used from here if required:
+ *
+ * debug_uart_init();
+ * printch('a');
+ * printhex8(0x1234);
+ * printascii("string");
+ */
+ debug_uart_init();
+#ifdef CONFIG_TPL_BANNER_PRINT
+ printascii("\nU-Boot TPL " PLAIN_VERSION " (" U_BOOT_DATE " - " \
+ U_BOOT_TIME ")\n");
+#endif
+#endif
+ ret = spl_early_init();
+ if (ret) {
+ debug("spl_early_init() failed: %d\n", ret);
+ hang();
+ }
+
+ /* Init secure timer */
+ rockchip_stimer_init();
+ /* Init ARM arch timer in arch/arm/cpu/ */
+ timer_init();
+
+ ret = uclass_get_device(UCLASS_RAM, 0, &dev);
+ if (ret) {
+ printf("DRAM init failed: %d\n", ret);
+ return;
+ }
+}
+
+void board_return_to_bootrom(void)
+{
+ back_to_bootrom(BROM_BOOT_NEXTSTAGE);
+}
+
+u32 spl_boot_device(void)
+{
+ return BOOT_DEVICE_BOOTROM;
+}
diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c
index 139bb09..1d91b2d 100644
--- a/arch/arm/mach-stm32mp/psci.c
+++ b/arch/arm/mach-stm32mp/psci.c
@@ -30,7 +30,7 @@
PSCI_AFFINITY_LEVEL_ON,
PSCI_AFFINITY_LEVEL_OFF};
-void __secure psci_set_state(int cpu, u8 state)
+static inline void psci_set_state(int cpu, u8 state)
{
psci_state[cpu] = state;
dsb();
@@ -67,7 +67,7 @@
writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER);
}
-int __secure psci_features(u32 function_id, u32 psci_fid)
+s32 __secure psci_features(u32 function_id, u32 psci_fid)
{
switch (psci_fid) {
case ARM_PSCI_0_2_FN_PSCI_VERSION:
@@ -82,12 +82,12 @@
return ARM_PSCI_RET_NI;
}
-unsigned int __secure psci_version(u32 function_id)
+u32 __secure psci_version(void)
{
return ARM_PSCI_VER_1_0;
}
-int __secure psci_affinity_info(u32 function_id, u32 target_affinity,
+s32 __secure psci_affinity_info(u32 function_id, u32 target_affinity,
u32 lowest_affinity_level)
{
u32 cpu = target_affinity & MPIDR_AFF0;
@@ -104,7 +104,7 @@
return psci_state[cpu];
}
-int __secure psci_migrate_info_type(u32 function_id)
+u32 __secure psci_migrate_info_type(void)
{
/*
* in Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
@@ -116,7 +116,7 @@
return 2;
}
-int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
+s32 __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
u32 context_id)
{
u32 cpu = target_cpu & MPIDR_AFF0;
@@ -161,7 +161,7 @@
return ARM_PSCI_RET_SUCCESS;
}
-int __secure psci_cpu_off(u32 function_id)
+s32 __secure psci_cpu_off(void)
{
u32 cpu;
@@ -181,7 +181,7 @@
wfi();
}
-void __secure psci_system_reset(u32 function_id)
+void __secure psci_system_reset(void)
{
/* System reset */
writel(RCC_MP_GRSTCSETR_MPSYSRST, RCC_MP_GRSTCSETR);
@@ -190,7 +190,7 @@
wfi();
}
-void __secure psci_system_off(u32 function_id)
+void __secure psci_system_off(void)
{
/* System Off is not managed, waiting user power off
* TODO: handle I2C write in PMIC Main Control register bit 0 = SWOFF
diff --git a/arch/arm/mach-uniphier/arm32/psci.c b/arch/arm/mach-uniphier/arm32/psci.c
index 3f67edf..ef35923 100644
--- a/arch/arm/mach-uniphier/arm32/psci.c
+++ b/arch/arm/mach-uniphier/arm32/psci.c
@@ -130,7 +130,7 @@
u32 uniphier_psci_holding_pen_release __secure_data = 0xffffffff;
-int __secure psci_cpu_on(u32 function_id, u32 cpuid, u32 entry_point,
+s32 __secure psci_cpu_on(u32 function_id, u32 cpuid, u32 entry_point,
u32 context_id)
{
u32 cpu = cpuid & 0xff;
@@ -155,7 +155,7 @@
return PSCI_RET_SUCCESS;
}
-void __secure psci_system_reset(u32 function_id)
+void __secure psci_system_reset(void)
{
reset_cpu(0);
}
diff --git a/arch/riscv/lib/crt0_riscv_efi.S b/arch/riscv/lib/crt0_riscv_efi.S
index b7b5329..87fe1e5 100644
--- a/arch/riscv/lib/crt0_riscv_efi.S
+++ b/arch/riscv/lib/crt0_riscv_efi.S
@@ -14,12 +14,12 @@
#define SIZE_LONG 8
#define SAVE_LONG(reg, idx) sd reg, (idx*SIZE_LONG)(sp)
#define LOAD_LONG(reg, idx) ld reg, (idx*SIZE_LONG)(sp)
-#define PE_MACHINE 0x5064
+#define PE_MACHINE IMAGE_FILE_MACHINE_RISCV64
#else
#define SIZE_LONG 4
#define SAVE_LONG(reg, idx) sw reg, (idx*SIZE_LONG)(sp)
#define LOAD_LONG(reg, idx) lw reg, (idx*SIZE_LONG)(sp)
-#define PE_MACHINE 0x5032
+#define PE_MACHINE IMAGE_FILE_MACHINE_RISCV32
#endif
@@ -30,12 +30,11 @@
*/
.globl ImageBase
ImageBase:
- .ascii "MZ"
+ .short IMAGE_DOS_SIGNATURE /* 'MZ' */
.skip 58 /* 'MZ' + pad + offset == 64 */
.long pe_header - ImageBase /* Offset to the PE header */
pe_header:
- .ascii "PE"
- .short 0
+ .long IMAGE_NT_SIGNATURE /* 'PE' */
coff_header:
.short PE_MACHINE /* RISC-V 64/32-bit */
.short 2 /* nr_sections */
@@ -49,7 +48,7 @@
IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
IMAGE_FILE_DEBUG_STRIPPED)
optional_header:
- .short 0x20b /* PE32+ format */
+ .short IMAGE_NT_OPTIONAL_HDR64_MAGIC /* PE32+ format */
.byte 0x02 /* MajorLinkerVersion */
.byte 0x14 /* MinorLinkerVersion */
.long _edata - _start /* SizeOfCode */
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 531c1af..a05414e 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -756,6 +756,10 @@
3 0x300 0xB000 0x1000
>;
+ dma-ranges = <0 0x000 0x10000000 0x1000
+ 1 0x100 0x20000000 0x1000
+ >;
+
dev@0,0 {
compatible = "denx,u-boot-fdt-dummy";
reg = <0 0x0 0x1000>;
@@ -824,7 +828,28 @@
dma-names = "m2m", "tx0", "rx0";
};
+ /*
+ * keep mdio-mux ahead of mdio so that the mux is removed first at the
+ * end of the test. If parent mdio is removed first, clean-up of the
+ * mux will trigger a 2nd probe of parent-mdio, leaving parent-mdio
+ * active at the end of the test. That it turn doesn't allow the mdio
+ * class to be destroyed, triggering an error.
+ */
+ mdio-mux-test {
+ compatible = "sandbox,mdio-mux";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mdio-parent-bus = <&mdio>;
+
+ mdio-ch-test@0 {
+ reg = <0>;
+ };
+ mdio-ch-test@1 {
+ reg = <1>;
+ };
+ };
+
- mdio-test {
+ mdio: mdio-test {
compatible = "sandbox,mdio";
};
};
diff --git a/board/amarula/vyasa-rk3288/vyasa-rk3288.c b/board/amarula/vyasa-rk3288/vyasa-rk3288.c
index 2b509f5..baf197c 100644
--- a/board/amarula/vyasa-rk3288/vyasa-rk3288.c
+++ b/board/amarula/vyasa-rk3288/vyasa-rk3288.c
@@ -6,14 +6,6 @@
#include <common.h>
#ifndef CONFIG_TPL_BUILD
-#include <spl.h>
-
-void board_boot_order(u32 *spl_boot_list)
-{
- /* eMMC prior to sdcard. */
- spl_boot_list[0] = BOOT_DEVICE_MMC2;
- spl_boot_list[1] = BOOT_DEVICE_MMC1;
-}
int spl_start_uboot(void)
{
diff --git a/board/chipspark/popmetal_rk3288/popmetal-rk3288.c b/board/chipspark/popmetal_rk3288/popmetal-rk3288.c
index 355c78b..9ba1fbd 100644
--- a/board/chipspark/popmetal_rk3288/popmetal-rk3288.c
+++ b/board/chipspark/popmetal_rk3288/popmetal-rk3288.c
@@ -4,16 +4,8 @@
*/
#include <common.h>
-#include <spl.h>
#include <asm/gpio.h>
-void board_boot_order(u32 *spl_boot_list)
-{
- /* eMMC prior to sdcard */
- spl_boot_list[0] = BOOT_DEVICE_MMC2;
- spl_boot_list[1] = BOOT_DEVICE_MMC1;
-}
-
#define GPIO7A3_HUB_RST 227
int rk_board_late_init(void)
diff --git a/board/davinci/da8xxevm/da850evm.c b/board/davinci/da8xxevm/da850evm.c
index 5180128..43483d5 100644
--- a/board/davinci/da8xxevm/da850evm.c
+++ b/board/davinci/da8xxevm/da850evm.c
@@ -13,7 +13,6 @@
#include <environment.h>
#include <i2c.h>
#include <net.h>
-#include <netdev.h>
#include <spi.h>
#include <spi_flash.h>
#include <asm/arch/hardware.h>
@@ -482,11 +481,6 @@
if (rmii_hw_init())
printf("RMII hardware init failed!!!\n");
#endif
- if (!davinci_emac_initialize()) {
- printf("Error: Ethernet init failed!\n");
- return -1;
- }
-
return 0;
}
#endif /* CONFIG_DRIVER_TI_EMAC */
diff --git a/board/davinci/da8xxevm/omapl138_lcdk.c b/board/davinci/da8xxevm/omapl138_lcdk.c
index fe1bf44..dd11551 100644
--- a/board/davinci/da8xxevm/omapl138_lcdk.c
+++ b/board/davinci/da8xxevm/omapl138_lcdk.c
@@ -11,7 +11,6 @@
#include <common.h>
#include <i2c.h>
#include <net.h>
-#include <netdev.h>
#include <spi.h>
#include <spi_flash.h>
#include <asm/arch/hardware.h>
@@ -229,19 +228,6 @@
#ifdef CONFIG_DRIVER_TI_EMAC
-/*
- * Initializes on-board ethernet controllers.
- */
-int board_eth_init(bd_t *bis)
-{
- if (!davinci_emac_initialize()) {
- printf("Error: Ethernet init failed!\n");
- return -1;
- }
-
- return 0;
-}
-
#endif /* CONFIG_DRIVER_TI_EMAC */
#define CFG_MAC_ADDR_SPI_BUS 0
diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig
index 7f9a74d..6cc7c31 100644
--- a/board/emulation/qemu-riscv/Kconfig
+++ b/board/emulation/qemu-riscv/Kconfig
@@ -24,6 +24,7 @@
imply VIRTIO_MMIO
imply VIRTIO_NET
imply VIRTIO_BLK
+ imply VIRTIO_PCI
imply CMD_PING
imply CMD_FS_GENERIC
imply DOS_PARTITION
diff --git a/board/freescale/ls1021atsn/Kconfig b/board/freescale/ls1021atsn/Kconfig
new file mode 100644
index 0000000..d999fa4
--- /dev/null
+++ b/board/freescale/ls1021atsn/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+if TARGET_LS1021ATSN
+
+config SYS_BOARD
+ default "ls1021atsn"
+
+config SYS_VENDOR
+ default "freescale"
+
+config SYS_SOC
+ default "ls102xa"
+
+config SYS_CONFIG_NAME
+ default "ls1021atsn"
+
+source "board/freescale/common/Kconfig"
+
+endif
diff --git a/board/freescale/ls1021atsn/MAINTAINERS b/board/freescale/ls1021atsn/MAINTAINERS
new file mode 100644
index 0000000..560bb61
--- /dev/null
+++ b/board/freescale/ls1021atsn/MAINTAINERS
@@ -0,0 +1,8 @@
+NXP LS1021A-TSN Board
+M: Vladimir Oltean <olteanv@gmail.com>
+S: Maintained
+F: arch/arm/dts/ls1021a-tsn.dts
+F: board/freescale/ls1021atsn/
+F: include/configs/ls1021atsn.h
+F: configs/ls1021atsn_qspi_defconfig
+F: configs/ls1021atsn_sdcard_defconfig
diff --git a/board/freescale/ls1021atsn/Makefile b/board/freescale/ls1021atsn/Makefile
new file mode 100644
index 0000000..b4808f0
--- /dev/null
+++ b/board/freescale/ls1021atsn/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-y += ls1021atsn.o
+obj-$(CONFIG_ARMV7_PSCI) += ../ls1021atwr/psci.o
diff --git a/board/freescale/ls1021atsn/README.rst b/board/freescale/ls1021atsn/README.rst
new file mode 100644
index 0000000..cdec02f
--- /dev/null
+++ b/board/freescale/ls1021atsn/README.rst
@@ -0,0 +1,97 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+LS1021A-TSN Board Overview
+==========================
+
+ - 1GB DDR3 at 800 MHz
+ - Spansion/Cypress 64 MB (Rev. A) / 32 MB (Rev. B and C) QSPI NOR flash
+ - Ethernet
+ - 2 SGMII 10/100/1G Ethernet ports (Atheros AR8031)
+ - One SJA1105T switch with 4 Ethernet ports (Broadcom BCM5464R)
+ - One internal RGMII port connected to the switch
+ - SDHC
+ - microSDHC/SDXC connector
+ - Other I/O
+ - One Serial port
+ - Arduino and expansion headers
+ - mPCIE slot
+ - SATA port
+ - USB3.0 port
+
+LS1021A Memory map
+==================
+
+The addresses in brackets are physical addresses.
+
+============== ============== ============================== =======
+Start Address End Address Description Size
+============== ============== ============================== =======
+0x00_0000_0000 0x00_000F_FFFF Secure Boot ROM 1MB
+0x00_0100_0000 0x00_0FFF_FFFF CCSRBAR 240MB
+0x00_1000_0000 0x00_1000_FFFF OCRAM0 64KB
+0x00_1001_0000 0x00_1001_FFFF OCRAM1 64KB
+0x00_2000_0000 0x00_20FF_FFFF DCSR 16MB
+0x00_4000_0000 0x00_5FFF_FFFF QSPI 512MB
+0x00_6000_0000 0x00_67FF_FFFF IFC - NOR Flash 128MB
+0x00_8000_0000 0x00_FFFF_FFFF DRAM1 2GB
+============== ============== ============================== =======
+
+Compiling and flashing
+======================
+
+The LS1021A-TSN board comes along with a microSD card with OpenIL U-Boot that
+can be used to update its internal QSPI flash (which is empty out of the
+factory).
+
+To compile and flash an SD card image::
+
+ make ls1021atsn_sdcard_defconfig && make -j 8 && sudo cp u-boot-with-spl-pbl.bin /srv/tftpboot/
+ => tftp 0x82000000 u-boot-with-spl-pbl.bin && mmc rescan && mmc erase 8 0x1100 && mmc write 0x82000000 8 0x1100
+
+For the QSPI flash, first obtain the Reset Configuration Word binary for
+bootimg from the QSPI flash from the rcw project
+(https://source.codeaurora.org/external/qoriq/qoriq-components/rcw)::
+
+ make -j 8 && sudo cp ls1021atsn/SSR_PNS_30/rcw_1200_qspiboot.bin.swapped /srv/tftpboot/
+
+The above RCW binary takes care of swapping the QSPI AMBA memory, so that the
+U-Boot binary does not need to be swapped when flashing it.
+
+To compile and flash a U-Boot image for QSPI::
+
+ make ls1021atsn_qspi_defconfig && make -j 8 && sudo cp u-boot.bin /srv/tftpboot/
+
+Then optionally create a custom uboot-env.txt file (although the default
+environment already supports distro boot) and convert it to binary format::
+
+ mkenvimage -s 2M -o /srv/tftpboot/uboot-env.bin uboot-env.txt
+
+To program the QSPI flash with the images::
+
+ => tftp 0x82000000 rcw_1200_qspiboot.bin.swapped && sf probe && sf erase 0x0 +${filesize} && sf write 0x82000000 0x0 ${filesize}
+ => tftp 0x82000000 u-boot.bin && sf probe && sf erase 0x100000 +${filesize} && sf write 0x82000000 0x100000 ${filesize}
+ => tftp 0x82000000 uboot-env.bin && sf probe && sf erase 0x400000 +${filesize} && sf write 0x82000000 0x400000 ${filesize}
+
+The boards contain an AT24 I2C EEPROM that is supposed to hold the MAC
+addresses of the Ethernet interfaces, however the EEPROM comes blank out of
+the factory, and the MAC addresses are printed on a label on the bottom of
+the boards.
+
+To write the MAC addresses to the EEPROM, the following needs to be done once::
+
+ => mac id
+ => mac 0 00:1F:7B:xx:xx:xx
+ => mac 1 00:1F:7B:xx:xx:xx
+ => mac 2 00:1F:7B:xx:xx:xx
+ => mac save
+
+The switch ports do not have their own MAC address - they inherit it from the
+master enet2 port.
+
+Known issues and limitations
+============================
+
+- The 4 SJA1105 switch ports are not functional in U-Boot for now.
+- Since the IFC pins are multiplexed with QSPI on LS1021A, currently there is
+ no way to talk to the CPLD for e.g. running the "qixis_reset" command, or
+ turning the fan on, etc.
diff --git a/board/freescale/ls1021atsn/ls1021atsn.c b/board/freescale/ls1021atsn/ls1021atsn.c
new file mode 100644
index 0000000..39e825c
--- /dev/null
+++ b/board/freescale/ls1021atsn/ls1021atsn.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2016-2019 NXP Semiconductors
+ */
+#include <common.h>
+#include <asm/arch-ls102xa/ls102xa_soc.h>
+#include <asm/arch/ls102xa_devdis.h>
+#include <asm/arch/immap_ls102xa.h>
+#include <asm/arch/ls102xa_soc.h>
+#include <asm/arch/fsl_serdes.h>
+#include "../common/sleep.h"
+#include <fsl_validate.h>
+#include <fsl_immap.h>
+#include <fsl_csu.h>
+#include <netdev.h>
+#include <spl.h>
+#ifdef CONFIG_U_QE
+#include <fsl_qe.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void ddrmc_init(void)
+{
+#if (!defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD))
+ struct ccsr_ddr *ddr = (struct ccsr_ddr *)CONFIG_SYS_FSL_DDR_ADDR;
+ u32 temp_sdram_cfg, tmp;
+
+ out_be32(&ddr->sdram_cfg, DDR_SDRAM_CFG);
+
+ out_be32(&ddr->cs0_bnds, DDR_CS0_BNDS);
+ out_be32(&ddr->cs0_config, DDR_CS0_CONFIG);
+
+ out_be32(&ddr->timing_cfg_0, DDR_TIMING_CFG_0);
+ out_be32(&ddr->timing_cfg_1, DDR_TIMING_CFG_1);
+ out_be32(&ddr->timing_cfg_2, DDR_TIMING_CFG_2);
+ out_be32(&ddr->timing_cfg_3, DDR_TIMING_CFG_3);
+ out_be32(&ddr->timing_cfg_4, DDR_TIMING_CFG_4);
+ out_be32(&ddr->timing_cfg_5, DDR_TIMING_CFG_5);
+
+#ifdef CONFIG_DEEP_SLEEP
+ if (is_warm_boot()) {
+ out_be32(&ddr->sdram_cfg_2,
+ DDR_SDRAM_CFG_2 & ~SDRAM_CFG2_D_INIT);
+ out_be32(&ddr->init_addr, CONFIG_SYS_SDRAM_BASE);
+ out_be32(&ddr->init_ext_addr, (1 << 31));
+
+ /* DRAM VRef will not be trained */
+ out_be32(&ddr->ddr_cdr2,
+ DDR_DDR_CDR2 & ~DDR_CDR2_VREF_TRAIN_EN);
+ } else
+#endif
+ {
+ out_be32(&ddr->sdram_cfg_2, DDR_SDRAM_CFG_2);
+ out_be32(&ddr->ddr_cdr2, DDR_DDR_CDR2);
+ }
+
+ out_be32(&ddr->sdram_mode, DDR_SDRAM_MODE);
+ out_be32(&ddr->sdram_mode_2, DDR_SDRAM_MODE_2);
+
+ out_be32(&ddr->sdram_interval, DDR_SDRAM_INTERVAL);
+
+ out_be32(&ddr->ddr_wrlvl_cntl, DDR_DDR_WRLVL_CNTL);
+
+ out_be32(&ddr->ddr_wrlvl_cntl_2, DDR_DDR_WRLVL_CNTL_2);
+ out_be32(&ddr->ddr_wrlvl_cntl_3, DDR_DDR_WRLVL_CNTL_3);
+
+ out_be32(&ddr->ddr_cdr1, DDR_DDR_CDR1);
+
+ out_be32(&ddr->sdram_clk_cntl, DDR_SDRAM_CLK_CNTL);
+ out_be32(&ddr->ddr_zq_cntl, DDR_DDR_ZQ_CNTL);
+
+ out_be32(&ddr->cs0_config_2, DDR_CS0_CONFIG_2);
+
+ /* DDR erratum A-009942 */
+ tmp = in_be32(&ddr->debug[28]);
+ out_be32(&ddr->debug[28], tmp | 0x0070006f);
+
+ udelay(1);
+
+#ifdef CONFIG_DEEP_SLEEP
+ if (is_warm_boot()) {
+ /* enter self-refresh */
+ temp_sdram_cfg = in_be32(&ddr->sdram_cfg_2);
+ temp_sdram_cfg |= SDRAM_CFG2_FRC_SR;
+ out_be32(&ddr->sdram_cfg_2, temp_sdram_cfg);
+
+ temp_sdram_cfg = (DDR_SDRAM_CFG_MEM_EN | SDRAM_CFG_BI);
+ } else
+#endif
+ temp_sdram_cfg = (DDR_SDRAM_CFG_MEM_EN & ~SDRAM_CFG_BI);
+
+ out_be32(&ddr->sdram_cfg, DDR_SDRAM_CFG | temp_sdram_cfg);
+
+#ifdef CONFIG_DEEP_SLEEP
+ if (is_warm_boot()) {
+ /* exit self-refresh */
+ temp_sdram_cfg = in_be32(&ddr->sdram_cfg_2);
+ temp_sdram_cfg &= ~SDRAM_CFG2_FRC_SR;
+ out_be32(&ddr->sdram_cfg_2, temp_sdram_cfg);
+ }
+#endif
+#endif /* !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) */
+}
+
+int dram_init(void)
+{
+ ddrmc_init();
+
+ erratum_a008850_post();
+
+ gd->ram_size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE);
+
+#if defined(CONFIG_DEEP_SLEEP) && !defined(CONFIG_SPL_BUILD)
+ fsl_dp_resume();
+#endif
+
+ return 0;
+}
+
+int board_eth_init(bd_t *bis)
+{
+ return pci_eth_init(bis);
+}
+
+int board_early_init_f(void)
+{
+ struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
+
+#ifdef CONFIG_TSEC_ENET
+ /*
+ * Clear BD & FR bits for big endian BD's and frame data (aka set
+ * correct eTSEC endianness). This is crucial in ensuring that it does
+ * not report Data Parity Errors in its RX/TX FIFOs when attempting to
+ * send traffic.
+ */
+ clrbits_be32(&scfg->etsecdmamcr, SCFG_ETSECDMAMCR_LE_BD_FR);
+ /* EC3_GTX_CLK125 (of enet2) used for all RGMII interfaces */
+ out_be32(&scfg->etsecmcr, SCFG_ETSECCMCR_GE2_CLK125);
+#endif
+
+ arch_soc_init();
+
+#if defined(CONFIG_DEEP_SLEEP)
+ if (is_warm_boot()) {
+ timer_init();
+ dram_init();
+ }
+#endif
+
+ return 0;
+}
+
+#ifdef CONFIG_SPL_BUILD
+void board_init_f(ulong dummy)
+{
+ void (*second_uboot)(void);
+
+ /* Clear the BSS */
+ memset(__bss_start, 0, __bss_end - __bss_start);
+
+ get_clocks();
+
+#if defined(CONFIG_DEEP_SLEEP)
+ if (is_warm_boot())
+ fsl_dp_disable_console();
+#endif
+
+ preloader_console_init();
+
+ dram_init();
+
+ /* Allow OCRAM access permission as R/W */
+#ifdef CONFIG_LAYERSCAPE_NS_ACCESS
+ enable_layerscape_ns_access();
+ enable_layerscape_ns_access();
+#endif
+
+ /*
+ * if it is woken up from deep sleep, then jump to second
+ * stage U-Boot and continue executing without recopying
+ * it from SD since it has already been reserved in memory
+ * in last boot.
+ */
+ if (is_warm_boot()) {
+ second_uboot = (void (*)(void))CONFIG_SYS_TEXT_BASE;
+ second_uboot();
+ }
+
+ board_init_r(NULL, 0);
+}
+#endif
+
+int board_init(void)
+{
+#ifndef CONFIG_SYS_FSL_NO_SERDES
+ fsl_serdes_init();
+#endif
+ ls102xa_smmu_stream_id_init();
+
+#ifdef CONFIG_LAYERSCAPE_NS_ACCESS
+ enable_layerscape_ns_access();
+#endif
+
+#ifdef CONFIG_U_QE
+ u_qe_init();
+#endif
+
+ return 0;
+}
+
+#if defined(CONFIG_SPL_BUILD)
+void spl_board_init(void)
+{
+ ls102xa_smmu_stream_id_init();
+}
+#endif
+
+#ifdef CONFIG_BOARD_LATE_INIT
+int board_late_init(void)
+{
+#ifdef CONFIG_CHAIN_OF_TRUST
+ fsl_setenv_chain_of_trust();
+#endif
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_MISC_INIT_R)
+int misc_init_r(void)
+{
+#ifdef CONFIG_FSL_DEVICE_DISABLE
+ device_disable(devdis_tbl, ARRAY_SIZE(devdis_tbl));
+#endif
+
+#ifdef CONFIG_FSL_CAAM
+ return sec_init();
+#endif
+}
+#endif
+
+#if defined(CONFIG_DEEP_SLEEP)
+void board_sleep_prepare(void)
+{
+#ifdef CONFIG_LAYERSCAPE_NS_ACCESS
+ enable_layerscape_ns_access();
+#endif
+}
+#endif
+
+int ft_board_setup(void *blob, bd_t *bd)
+{
+ ft_cpu_setup(blob, bd);
+
+#ifdef CONFIG_PCI
+ ft_pci_setup(blob, bd);
+#endif
+
+ return 0;
+}
diff --git a/board/freescale/ls1021atsn/ls102xa_pbi.cfg b/board/freescale/ls1021atsn/ls102xa_pbi.cfg
new file mode 100644
index 0000000..ba1499b
--- /dev/null
+++ b/board/freescale/ls1021atsn/ls102xa_pbi.cfg
@@ -0,0 +1,15 @@
+# PBI commands
+
+09570200 ffffffff
+09570158 00000300
+8940007c 21f47300
+
+# Configure Scratch register
+09ee0200 10000000
+# Configure alternate space
+09570158 00001000
+# Flush PBL data
+096100c0 000FFFFF
+
+09ea085c 00502880
+09ea0560 80800000
diff --git a/board/freescale/ls1021atsn/ls102xa_rcw_sd.cfg b/board/freescale/ls1021atsn/ls102xa_rcw_sd.cfg
new file mode 100644
index 0000000..a6fc914
--- /dev/null
+++ b/board/freescale/ls1021atsn/ls102xa_rcw_sd.cfg
@@ -0,0 +1,8 @@
+# PBL preamble and RCW header
+aa55aa55 01ee0100
+
+# Disable IFC, enable QSPI and DSPI
+0608000c 00000000 00000000 00000000
+30000000 08007900 40105a00 21046000
+00000000 00000000 00000000 10002000
+20124801 8804b340 00000000 00000000
diff --git a/board/freescale/ls1021atwr/ls1021atwr.c b/board/freescale/ls1021atwr/ls1021atwr.c
index 01ba1bc..fcf2ec9 100644
--- a/board/freescale/ls1021atwr/ls1021atwr.c
+++ b/board/freescale/ls1021atwr/ls1021atwr.c
@@ -248,44 +248,6 @@
int board_eth_init(bd_t *bis)
{
-#ifdef CONFIG_TSEC_ENET
- struct fsl_pq_mdio_info mdio_info;
- struct tsec_info_struct tsec_info[4];
- int num = 0;
-
-#ifdef CONFIG_TSEC1
- SET_STD_TSEC_INFO(tsec_info[num], 1);
- if (is_serdes_configured(SGMII_TSEC1)) {
- puts("eTSEC1 is in sgmii mode.\n");
- tsec_info[num].flags |= TSEC_SGMII;
- }
- num++;
-#endif
-#ifdef CONFIG_TSEC2
- SET_STD_TSEC_INFO(tsec_info[num], 2);
- if (is_serdes_configured(SGMII_TSEC2)) {
- puts("eTSEC2 is in sgmii mode.\n");
- tsec_info[num].flags |= TSEC_SGMII;
- }
- num++;
-#endif
-#ifdef CONFIG_TSEC3
- SET_STD_TSEC_INFO(tsec_info[num], 3);
- tsec_info[num].interface = PHY_INTERFACE_MODE_RGMII_ID;
- num++;
-#endif
- if (!num) {
- printf("No TSECs initialized\n");
- return 0;
- }
-
- mdio_info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR;
- mdio_info.name = DEFAULT_MII_NAME;
- fsl_pq_mdio_init(bis, &mdio_info);
-
- tsec_eth_init(bis, tsec_info, num);
-#endif
-
return pci_eth_init(bis);
}
diff --git a/board/logicpd/am3517evm/am3517evm.c b/board/logicpd/am3517evm/am3517evm.c
index 10031a4..bfd4e78 100644
--- a/board/logicpd/am3517evm/am3517evm.c
+++ b/board/logicpd/am3517evm/am3517evm.c
@@ -28,7 +28,6 @@
#include <linux/usb/gadget.h>
#include <linux/usb/musb.h>
#include <i2c.h>
-#include <netdev.h>
#include "am3517evm.h"
DECLARE_GLOBAL_DATA_PTR;
diff --git a/board/mqmaker/miqi_rk3288/miqi-rk3288.c b/board/mqmaker/miqi_rk3288/miqi-rk3288.c
index d6992a2..779bc64 100644
--- a/board/mqmaker/miqi_rk3288/miqi-rk3288.c
+++ b/board/mqmaker/miqi_rk3288/miqi-rk3288.c
@@ -3,12 +3,3 @@
* (C) Copyright 2016 Rockchip Electronics Co., Ltd
*/
-#include <common.h>
-#include <spl.h>
-
-void board_boot_order(u32 *spl_boot_list)
-{
- /* eMMC prior to sdcard. */
- spl_boot_list[0] = BOOT_DEVICE_MMC2;
- spl_boot_list[1] = BOOT_DEVICE_MMC1;
-}
diff --git a/board/rockchip/evb_rk3288/evb-rk3288.c b/board/rockchip/evb_rk3288/evb-rk3288.c
index d6992a2..779bc64 100644
--- a/board/rockchip/evb_rk3288/evb-rk3288.c
+++ b/board/rockchip/evb_rk3288/evb-rk3288.c
@@ -3,12 +3,3 @@
* (C) Copyright 2016 Rockchip Electronics Co., Ltd
*/
-#include <common.h>
-#include <spl.h>
-
-void board_boot_order(u32 *spl_boot_list)
-{
- /* eMMC prior to sdcard. */
- spl_boot_list[0] = BOOT_DEVICE_MMC2;
- spl_boot_list[1] = BOOT_DEVICE_MMC1;
-}
diff --git a/board/rockchip/evb_rk3399/README b/board/rockchip/evb_rk3399/README
index 6469821..ea3258c 100644
--- a/board/rockchip/evb_rk3399/README
+++ b/board/rockchip/evb_rk3399/README
@@ -35,12 +35,6 @@
> git clone https://github.com/rockchip-linux/rkbin.git
> git clone https://github.com/rockchip-linux/rkdeveloptool.git
-Get some prerequisites
-======================
-
-You need the Python elftools.elf.elffile library for make_fit_atf.py to work:
-
- > sudo apt-get install python-pyelftools
Compile ATF
===========
diff --git a/board/rockchip/fennec_rk3288/fennec-rk3288.c b/board/rockchip/fennec_rk3288/fennec-rk3288.c
index ce45544..779bc64 100644
--- a/board/rockchip/fennec_rk3288/fennec-rk3288.c
+++ b/board/rockchip/fennec_rk3288/fennec-rk3288.c
@@ -3,12 +3,3 @@
* (C) Copyright 2016 Rockchip Electronics Co., Ltd
*/
-#include <common.h>
-#include <spl.h>
-
-void board_boot_order(u32 *spl_boot_list)
-{
- /* eMMC prior to sdcard */
- spl_boot_list[0] = BOOT_DEVICE_MMC2;
- spl_boot_list[1] = BOOT_DEVICE_MMC1;
-}
diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig
index 8eb5e30..5d65080 100644
--- a/board/sifive/fu540/Kconfig
+++ b/board/sifive/fu540/Kconfig
@@ -28,7 +28,6 @@
imply CMD_PING
imply CLK_SIFIVE
imply CLK_SIFIVE_FU540_PRCI
- imply CLK_SIFIVE_GEMGXL_MGMT
imply DOS_PARTITION
imply EFI_PARTITION
imply IP_DYN
@@ -39,6 +38,12 @@
imply PHY_LIB
imply PHY_MSCC
imply SIFIVE_SERIAL
+ imply SPI
+ imply SPI_SIFIVE
+ imply MMC
+ imply MMC_SPI
+ imply MMC_BROKEN_CD
+ imply CMD_MMC
imply SMP
endif
diff --git a/board/sifive/fu540/fu540.c b/board/sifive/fu540/fu540.c
index 5adc4a3..11daf1a 100644
--- a/board/sifive/fu540/fu540.c
+++ b/board/sifive/fu540/fu540.c
@@ -8,6 +8,128 @@
#include <common.h>
#include <dm.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#ifdef CONFIG_MISC_INIT_R
+
+#define FU540_OTP_BASE_ADDR 0x10070000
+
+struct fu540_otp_regs {
+ u32 pa; /* Address input */
+ u32 paio; /* Program address input */
+ u32 pas; /* Program redundancy cell selection input */
+ u32 pce; /* OTP Macro enable input */
+ u32 pclk; /* Clock input */
+ u32 pdin; /* Write data input */
+ u32 pdout; /* Read data output */
+ u32 pdstb; /* Deep standby mode enable input (active low) */
+ u32 pprog; /* Program mode enable input */
+ u32 ptc; /* Test column enable input */
+ u32 ptm; /* Test mode enable input */
+ u32 ptm_rep;/* Repair function test mode enable input */
+ u32 ptr; /* Test row enable input */
+ u32 ptrim; /* Repair function enable input */
+ u32 pwe; /* Write enable input (defines program cycle) */
+} __packed;
+
+#define BYTES_PER_FUSE 4
+#define NUM_FUSES 0x1000
+
+static int fu540_otp_read(int offset, void *buf, int size)
+{
+ struct fu540_otp_regs *regs = (void __iomem *)FU540_OTP_BASE_ADDR;
+ unsigned int i;
+ int fuseidx = offset / BYTES_PER_FUSE;
+ int fusecount = size / BYTES_PER_FUSE;
+ u32 fusebuf[fusecount];
+
+ /* check bounds */
+ if (offset < 0 || size < 0)
+ return -EINVAL;
+ if (fuseidx >= NUM_FUSES)
+ return -EINVAL;
+ if ((fuseidx + fusecount) > NUM_FUSES)
+ return -EINVAL;
+
+ /* init OTP */
+ writel(0x01, ®s->pdstb); /* wake up from stand-by */
+ writel(0x01, ®s->ptrim); /* enable repair function */
+ writel(0x01, ®s->pce); /* enable input */
+
+ /* read all requested fuses */
+ for (i = 0; i < fusecount; i++, fuseidx++) {
+ writel(fuseidx, ®s->pa);
+
+ /* cycle clock to read */
+ writel(0x01, ®s->pclk);
+ mdelay(1);
+ writel(0x00, ®s->pclk);
+ mdelay(1);
+
+ /* read the value */
+ fusebuf[i] = readl(®s->pdout);
+ }
+
+ /* shut down */
+ writel(0, ®s->pce);
+ writel(0, ®s->ptrim);
+ writel(0, ®s->pdstb);
+
+ /* copy out */
+ memcpy(buf, fusebuf, size);
+
+ return 0;
+}
+
+static u32 fu540_read_serialnum(void)
+{
+ int ret;
+ u32 serial[2] = {0};
+
+ for (int i = 0xfe * 4; i > 0; i -= 8) {
+ ret = fu540_otp_read(i, serial, sizeof(serial));
+ if (ret) {
+ printf("%s: error reading from OTP\n", __func__);
+ break;
+ }
+ if (serial[0] == ~serial[1])
+ return serial[0];
+ }
+
+ return 0;
+}
+
+static void fu540_setup_macaddr(u32 serialnum)
+{
+ /* Default MAC address */
+ unsigned char mac[6] = { 0x70, 0xb3, 0xd5, 0x92, 0xf0, 0x00 };
+
+ /*
+ * We derive our board MAC address by ORing last three bytes
+ * of board serial number to above default MAC address.
+ *
+ * This logic of deriving board MAC address is taken from
+ * SiFive FSBL and is kept unchanged.
+ */
+ mac[5] |= (serialnum >> 0) & 0xff;
+ mac[4] |= (serialnum >> 8) & 0xff;
+ mac[3] |= (serialnum >> 16) & 0xff;
+
+ /* Update environment variable */
+ eth_env_set_enetaddr("ethaddr", mac);
+}
+
+int misc_init_r(void)
+{
+ /* Set ethaddr environment variable if not set */
+ if (!env_get("ethaddr"))
+ fu540_setup_macaddr(fu540_read_serialnum());
+
+ return 0;
+}
+
+#endif
int board_init(void)
{
diff --git a/board/ti/am65x/Kconfig b/board/ti/am65x/Kconfig
index 98172c2..47b41cd 100644
--- a/board/ti/am65x/Kconfig
+++ b/board/ti/am65x/Kconfig
@@ -12,14 +12,18 @@
select ARM64
select SOC_K3_AM6
select SYS_DISABLE_DCACHE_OPS
+ select BOARD_LATE_INIT
+ imply TI_I2C_BOARD_DETECT
config TARGET_AM654_R5_EVM
bool "TI K3 based AM654 EVM running on R5"
select CPU_V7R
select SYS_THUMB_BUILD
select SOC_K3_AM6
+ select K3_LOAD_SYSFW
select K3_AM654_DDRSS
imply SYS_K3_SPL_ATF
+ imply TI_I2C_BOARD_DETECT
endchoice
@@ -34,6 +38,8 @@
config SYS_CONFIG_NAME
default "am65x_evm"
+source "board/ti/common/Kconfig"
+
endif
if TARGET_AM654_R5_EVM
@@ -50,4 +56,6 @@
config SPL_LDSCRIPT
default "arch/arm/mach-omap2/u-boot-spl.lds"
+source "board/ti/common/Kconfig"
+
endif
diff --git a/board/ti/am65x/README b/board/ti/am65x/README
index 0b82bd5..16384e0 100644
--- a/board/ti/am65x/README
+++ b/board/ti/am65x/README
@@ -209,3 +209,55 @@
| | Secure config | |
| +-------------------+ |
+-----------------------+
+
+eMMC:
+-----
+ROM supports booting from eMMC from boot0 partition offset 0x0
+
+Flashing images to eMMC:
+
+The following commands can be used to download tiboot3.bin, tispl.bin,
+u-boot.img, and sysfw.itb from an SD card and write them to the eMMC boot0
+partition at respective addresses.
+
+=> mmc dev 0 1
+=> fatload mmc 1 ${loadaddr} tiboot3.bin
+=> mmc write ${loadaddr} 0x0 0x400
+=> fatload mmc 1 ${loadaddr} tispl.bin
+=> mmc write ${loadaddr} 0x400 0x1000
+=> fatload mmc 1 ${loadaddr} u-boot.img
+=> mmc write ${loadaddr} 0x1400 0x2000
+=> fatload mmc 1 ${loadaddr} sysfw.itb
+=> mmc write ${loadaddr} 0x3600 0x800
+
+To give the ROM access to the boot partition, the following commands must be
+used for the first time:
+=> mmc partconf 0 1 1 1
+=> mmc bootbus 0 1 0 0
+
+To create a software partition for the rootfs, the following command can be
+used:
+=> gpt write mmc 0 ${partitions}
+
+eMMC layout:
+
+ boot0 partition (8 MB) user partition
+ 0x0+----------------------------------+ 0x0+-------------------------+
+ | tiboot3.bin (512 KB) | | |
+ 0x400+----------------------------------+ | |
+ | tispl.bin (2 MB) | | |
+0x1400+----------------------------------+ | rootfs |
+ | u-boot.img (4 MB) | | |
+0x3400+----------------------------------+ | |
+ | environment (128 KB) | | |
+0x3500+----------------------------------+ | |
+ | backup environment (128 KB) | | |
+0x3600+----------------------------------+ | |
+ | sysfw (1 MB) | | |
+0x3E00+----------------------------------+ +-------------------------+
+
+Kernel image and DT are expected to be present in the /boot folder of rootfs.
+To boot kernel from eMMC, use the following commands:
+=> setenv mmcdev 0
+=> setenv bootpart 0
+=> boot
diff --git a/board/ti/am65x/evm.c b/board/ti/am65x/evm.c
index 52f5d6b..7bd8c4f 100644
--- a/board/ti/am65x/evm.c
+++ b/board/ti/am65x/evm.c
@@ -8,10 +8,31 @@
*/
#include <common.h>
+#include <dm.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/hardware.h>
+#include <asm/gpio.h>
#include <asm/io.h>
+#include <asm/omap_common.h>
#include <spl.h>
#include <asm/arch/sys_proto.h>
+#include "../common/board_detect.h"
+
+#define board_is_am65x_base_board() board_ti_is("AM6-COMPROCEVM")
+
+/* Daughter card presence detection signals */
+enum {
+ AM65X_EVM_APP_BRD_DET,
+ AM65X_EVM_LCD_BRD_DET,
+ AM65X_EVM_SERDES_BRD_DET,
+ AM65X_EVM_HDMI_GPMC_BRD_DET,
+ AM65X_EVM_BRD_DET_COUNT,
+};
+
+/* Max number of MAC addresses that are parsed/processed per daughter card */
+#define DAUGHTER_CARD_NO_OF_MAC_ADDR 8
+
DECLARE_GLOBAL_DATA_PTR;
int board_init(void)
@@ -80,3 +101,223 @@
return ret;
}
#endif
+
+int do_board_detect(void)
+{
+ int ret;
+
+ ret = ti_i2c_eeprom_am6_get_base(CONFIG_EEPROM_BUS_ADDRESS,
+ CONFIG_EEPROM_CHIP_ADDRESS);
+ if (ret)
+ pr_err("Reading on-board EEPROM at 0x%02x failed %d\n",
+ CONFIG_EEPROM_CHIP_ADDRESS, ret);
+
+ return ret;
+}
+
+static void setup_board_eeprom_env(void)
+{
+ char *name = "am65x";
+
+ if (do_board_detect())
+ goto invalid_eeprom;
+
+ if (board_is_am65x_base_board())
+ name = "am65x";
+ else
+ printf("Unidentified board claims %s in eeprom header\n",
+ board_ti_get_name());
+
+invalid_eeprom:
+ set_board_info_env_am6(name);
+}
+
+static int init_daughtercard_det_gpio(char *gpio_name, struct gpio_desc *desc)
+{
+ int ret;
+
+ memset(desc, 0, sizeof(*desc));
+
+ ret = dm_gpio_lookup_name(gpio_name, desc);
+ if (ret < 0)
+ return ret;
+
+ /* Request GPIO, simply re-using the name as label */
+ ret = dm_gpio_request(desc, gpio_name);
+ if (ret < 0)
+ return ret;
+
+ return dm_gpio_set_dir_flags(desc, GPIOD_IS_IN);
+}
+
+static int probe_daughtercards(void)
+{
+ struct ti_am6_eeprom ep;
+ struct gpio_desc board_det_gpios[AM65X_EVM_BRD_DET_COUNT];
+ char mac_addr[DAUGHTER_CARD_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
+ u8 mac_addr_cnt;
+ char name_overlays[1024] = { 0 };
+ int i, j;
+ int ret;
+
+ /*
+ * Daughter card presence detection signal name to GPIO (via I2C I/O
+ * expander @ address 0x38) name and EEPROM I2C address mapping.
+ */
+ const struct {
+ char *gpio_name;
+ u8 i2c_addr;
+ } slot_map[AM65X_EVM_BRD_DET_COUNT] = {
+ { "gpio@38_0", 0x52, }, /* AM65X_EVM_APP_BRD_DET */
+ { "gpio@38_1", 0x55, }, /* AM65X_EVM_LCD_BRD_DET */
+ { "gpio@38_2", 0x54, }, /* AM65X_EVM_SERDES_BRD_DET */
+ { "gpio@38_3", 0x53, }, /* AM65X_EVM_HDMI_GPMC_BRD_DET */
+ };
+
+ /* Declaration of daughtercards to probe */
+ const struct {
+ u8 slot_index; /* Slot the card is installed */
+ char *card_name; /* EEPROM-programmed card name */
+ char *dtbo_name; /* Device tree overlay to apply */
+ u8 eth_offset; /* ethXaddr MAC address index offset */
+ } cards[] = {
+ {
+ AM65X_EVM_APP_BRD_DET,
+ "AM6-GPAPPEVM",
+ "k3-am654-gp.dtbo",
+ 0,
+ },
+ {
+ AM65X_EVM_APP_BRD_DET,
+ "AM6-IDKAPPEVM",
+ "k3-am654-idk.dtbo",
+ 3,
+ },
+ {
+ AM65X_EVM_SERDES_BRD_DET,
+ "SER-PCIE2LEVM",
+ "k3-am654-pcie-usb2.dtbo",
+ 0,
+ },
+ {
+ AM65X_EVM_SERDES_BRD_DET,
+ "SER-PCIEUSBEVM",
+ "k3-am654-pcie-usb3.dtbo",
+ 0,
+ },
+ {
+ AM65X_EVM_LCD_BRD_DET,
+ "OLDI-LCD1EVM",
+ "k3-am654-evm-oldi-lcd1evm.dtbo",
+ 0,
+ },
+ };
+
+ /*
+ * Initialize GPIO used for daughtercard slot presence detection and
+ * keep the resulting handles in local array for easier access.
+ */
+ for (i = 0; i < AM65X_EVM_BRD_DET_COUNT; i++) {
+ ret = init_daughtercard_det_gpio(slot_map[i].gpio_name,
+ &board_det_gpios[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cards); i++) {
+ /* Obtain card-specific slot index and associated I2C address */
+ u8 slot_index = cards[i].slot_index;
+ u8 i2c_addr = slot_map[slot_index].i2c_addr;
+
+ /*
+ * The presence detection signal is active-low, hence skip
+ * over this card slot if anything other than 0 is returned.
+ */
+ ret = dm_gpio_get_value(&board_det_gpios[slot_index]);
+ if (ret < 0)
+ return ret;
+ else if (ret)
+ continue;
+
+ /* Get and parse the daughter card EEPROM record */
+ ret = ti_i2c_eeprom_am6_get(CONFIG_EEPROM_BUS_ADDRESS, i2c_addr,
+ &ep,
+ (char **)mac_addr,
+ DAUGHTER_CARD_NO_OF_MAC_ADDR,
+ &mac_addr_cnt);
+ if (ret) {
+ pr_err("Reading daughtercard EEPROM at 0x%02x failed %d\n",
+ i2c_addr, ret);
+ /*
+ * Even this is pretty serious let's just skip over
+ * this particular daughtercard, rather than ending
+ * the probing process altogether.
+ */
+ continue;
+ }
+
+ /* Only process the parsed data if we found a match */
+ if (strncmp(ep.name, cards[i].card_name, sizeof(ep.name)))
+ continue;
+
+ printf("detected %s\n", cards[i].card_name);
+
+ /*
+ * Populate any MAC addresses from daughtercard into the U-Boot
+ * environment, starting with a card-specific offset so we can
+ * have multiple cards contribute to the MAC pool in a well-
+ * defined manner.
+ */
+ for (j = 0; j < mac_addr_cnt; j++) {
+ if (!is_valid_ethaddr((u8 *)mac_addr[j]))
+ continue;
+
+ eth_env_set_enetaddr_by_index("eth",
+ cards[i].eth_offset + j,
+ (uchar *)mac_addr[j]);
+ }
+
+ /* Skip if no overlays are to be added */
+ if (!strlen(cards[i].dtbo_name))
+ continue;
+
+ /*
+ * Make sure we are not running out of buffer space by checking
+ * if we can fit the new overlay, a trailing space to be used
+ * as a separator, plus the terminating zero.
+ */
+ if (strlen(name_overlays) + strlen(cards[i].dtbo_name) + 2 >
+ sizeof(name_overlays))
+ return -ENOMEM;
+
+ /* Append to our list of overlays */
+ strcat(name_overlays, cards[i].dtbo_name);
+ strcat(name_overlays, " ");
+ }
+
+ /* Apply device tree overlay(s) to the U-Boot environment, if any */
+ if (strlen(name_overlays))
+ return env_set("name_overlays", name_overlays);
+
+ return 0;
+}
+
+int board_late_init(void)
+{
+ struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
+
+ setup_board_eeprom_env();
+
+ /*
+ * The first MAC address for ethernet a.k.a. ethernet0 comes from
+ * efuse populated via the am654 gigabit eth switch subsystem driver.
+ * All the other ones are populated via EEPROM, hence continue with
+ * an index of 1.
+ */
+ board_ti_am6_set_ethaddr(1, ep->mac_addr_cnt);
+
+ /* Check for and probe any plugged-in daughtercards */
+ probe_daughtercards();
+
+ return 0;
+}
diff --git a/board/ti/common/board_detect.c b/board/ti/common/board_detect.c
index e258e22..32fa105 100644
--- a/board/ti/common/board_detect.c
+++ b/board/ti/common/board_detect.c
@@ -8,6 +8,7 @@
*/
#include <common.h>
+#include <asm/arch/hardware.h>
#include <asm/omap_common.h>
#include <dm/uclass.h>
#include <i2c.h>
@@ -284,6 +285,191 @@
return 0;
}
+static int ti_i2c_eeprom_am6_parse_record(struct ti_am6_eeprom_record *record,
+ struct ti_am6_eeprom *ep,
+ char **mac_addr,
+ u8 mac_addr_max_cnt,
+ u8 *mac_addr_cnt)
+{
+ switch (record->header.id) {
+ case TI_AM6_EEPROM_RECORD_BOARD_INFO:
+ if (record->header.len != sizeof(record->data.board_info))
+ return -EINVAL;
+
+ if (!ep)
+ break;
+
+ /* Populate (and clean, if needed) the board name */
+ strlcpy(ep->name, record->data.board_info.name,
+ sizeof(ep->name));
+ ti_eeprom_string_cleanup(ep->name);
+
+ /* Populate selected other fields from the board info record */
+ strlcpy(ep->version, record->data.board_info.version,
+ sizeof(ep->version));
+ strlcpy(ep->software_revision,
+ record->data.board_info.software_revision,
+ sizeof(ep->software_revision));
+ strlcpy(ep->serial, record->data.board_info.serial,
+ sizeof(ep->serial));
+ break;
+ case TI_AM6_EEPROM_RECORD_MAC_INFO:
+ if (record->header.len != sizeof(record->data.mac_info))
+ return -EINVAL;
+
+ if (!mac_addr || !mac_addr_max_cnt)
+ break;
+
+ *mac_addr_cnt = ((record->data.mac_info.mac_control &
+ TI_AM6_EEPROM_MAC_ADDR_COUNT_MASK) >>
+ TI_AM6_EEPROM_MAC_ADDR_COUNT_SHIFT) + 1;
+
+ /*
+ * The EEPROM can (but may not) hold a very large amount
+ * of MAC addresses, by far exceeding what we want/can store
+ * in the common memory array, so only grab what we can fit.
+ * Note that a value of 0 means 1 MAC address, and so on.
+ */
+ *mac_addr_cnt = min(*mac_addr_cnt, mac_addr_max_cnt);
+
+ memcpy(mac_addr, record->data.mac_info.mac_addr,
+ *mac_addr_cnt * TI_EEPROM_HDR_ETH_ALEN);
+ break;
+ case 0x00:
+ /* Illegal value... Fall through... */
+ case 0xFF:
+ /* Illegal value... Something went horribly wrong... */
+ return -EINVAL;
+ default:
+ pr_warn("%s: Ignoring record id %u\n", __func__,
+ record->header.id);
+ }
+
+ return 0;
+}
+
+int __maybe_unused ti_i2c_eeprom_am6_get(int bus_addr, int dev_addr,
+ struct ti_am6_eeprom *ep,
+ char **mac_addr,
+ u8 mac_addr_max_cnt,
+ u8 *mac_addr_cnt)
+{
+ struct udevice *dev;
+ struct udevice *bus;
+ unsigned int eeprom_addr;
+ struct ti_am6_eeprom_record_board_id board_id;
+ struct ti_am6_eeprom_record record;
+ int rc;
+
+ /* Initialize with a known bad marker for i2c fails.. */
+ memset(ep, 0, sizeof(*ep));
+ ep->header = TI_DEAD_EEPROM_MAGIC;
+
+ /* Read the board ID record which is always the first EEPROM record */
+ rc = ti_i2c_eeprom_get(bus_addr, dev_addr, TI_EEPROM_HEADER_MAGIC,
+ sizeof(board_id), (uint8_t *)&board_id);
+ if (rc)
+ return rc;
+
+ if (board_id.header.id != TI_AM6_EEPROM_RECORD_BOARD_ID) {
+ pr_err("%s: Invalid board ID record!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Establish DM handle to board config EEPROM */
+ rc = uclass_get_device_by_seq(UCLASS_I2C, bus_addr, &bus);
+ if (rc)
+ return rc;
+ rc = i2c_get_chip(bus, dev_addr, 1, &dev);
+ if (rc)
+ return rc;
+
+ ep->header = TI_EEPROM_HEADER_MAGIC;
+
+ /* Ready to parse TLV structure. Initialize variables... */
+ *mac_addr_cnt = 0;
+
+ /*
+ * After the all-encompassing board ID record all other records follow
+ * a TLV-type scheme. Point to the first such record and then start
+ * parsing those one by one.
+ */
+ eeprom_addr = sizeof(board_id);
+
+ while (true) {
+ rc = dm_i2c_read(dev, eeprom_addr, (uint8_t *)&record.header,
+ sizeof(record.header));
+ if (rc)
+ return rc;
+
+ /*
+ * Check for end of list marker. If we reached it don't go
+ * any further and stop parsing right here.
+ */
+ if (record.header.id == TI_AM6_EEPROM_RECORD_END_LIST)
+ break;
+
+ eeprom_addr += sizeof(record.header);
+
+ debug("%s: dev_addr=0x%02x header.id=%u header.len=%u\n",
+ __func__, dev_addr, record.header.id,
+ record.header.len);
+
+ /* Read record into memory if it fits */
+ if (record.header.len <= sizeof(record.data)) {
+ rc = dm_i2c_read(dev, eeprom_addr,
+ (uint8_t *)&record.data,
+ record.header.len);
+ if (rc)
+ return rc;
+
+ /* Process record */
+ rc = ti_i2c_eeprom_am6_parse_record(&record, ep,
+ mac_addr,
+ mac_addr_max_cnt,
+ mac_addr_cnt);
+ if (rc) {
+ pr_err("%s: EEPROM parsing error!\n", __func__);
+ return rc;
+ }
+ } else {
+ /*
+ * We may get here in case of larger records which
+ * are not yet understood.
+ */
+ pr_err("%s: Ignoring record id %u\n", __func__,
+ record.header.id);
+ }
+
+ eeprom_addr += record.header.len;
+ }
+
+ return 0;
+}
+
+int __maybe_unused ti_i2c_eeprom_am6_get_base(int bus_addr, int dev_addr)
+{
+ struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
+ int ret;
+
+ /*
+ * Always execute EEPROM read by not allowing to bypass it during the
+ * first invocation of SPL which happens on the R5 core.
+ */
+#if !(defined(CONFIG_SPL_BUILD) && defined(CONFIG_CPU_V7R))
+ if (ep->header == TI_EEPROM_HEADER_MAGIC) {
+ debug("%s: EEPROM has already been read\n", __func__);
+ return 0;
+ }
+#endif
+
+ ret = ti_i2c_eeprom_am6_get(bus_addr, dev_addr, ep,
+ (char **)ep->mac_addr,
+ AM6_EEPROM_HDR_NO_OF_MAC_ADDR,
+ &ep->mac_addr_cnt);
+ return ret;
+}
+
bool __maybe_unused board_ti_is(char *name_tag)
{
struct ti_common_eeprom *ep = TI_EEPROM_DATA;
@@ -348,6 +534,25 @@
memset(mac_addr, 0, TI_EEPROM_HDR_ETH_ALEN);
}
+void __maybe_unused
+board_ti_am6_get_eth_mac_addr(int index,
+ u8 mac_addr[TI_EEPROM_HDR_ETH_ALEN])
+{
+ struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
+
+ if (ep->header == TI_DEAD_EEPROM_MAGIC)
+ goto fail;
+
+ if (index < 0 || index >= ep->mac_addr_cnt)
+ goto fail;
+
+ memcpy(mac_addr, ep->mac_addr[index], TI_EEPROM_HDR_ETH_ALEN);
+ return;
+
+fail:
+ memset(mac_addr, 0, TI_EEPROM_HDR_ETH_ALEN);
+}
+
u64 __maybe_unused board_ti_get_emif1_size(void)
{
struct ti_common_eeprom *ep = TI_EEPROM_DATA;
@@ -385,6 +590,34 @@
else
env_set("board_rev", unknown);
+ if (ep->serial)
+ env_set("board_serial", ep->serial);
+ else
+ env_set("board_serial", unknown);
+}
+
+void __maybe_unused set_board_info_env_am6(char *name)
+{
+ char *unknown = "unknown";
+ struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
+
+ if (name)
+ env_set("board_name", name);
+ else if (ep->name)
+ env_set("board_name", ep->name);
+ else
+ env_set("board_name", unknown);
+
+ if (ep->version)
+ env_set("board_rev", ep->version);
+ else
+ env_set("board_rev", unknown);
+
+ if (ep->software_revision)
+ env_set("board_software_revision", ep->software_revision);
+ else
+ env_set("board_software_revision", unknown);
+
if (ep->serial)
env_set("board_serial", ep->serial);
else
@@ -453,6 +686,19 @@
}
}
+void board_ti_am6_set_ethaddr(int index, int count)
+{
+ u8 mac_addr[6];
+ int i;
+
+ for (i = 0; i < count; i++) {
+ board_ti_am6_get_eth_mac_addr(i, mac_addr);
+ if (is_valid_ethaddr(mac_addr))
+ eth_env_set_enetaddr_by_index("eth", i + index,
+ mac_addr);
+ }
+}
+
bool __maybe_unused board_ti_was_eeprom_read(void)
{
struct ti_common_eeprom *ep = TI_EEPROM_DATA;
diff --git a/board/ti/common/board_detect.h b/board/ti/common/board_detect.h
index f8495a7..a45d896 100644
--- a/board/ti/common/board_detect.h
+++ b/board/ti/common/board_detect.h
@@ -43,6 +43,133 @@
char mac_addr[TI_EEPROM_HDR_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
} __attribute__ ((__packed__));
+/* AM6x TI EVM EEPROM Definitions */
+#define TI_AM6_EEPROM_RECORD_BOARD_ID 0x01
+#define TI_AM6_EEPROM_RECORD_BOARD_INFO 0x10
+#define TI_AM6_EEPROM_RECORD_DDR_INFO 0x11
+#define TI_AM6_EEPROM_RECORD_DDR_SPD 0x12
+#define TI_AM6_EEPROM_RECORD_MAC_INFO 0x13
+#define TI_AM6_EEPROM_RECORD_END_LIST 0xFE
+
+/*
+ * Common header for AM6x TI EVM EEPROM records. Used to encapsulate the config
+ * EEPROM in its entirety as well as for individual records contained within.
+ */
+struct ti_am6_eeprom_record_header {
+ u8 id;
+ u16 len;
+} __attribute__ ((__packed__));
+
+/* AM6x TI EVM EEPROM board ID structure */
+struct ti_am6_eeprom_record_board_id {
+ u32 magic_number;
+ struct ti_am6_eeprom_record_header header;
+} __attribute__ ((__packed__));
+
+/* AM6x TI EVM EEPROM board info structure */
+#define AM6_EEPROM_HDR_NAME_LEN 16
+#define AM6_EEPROM_HDR_VERSION_LEN 2
+#define AM6_EEPROM_HDR_PROC_NR_LEN 4
+#define AM6_EEPROM_HDR_VARIANT_LEN 2
+#define AM6_EEPROM_HDR_PCB_REV_LEN 2
+#define AM6_EEPROM_HDR_SCH_BOM_REV_LEN 2
+#define AM6_EEPROM_HDR_SW_REV_LEN 2
+#define AM6_EEPROM_HDR_VID_LEN 2
+#define AM6_EEPROM_HDR_BLD_WK_LEN 2
+#define AM6_EEPROM_HDR_BLD_YR_LEN 2
+#define AM6_EEPROM_HDR_4P_NR_LEN 6
+#define AM6_EEPROM_HDR_SERIAL_LEN 4
+
+struct ti_am6_eeprom_record_board_info {
+ char name[AM6_EEPROM_HDR_NAME_LEN];
+ char version[AM6_EEPROM_HDR_VERSION_LEN];
+ char proc_number[AM6_EEPROM_HDR_PROC_NR_LEN];
+ char variant[AM6_EEPROM_HDR_VARIANT_LEN];
+ char pcb_revision[AM6_EEPROM_HDR_PCB_REV_LEN];
+ char schematic_bom_revision[AM6_EEPROM_HDR_SCH_BOM_REV_LEN];
+ char software_revision[AM6_EEPROM_HDR_SW_REV_LEN];
+ char vendor_id[AM6_EEPROM_HDR_VID_LEN];
+ char build_week[AM6_EEPROM_HDR_BLD_WK_LEN];
+ char build_year[AM6_EEPROM_HDR_BLD_YR_LEN];
+ char board_4p_number[AM6_EEPROM_HDR_4P_NR_LEN];
+ char serial[AM6_EEPROM_HDR_SERIAL_LEN];
+} __attribute__ ((__packed__));
+
+/* Memory location to keep a copy of the AM6 board info record */
+#define TI_AM6_EEPROM_BD_INFO_DATA ((struct ti_am6_eeprom_record_board_info *) \
+ TI_SRAM_SCRATCH_BOARD_EEPROM_START)
+
+/* AM6x TI EVM EEPROM DDR info structure */
+#define TI_AM6_EEPROM_DDR_CTRL_INSTANCE_MASK GENMASK(1, 0)
+#define TI_AM6_EEPROM_DDR_CTRL_INSTANCE_SHIFT 0
+#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_MASK GENMASK(3, 2)
+#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_NA (0 << 2)
+#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_BOARDID (2 << 2)
+#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_I2C51 (3 << 2)
+#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_MASK GENMASK(5, 4)
+#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_DDR3 (0 << 4)
+#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_DDR4 (1 << 4)
+#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_LPDDR4 (2 << 4)
+#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_MASK GENMASK(7, 6)
+#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_16 (0 << 6)
+#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_32 (1 << 6)
+#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_64 (2 << 6)
+#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_MASK GENMASK(9, 8)
+#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_8 (0 << 8)
+#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_16 (1 << 8)
+#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_32 (2 << 8)
+#define TI_AM6_EEPROM_DDR_CTRL_RANKS_2 BIT(10)
+#define TI_AM6_EEPROM_DDR_CTRL_DENS_MASK GENMASK(13, 11)
+#define TI_AM6_EEPROM_DDR_CTRL_DENS_1GB (0 << 11)
+#define TI_AM6_EEPROM_DDR_CTRL_DENS_2GB (1 << 11)
+#define TI_AM6_EEPROM_DDR_CTRL_DENS_4GB (2 << 11)
+#define TI_AM6_EEPROM_DDR_CTRL_DENS_8GB (3 << 11)
+#define TI_AM6_EEPROM_DDR_CTRL_DENS_12GB (4 << 11)
+#define TI_AM6_EEPROM_DDR_CTRL_DENS_16GB (5 << 11)
+#define TI_AM6_EEPROM_DDR_CTRL_DENS_24GB (6 << 11)
+#define TI_AM6_EEPROM_DDR_CTRL_DENS_32GB (7 << 11)
+#define TI_AM6_EEPROM_DDR_CTRL_ECC BIT(14)
+
+struct ti_am6_eeprom_record_ddr_info {
+ u16 ddr_control;
+} __attribute__ ((__packed__));
+
+/* AM6x TI EVM EEPROM DDR SPD structure */
+#define TI_AM6_EEPROM_DDR_SPD_INSTANCE_MASK GENMASK(1, 0)
+#define TI_AM6_EEPROM_DDR_SPD_INSTANCE_SHIFT 0
+#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_MASK GENMASK(4, 3)
+#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_DDR3 (0 << 3)
+#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_DDR4 (1 << 3)
+#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_LPDDR4 (2 << 3)
+#define TI_AM6_EEPROM_DDR_SPD_DATA_LEN 512
+
+struct ti_am6_eeprom_record_ddr_spd {
+ u16 spd_control;
+ u8 data[TI_AM6_EEPROM_DDR_SPD_DATA_LEN];
+} __attribute__ ((__packed__));
+
+/* AM6x TI EVM EEPROM MAC info structure */
+#define TI_AM6_EEPROM_MAC_INFO_INSTANCE_MASK GENMASK(2, 0)
+#define TI_AM6_EEPROM_MAC_INFO_INSTANCE_SHIFT 0
+#define TI_AM6_EEPROM_MAC_ADDR_COUNT_MASK GENMASK(7, 3)
+#define TI_AM6_EEPROM_MAC_ADDR_COUNT_SHIFT 3
+#define TI_AM6_EEPROM_MAC_ADDR_MAX_COUNT 32
+
+struct ti_am6_eeprom_record_mac_info {
+ u16 mac_control;
+ u8 mac_addr[TI_AM6_EEPROM_MAC_ADDR_MAX_COUNT][TI_EEPROM_HDR_ETH_ALEN];
+} __attribute__ ((__packed__));
+
+struct ti_am6_eeprom_record {
+ struct ti_am6_eeprom_record_header header;
+ union {
+ struct ti_am6_eeprom_record_board_info board_info;
+ struct ti_am6_eeprom_record_ddr_info ddr_info;
+ struct ti_am6_eeprom_record_ddr_spd ddr_spd;
+ struct ti_am6_eeprom_record_mac_info mac_info;
+ } data;
+} __attribute__ ((__packed__));
+
/* DRA7 EEPROM MAGIC Header identifier */
#define DRA7_EEPROM_HEADER_MAGIC 0xAA5533EE
#define DRA7_EEPROM_HDR_NAME_LEN 16
@@ -99,7 +226,38 @@
#define TI_EEPROM_DATA ((struct ti_common_eeprom *)\
TI_SRAM_SCRATCH_BOARD_EEPROM_START)
+/*
+ * Maximum number of Ethernet MAC addresses extracted from the AM6x on-board
+ * EEPROM during the initial probe and carried forward in SRAM.
+ */
+#define AM6_EEPROM_HDR_NO_OF_MAC_ADDR 8
+
/**
+ * struct ti_am6_eeprom - Null terminated, usable EEPROM contents, as extracted
+ * from the AM6 on-board EEPROM. Note that we only carry a subset of data
+ * at this time to be considerate about memory consumption.
+ * @header: Magic number for data validity indication
+ * @name: NULL terminated name
+ * @version: NULL terminated version
+ * @software_revision: NULL terminated software revision
+ * @serial: Board serial number
+ * @mac_addr_cnt: Number of MAC addresses stored in this object
+ * @mac_addr: MAC addresses
+ */
+struct ti_am6_eeprom {
+ u32 header;
+ char name[AM6_EEPROM_HDR_NAME_LEN + 1];
+ char version[AM6_EEPROM_HDR_VERSION_LEN + 1];
+ char software_revision[AM6_EEPROM_HDR_SW_REV_LEN + 1];
+ char serial[AM6_EEPROM_HDR_SERIAL_LEN + 1];
+ u8 mac_addr_cnt;
+ char mac_addr[AM6_EEPROM_HDR_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
+};
+
+#define TI_AM6_EEPROM_DATA ((struct ti_am6_eeprom *) \
+ TI_SRAM_SCRATCH_BOARD_EEPROM_START)
+
+/**
* ti_i2c_eeprom_am_get() - Consolidated eeprom data collection for AM* TI EVMs
* @bus_addr: I2C bus address
* @dev_addr: I2C slave address
@@ -117,6 +275,33 @@
int ti_i2c_eeprom_dra7_get(int bus_addr, int dev_addr);
/**
+ * ti_i2c_eeprom_am6_get() - Consolidated eeprom data for AM6x TI EVMs and
+ * associated daughter cards, parsed into user-
+ * provided data structures
+ * @bus_addr: I2C bus address
+ * @dev_addr: I2C slave address
+ * @ep: Pointer to structure receiving AM6-specific header data
+ * @mac_addr: Pointer to memory receiving parsed MAC addresses. May be
+ * NULL to skip MAC parsing.
+ * @mac_addr_max_cnt: Maximum number of MAC addresses that can be stored into
+ * mac_addr. May be NULL to skip MAC parsing.
+ * @mac_addr_cnt: Pointer to a location returning how many MAC addressed got
+ * actually parsed.
+ */
+int __maybe_unused ti_i2c_eeprom_am6_get(int bus_addr, int dev_addr,
+ struct ti_am6_eeprom *ep,
+ char **mac_addr,
+ u8 mac_addr_max_cnt,
+ u8 *mac_addr_cnt);
+
+/**
+ * ti_i2c_eeprom_am6_get_base() - Consolidated eeprom data for AM6x TI EVMs
+ * @bus_addr: I2C bus address
+ * @dev_addr: I2C slave address
+ */
+int __maybe_unused ti_i2c_eeprom_am6_get_base(int bus_addr, int dev_addr);
+
+/**
* board_ti_is() - Board detection logic for TI EVMs
* @name_tag: Tag used in eeprom for the board
*
@@ -193,6 +378,15 @@
void set_board_info_env(char *name);
/**
+ * set_board_info_env_am6() - Setup commonly used board information environment
+ * vars for AM6-type boards
+ * @name: Name of the board
+ *
+ * If name is NULL, default_name is used.
+ */
+void set_board_info_env_am6(char *name);
+
+/**
* board_ti_set_ethaddr- Sets the ethaddr environment from EEPROM
* @index: The first eth<index>addr environment variable to set
*
@@ -205,6 +399,18 @@
void board_ti_set_ethaddr(int index);
/**
+ * board_ti_am6_set_ethaddr- Sets the ethaddr environment from EEPROM
+ * @index: The first eth<index>addr environment variable to set
+ * @count: The number of MAC addresses to process
+ *
+ * EEPROM should be already read before calling this function. The EEPROM
+ * contains n dedicated MAC addresses. This function sets the ethaddr
+ * environment variable for all the available MAC addresses starting
+ * from eth<index>addr.
+ */
+void board_ti_am6_set_ethaddr(int index, int count);
+
+/**
* board_ti_was_eeprom_read() - Check to see if the eeprom contents have been read
*
* This function is useful to determine if the eeprom has already been read and
diff --git a/board/ti/ti816x/evm.c b/board/ti/ti816x/evm.c
index 07a084b..240df8c 100644
--- a/board/ti/ti816x/evm.c
+++ b/board/ti/ti816x/evm.c
@@ -9,7 +9,6 @@
#include <common.h>
#include <environment.h>
#include <spl.h>
-#include <netdev.h>
#include <asm/cache.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
@@ -56,7 +55,7 @@
printf("Unable to read MAC address. Set <ethaddr>\n");
}
- return davinci_emac_initialize();
+ return 0;
}
#ifdef CONFIG_SPL_BUILD
diff --git a/board/vamrs/rock960_rk3399/MAINTAINERS b/board/vamrs/rock960_rk3399/MAINTAINERS
index 22b2db9..5ee5256 100644
--- a/board/vamrs/rock960_rk3399/MAINTAINERS
+++ b/board/vamrs/rock960_rk3399/MAINTAINERS
@@ -1,11 +1,11 @@
ROCK960-RK3399
-M: Manivannan Sadhasivam manivannan.sadhasivam@linaro.org
+M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
S: Maintained
F: board/rockchip/rock960_rk3399
F: include/configs/rock960_rk3399.h
F: configs/rock960-rk3399_defconfig
FICUS EE
-M: Manivannan Sadhasivam manivannan.sadhasivam@linaro.org
+M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
S: Maintained
F: configs/ficus-rk3399_defconfig
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 67284d8..9e66cc1 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -408,6 +408,14 @@
Save all environment variables into the compiled-in persistent
storage.
+config CMD_ERASEENV
+ bool "eraseenv"
+ default n
+ depends on CMD_SAVEENV
+ help
+ Erase environment variables from the compiled-in persistent
+ storage.
+
config CMD_ENV_EXISTS
bool "env exists"
default y
@@ -563,6 +571,13 @@
base - print or set address offset
loop - initialize loop on address range
+config CMD_RANDOM
+ bool "random"
+ default y
+ depends on CMD_MEMORY && (LIB_RAND || LIB_HW_RAND)
+ help
+ random - fill memory with random data
+
config CMD_MEMTEST
bool "memtest"
help
@@ -720,7 +735,7 @@
Android devices. Fastboot requires either the network stack
enabled or support for acting as a USB device.
- See doc/README.android-fastboot for more information.
+ See doc/android/fastboot.txt for more information.
config CMD_FDC
bool "fdcboot - Boot from floppy device"
@@ -1183,6 +1198,21 @@
endmenu
+menu "Android support commands"
+
+config CMD_AB_SELECT
+ bool "ab_select"
+ default n
+ depends on ANDROID_AB
+ help
+ On Android devices with more than one boot slot (multiple copies of
+ the kernel and system images) this provides a command to select which
+ slot should be used to boot from and register the boot attempt. This
+ is used by the new A/B update model where one slot is updated in the
+ background while running from the other slot.
+
+endmenu
+
if NET
menuconfig CMD_NET
diff --git a/cmd/Makefile b/cmd/Makefile
index 0aa3741..43a6b0e 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -12,6 +12,7 @@
# command
obj-$(CONFIG_CMD_AES) += aes.o
+obj-$(CONFIG_CMD_AB_SELECT) += ab_select.o
obj-$(CONFIG_CMD_ADC) += adc.o
obj-$(CONFIG_CMD_ARMFLASH) += armflash.o
obj-y += blk_common.o
diff --git a/cmd/ab_select.c b/cmd/ab_select.c
new file mode 100644
index 0000000..7c8f2ee
--- /dev/null
+++ b/cmd/ab_select.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ */
+
+#include <android_ab.h>
+#include <command.h>
+
+static int do_ab_select(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ int ret;
+ struct blk_desc *dev_desc;
+ disk_partition_t part_info;
+ char slot[2];
+
+ if (argc != 4)
+ return CMD_RET_USAGE;
+
+ /* Lookup the "misc" partition from argv[2] and argv[3] */
+ if (part_get_info_by_dev_and_name_or_num(argv[2], argv[3],
+ &dev_desc, &part_info) < 0) {
+ return CMD_RET_FAILURE;
+ }
+
+ ret = ab_select_slot(dev_desc, &part_info);
+ if (ret < 0) {
+ printf("Android boot failed, error %d.\n", ret);
+ return CMD_RET_FAILURE;
+ }
+
+ /* Android standard slot names are 'a', 'b', ... */
+ slot[0] = BOOT_SLOT_NAME(ret);
+ slot[1] = '\0';
+ env_set(argv[1], slot);
+ printf("ANDROID: Booting slot: %s\n", slot);
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(ab_select, 4, 0, do_ab_select,
+ "Select the slot used to boot from and register the boot attempt.",
+ "<slot_var_name> <interface> <dev[:part|#part_name]>\n"
+ " - Load the slot metadata from the partition 'part' on\n"
+ " device type 'interface' instance 'dev' and store the active\n"
+ " slot in the 'slot_var_name' variable. This also updates the\n"
+ " Android slot metadata with a boot attempt, which can cause\n"
+ " successive calls to this function to return a different result\n"
+ " if the returned slot runs out of boot attempts.\n"
+ " - If 'part_name' is passed, preceded with a # instead of :, the\n"
+ " partition name whose label is 'part_name' will be looked up in\n"
+ " the partition table. This is commonly the \"misc\" partition.\n"
+);
diff --git a/cmd/bcb.c b/cmd/bcb.c
index 2bd5a74..9626f2c 100644
--- a/cmd/bcb.c
+++ b/cmd/bcb.c
@@ -24,17 +24,17 @@
static int bcb_cmd_get(char *cmd)
{
- if (!strncmp(cmd, "load", sizeof("load")))
+ if (!strcmp(cmd, "load"))
return BCB_CMD_LOAD;
- if (!strncmp(cmd, "set", sizeof("set")))
+ if (!strcmp(cmd, "set"))
return BCB_CMD_FIELD_SET;
- if (!strncmp(cmd, "clear", sizeof("clear")))
+ if (!strcmp(cmd, "clear"))
return BCB_CMD_FIELD_CLEAR;
- if (!strncmp(cmd, "test", sizeof("test")))
+ if (!strcmp(cmd, "test"))
return BCB_CMD_FIELD_TEST;
- if (!strncmp(cmd, "store", sizeof("store")))
+ if (!strcmp(cmd, "store"))
return BCB_CMD_STORE;
- if (!strncmp(cmd, "dump", sizeof("dump")))
+ if (!strcmp(cmd, "dump"))
return BCB_CMD_FIELD_DUMP;
else
return -1;
@@ -46,9 +46,6 @@
switch (cmd) {
case BCB_CMD_LOAD:
- if (argc != 3)
- goto err;
- break;
case BCB_CMD_FIELD_SET:
if (argc != 3)
goto err;
@@ -86,23 +83,23 @@
return -1;
}
-static int bcb_field_get(char *name, char **field, int *size)
+static int bcb_field_get(char *name, char **fieldp, int *sizep)
{
- if (!strncmp(name, "command", sizeof("command"))) {
- *field = bcb.command;
- *size = sizeof(bcb.command);
- } else if (!strncmp(name, "status", sizeof("status"))) {
- *field = bcb.status;
- *size = sizeof(bcb.status);
- } else if (!strncmp(name, "recovery", sizeof("recovery"))) {
- *field = bcb.recovery;
- *size = sizeof(bcb.recovery);
- } else if (!strncmp(name, "stage", sizeof("stage"))) {
- *field = bcb.stage;
- *size = sizeof(bcb.stage);
- } else if (!strncmp(name, "reserved", sizeof("reserved"))) {
- *field = bcb.reserved;
- *size = sizeof(bcb.reserved);
+ if (!strcmp(name, "command")) {
+ *fieldp = bcb.command;
+ *sizep = sizeof(bcb.command);
+ } else if (!strcmp(name, "status")) {
+ *fieldp = bcb.status;
+ *sizep = sizeof(bcb.status);
+ } else if (!strcmp(name, "recovery")) {
+ *fieldp = bcb.recovery;
+ *sizep = sizeof(bcb.recovery);
+ } else if (!strcmp(name, "stage")) {
+ *fieldp = bcb.stage;
+ *sizep = sizeof(bcb.stage);
+ } else if (!strcmp(name, "reserved")) {
+ *fieldp = bcb.reserved;
+ *sizep = sizeof(bcb.reserved);
} else {
printf("Error: Unknown bcb field '%s'\n", name);
return -1;
@@ -111,8 +108,8 @@
return 0;
}
-static int
-do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
{
struct blk_desc *desc;
disk_partition_t info;
@@ -122,28 +119,28 @@
ret = blk_get_device_by_str("mmc", argv[1], &desc);
if (ret < 0)
- goto err_1;
+ goto err_read_fail;
part = simple_strtoul(argv[2], &endp, 0);
if (*endp == '\0') {
ret = part_get_info(desc, part, &info);
if (ret)
- goto err_1;
+ goto err_read_fail;
} else {
part = part_get_info_by_name(desc, argv[2], &info);
if (part < 0) {
ret = part;
- goto err_1;
+ goto err_read_fail;
}
}
cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), info.blksz);
if (cnt > info.size)
- goto err_2;
+ goto err_too_small;
if (blk_dread(desc, info.start, cnt, &bcb) != cnt) {
ret = -EIO;
- goto err_1;
+ goto err_read_fail;
}
bcb_dev = desc->devnum;
@@ -151,10 +148,10 @@
debug("%s: Loaded from mmc %d:%d\n", __func__, bcb_dev, bcb_part);
return CMD_RET_SUCCESS;
-err_1:
+err_read_fail:
printf("Error: mmc %s:%s read failed (%d)\n", argv[1], argv[2], ret);
goto err;
-err_2:
+err_too_small:
printf("Error: mmc %s:%s too small!", argv[1], argv[2]);
goto err;
err:
@@ -307,7 +304,8 @@
return CMD_RET_USAGE;
if (bcb_is_misused(argc, argv)) {
- /* We try to improve the user experience by reporting the
+ /*
+ * We try to improve the user experience by reporting the
* root-cause of misusage, so don't return CMD_RET_USAGE,
* since the latter prints out the full-blown help text
*/
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index c19256e..a45bfd1 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -24,7 +24,7 @@
static struct efi_device_path *bootefi_image_path;
static struct efi_device_path *bootefi_device_path;
-/*
+/**
* Set the load options of an image from an environment variable.
*
* @handle: the image handle
@@ -143,7 +143,7 @@
return ret;
}
-/*
+/**
* efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
*
* The mem_rsv entries of the FDT are added to the memory map. Any failures are
@@ -169,8 +169,8 @@
pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK));
addr &= ~EFI_PAGE_MASK;
- if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
- false))
+ if (efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
+ false) != EFI_SUCCESS)
printf("FDT memrsv map %d: Failed to add to map\n", i);
}
}
@@ -342,7 +342,7 @@
return CMD_RET_SUCCESS;
}
-/*
+/**
* do_bootefi_image() - execute EFI binary
*
* Set up memory image for the binary to be loaded, prepare device path, and
@@ -612,6 +612,16 @@
bootefi_help_text
);
+/**
+ * efi_set_bootdev() - set boot device
+ *
+ * This function is called when a file is loaded, e.g. via the 'load' command.
+ * We use the path to this file to inform the UEFI binary about the boot device.
+ *
+ * @dev: device, e.g. "MMC"
+ * @devnr: number of the device, e.g. "1:2"
+ * @path: path to file loaded
+ */
void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
{
struct efi_device_path *device, *image;
diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index cb152b3..02dc491 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -394,6 +394,7 @@
/**
* print_memory_attributes() - print memory map attributes
+ *
* @attributes: Attribute value
*
* Print memory map attributes
@@ -487,9 +488,9 @@
* Return: CMD_RET_SUCCESS on success,
* CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
*
- * Implement efidebug "boot add" sub-command.
- * Create or change UEFI load option.
- * - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
+ * Implement efidebug "boot add" sub-command. Create or change UEFI load option.
+ *
+ * efidebug boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
*/
static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
@@ -587,7 +588,8 @@
*
* Implement efidebug "boot rm" sub-command.
* Delete UEFI load options.
- * - boot rm <id> ...
+ *
+ * efidebug boot rm <id> ...
*/
static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
@@ -890,7 +892,8 @@
*
* Implement efidebug "boot next" sub-command.
* Set BootNext variable.
- * - boot next <id>
+ *
+ * efidebug boot next <id>
*/
static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
@@ -938,7 +941,8 @@
*
* Implement efidebug "boot order" sub-command.
* Show order of UEFI load options, or change it in BootOrder variable.
- * - boot order [<id> ...]
+ *
+ * efidebug boot order [<id> ...]
*/
static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
diff --git a/cmd/mdio.c b/cmd/mdio.c
index a6fa926..add6440 100644
--- a/cmd/mdio.c
+++ b/cmd/mdio.c
@@ -268,6 +268,11 @@
break;
}
+ if (!bus) {
+ puts("No MDIO bus found\n");
+ return CMD_RET_FAILURE;
+ }
+
if (op[0] == 'l') {
mdio_list_devices();
diff --git a/cmd/mem.c b/cmd/mem.c
index 392ed17..c6b8038 100644
--- a/cmd/mem.c
+++ b/cmd/mem.c
@@ -1082,6 +1082,49 @@
#endif
+#ifdef CONFIG_CMD_RANDOM
+static int do_random(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr, len;
+ unsigned long seed; // NOT INITIALIZED ON PURPOSE
+ unsigned int *buf, *start;
+ unsigned char *buf8;
+ unsigned int i;
+
+ if (argc < 3 || argc > 4) {
+ printf("usage: %s <addr> <len> [<seed>]\n", argv[0]);
+ return 0;
+ }
+
+ len = simple_strtoul(argv[2], NULL, 16);
+ addr = simple_strtoul(argv[1], NULL, 16);
+
+ if (argc == 4) {
+ seed = simple_strtoul(argv[3], NULL, 16);
+ if (seed == 0) {
+ printf("The seed cannot be 0. Using 0xDEADBEEF.\n");
+ seed = 0xDEADBEEF;
+ }
+ } else {
+ seed = get_timer(0) ^ rand();
+ }
+
+ srand(seed);
+ start = map_sysmem(addr, len);
+ buf = start;
+ for (i = 0; i < (len / 4); i++)
+ *buf++ = rand();
+
+ buf8 = (unsigned char *)buf;
+ for (i = 0; i < (len % 4); i++)
+ *buf8++ = rand() & 0xFF;
+
+ unmap_sysmem(start);
+ printf("%lu bytes filled with random data\n", len);
+ return 1;
+}
+#endif
+
/**************************************************/
U_BOOT_CMD(
md, 3, 1, do_mem_md,
@@ -1250,3 +1293,12 @@
""
);
#endif
+
+#ifdef CONFIG_CMD_RANDOM
+U_BOOT_CMD(
+ random, 4, 0, do_random,
+ "fill memory with random pattern",
+ "<addr> <len> [<seed>]\n"
+ " - Fill 'len' bytes of memory starting at 'addr' with random data\n"
+);
+#endif
diff --git a/cmd/nvedit.c b/cmd/nvedit.c
index 7e468ab..46b1e60 100644
--- a/cmd/nvedit.c
+++ b/cmd/nvedit.c
@@ -767,6 +767,20 @@
"save environment variables to persistent storage",
""
);
+
+#if defined(CONFIG_CMD_ERASEENV)
+static int do_env_erase(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ return env_erase() ? 1 : 0;
+}
+
+U_BOOT_CMD(
+ eraseenv, 1, 0, do_env_erase,
+ "erase environment variables from persistent storage",
+ ""
+);
+#endif
#endif
#endif /* CONFIG_SPL_BUILD */
@@ -1316,6 +1330,9 @@
#endif
#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE)
U_BOOT_CMD_MKENT(save, 1, 0, do_env_save, "", ""),
+#if defined(CONFIG_CMD_ERASEENV)
+ U_BOOT_CMD_MKENT(erase, 1, 0, do_env_erase, "", ""),
+#endif
#endif
U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 0, do_env_set, "", ""),
#if defined(CONFIG_CMD_ENV_EXISTS)
@@ -1396,6 +1413,9 @@
#endif
#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE)
"env save - save environment\n"
+#if defined(CONFIG_CMD_ERASEENV)
+ "env erase - erase environment\n"
+#endif
#endif
#if defined(CONFIG_CMD_NVEDIT_EFI)
"env set -e name [arg ...] - set UEFI variable; unset if 'arg' not specified\n"
diff --git a/cmd/part.c b/cmd/part.c
index bfb6488..653e13c 100644
--- a/cmd/part.c
+++ b/cmd/part.c
@@ -24,6 +24,7 @@
enum cmd_part_info {
CMD_PART_INFO_START = 0,
CMD_PART_INFO_SIZE,
+ CMD_PART_INFO_NUMBER
};
static int do_part_uuid(int argc, char * const argv[])
@@ -149,6 +150,9 @@
case CMD_PART_INFO_SIZE:
snprintf(buf, sizeof(buf), LBAF, info.size);
break;
+ case CMD_PART_INFO_NUMBER:
+ snprintf(buf, sizeof(buf), "%d", part);
+ break;
default:
printf("** Unknown cmd_part_info value: %d\n", param);
return 1;
@@ -172,6 +176,11 @@
return do_part_info(argc, argv, CMD_PART_INFO_SIZE);
}
+static int do_part_number(int argc, char * const argv[])
+{
+ return do_part_info(argc, argv, CMD_PART_INFO_NUMBER);
+}
+
static int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
if (argc < 2)
@@ -185,6 +194,8 @@
return do_part_start(argc - 2, argv + 2);
else if (!strcmp(argv[1], "size"))
return do_part_size(argc - 2, argv + 2);
+ else if (!strcmp(argv[1], "number"))
+ return do_part_number(argc - 2, argv + 2);
return CMD_RET_USAGE;
}
@@ -206,5 +217,8 @@
" part can be either partition number or partition name\n"
"part size <interface> <dev> <part> <varname>\n"
" - set environment variable to the size of the partition (in blocks)\n"
- " part can be either partition number or partition name"
+ " part can be either partition number or partition name\n"
+ "part number <interface> <dev> <part> <varname>\n"
+ " - set environment variable to the partition number using the partition name\n"
+ " part must be specified as partition name"
);
diff --git a/common/Kconfig b/common/Kconfig
index 4865a4d..b556b59 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -821,6 +821,16 @@
default 100
depends on UPDATE_TFTP
+config ANDROID_AB
+ bool "Android A/B updates"
+ default n
+ help
+ If enabled, adds support for the new Android A/B update model. This
+ allows the bootloader to select which slot to boot from based on the
+ information provided by userspace via the Android boot_ctrl HAL. This
+ allows a bootloader to try a new version of the system but roll back
+ to previous version if the new one didn't boot all the way.
+
endmenu
menu "Blob list"
diff --git a/common/Makefile b/common/Makefile
index c7e41ef..302d8be 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -107,6 +107,7 @@
endif
obj-y += image.o
+obj-$(CONFIG_ANDROID_AB) += android_ab.o
obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
diff --git a/common/android_ab.c b/common/android_ab.c
new file mode 100644
index 0000000..05ffc6f
--- /dev/null
+++ b/common/android_ab.c
@@ -0,0 +1,300 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ */
+#include <common.h>
+#include <android_ab.h>
+#include <android_bootloader_message.h>
+#include <linux/err.h>
+#include <memalign.h>
+#include <u-boot/crc.h>
+
+/**
+ * Compute the CRC-32 of the bootloader control struct.
+ *
+ * Only the bytes up to the crc32_le field are considered for the CRC-32
+ * calculation.
+ *
+ * @param[in] abc bootloader control block
+ *
+ * @return crc32 sum
+ */
+static uint32_t ab_control_compute_crc(struct bootloader_control *abc)
+{
+ return crc32(0, (void *)abc, offsetof(typeof(*abc), crc32_le));
+}
+
+/**
+ * Initialize bootloader_control to the default value.
+ *
+ * It allows us to boot all slots in order from the first one. This value
+ * should be used when the bootloader message is corrupted, but not when
+ * a valid message indicates that all slots are unbootable.
+ *
+ * @param[in] abc bootloader control block
+ *
+ * @return 0 on success and a negative on error
+ */
+static int ab_control_default(struct bootloader_control *abc)
+{
+ int i;
+ const struct slot_metadata metadata = {
+ .priority = 15,
+ .tries_remaining = 7,
+ .successful_boot = 0,
+ .verity_corrupted = 0,
+ .reserved = 0
+ };
+
+ if (!abc)
+ return -EFAULT;
+
+ memcpy(abc->slot_suffix, "a\0\0\0", 4);
+ abc->magic = BOOT_CTRL_MAGIC;
+ abc->version = BOOT_CTRL_VERSION;
+ abc->nb_slot = NUM_SLOTS;
+ memset(abc->reserved0, 0, sizeof(abc->reserved0));
+ for (i = 0; i < abc->nb_slot; ++i)
+ abc->slot_info[i] = metadata;
+
+ memset(abc->reserved1, 0, sizeof(abc->reserved1));
+ abc->crc32_le = ab_control_compute_crc(abc);
+
+ return 0;
+}
+
+/**
+ * Load the boot_control struct from disk into newly allocated memory.
+ *
+ * This function allocates and returns an integer number of disk blocks,
+ * based on the block size of the passed device to help performing a
+ * read-modify-write operation on the boot_control struct.
+ * The boot_control struct offset (2 KiB) must be a multiple of the device
+ * block size, for simplicity.
+ *
+ * @param[in] dev_desc Device where to read the boot_control struct from
+ * @param[in] part_info Partition in 'dev_desc' where to read from, normally
+ * the "misc" partition should be used
+ * @param[out] pointer to pointer to bootloader_control data
+ * @return 0 on success and a negative on error
+ */
+static int ab_control_create_from_disk(struct blk_desc *dev_desc,
+ const disk_partition_t *part_info,
+ struct bootloader_control **abc)
+{
+ ulong abc_offset, abc_blocks, ret;
+
+ abc_offset = offsetof(struct bootloader_message_ab, slot_suffix);
+ if (abc_offset % part_info->blksz) {
+ log_err("ANDROID: Boot control block not block aligned.\n");
+ return -EINVAL;
+ }
+ abc_offset /= part_info->blksz;
+
+ abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
+ part_info->blksz);
+ if (abc_offset + abc_blocks > part_info->size) {
+ log_err("ANDROID: boot control partition too small. Need at");
+ log_err(" least %lu blocks but have %lu blocks.\n",
+ abc_offset + abc_blocks, part_info->size);
+ return -EINVAL;
+ }
+ *abc = malloc_cache_aligned(abc_blocks * part_info->blksz);
+ if (!*abc)
+ return -ENOMEM;
+
+ ret = blk_dread(dev_desc, part_info->start + abc_offset, abc_blocks,
+ *abc);
+ if (IS_ERR_VALUE(ret)) {
+ log_err("ANDROID: Could not read from boot ctrl partition\n");
+ free(*abc);
+ return -EIO;
+ }
+
+ log_debug("ANDROID: Loaded ABC, %lu blocks\n", abc_blocks);
+
+ return 0;
+}
+
+/**
+ * Store the loaded boot_control block.
+ *
+ * Store back to the same location it was read from with
+ * ab_control_create_from_misc().
+ *
+ * @param[in] dev_desc Device where we should write the boot_control struct
+ * @param[in] part_info Partition on the 'dev_desc' where to write
+ * @param[in] abc Pointer to the boot control struct and the extra bytes after
+ * it up to the nearest block boundary
+ * @return 0 on success and a negative on error
+ */
+static int ab_control_store(struct blk_desc *dev_desc,
+ const disk_partition_t *part_info,
+ struct bootloader_control *abc)
+{
+ ulong abc_offset, abc_blocks, ret;
+
+ abc_offset = offsetof(struct bootloader_message_ab, slot_suffix) /
+ part_info->blksz;
+ abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
+ part_info->blksz);
+ ret = blk_dwrite(dev_desc, part_info->start + abc_offset, abc_blocks,
+ abc);
+ if (IS_ERR_VALUE(ret)) {
+ log_err("ANDROID: Could not write back the misc partition\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * Compare two slots.
+ *
+ * The function determines slot which is should we boot from among the two.
+ *
+ * @param[in] a The first bootable slot metadata
+ * @param[in] b The second bootable slot metadata
+ * @return Negative if the slot "a" is better, positive of the slot "b" is
+ * better or 0 if they are equally good.
+ */
+static int ab_compare_slots(const struct slot_metadata *a,
+ const struct slot_metadata *b)
+{
+ /* Higher priority is better */
+ if (a->priority != b->priority)
+ return b->priority - a->priority;
+
+ /* Higher successful_boot value is better, in case of same priority */
+ if (a->successful_boot != b->successful_boot)
+ return b->successful_boot - a->successful_boot;
+
+ /* Higher tries_remaining is better to ensure round-robin */
+ if (a->tries_remaining != b->tries_remaining)
+ return b->tries_remaining - a->tries_remaining;
+
+ return 0;
+}
+
+int ab_select_slot(struct blk_desc *dev_desc, disk_partition_t *part_info)
+{
+ struct bootloader_control *abc = NULL;
+ u32 crc32_le;
+ int slot, i, ret;
+ bool store_needed = false;
+ char slot_suffix[4];
+
+ ret = ab_control_create_from_disk(dev_desc, part_info, &abc);
+ if (ret < 0) {
+ /*
+ * This condition represents an actual problem with the code or
+ * the board setup, like an invalid partition information.
+ * Signal a repair mode and do not try to boot from either slot.
+ */
+ return ret;
+ }
+
+ crc32_le = ab_control_compute_crc(abc);
+ if (abc->crc32_le != crc32_le) {
+ log_err("ANDROID: Invalid CRC-32 (expected %.8x, found %.8x),",
+ crc32_le, abc->crc32_le);
+ log_err("re-initializing A/B metadata.\n");
+
+ ret = ab_control_default(abc);
+ if (ret < 0) {
+ free(abc);
+ return -ENODATA;
+ }
+ store_needed = true;
+ }
+
+ if (abc->magic != BOOT_CTRL_MAGIC) {
+ log_err("ANDROID: Unknown A/B metadata: %.8x\n", abc->magic);
+ free(abc);
+ return -ENODATA;
+ }
+
+ if (abc->version > BOOT_CTRL_VERSION) {
+ log_err("ANDROID: Unsupported A/B metadata version: %.8x\n",
+ abc->version);
+ free(abc);
+ return -ENODATA;
+ }
+
+ /*
+ * At this point a valid boot control metadata is stored in abc,
+ * followed by other reserved data in the same block. We select a with
+ * the higher priority slot that
+ * - is not marked as corrupted and
+ * - either has tries_remaining > 0 or successful_boot is true.
+ * If the selected slot has a false successful_boot, we also decrement
+ * the tries_remaining until it eventually becomes unbootable because
+ * tries_remaining reaches 0. This mechanism produces a bootloader
+ * induced rollback, typically right after a failed update.
+ */
+
+ /* Safety check: limit the number of slots. */
+ if (abc->nb_slot > ARRAY_SIZE(abc->slot_info)) {
+ abc->nb_slot = ARRAY_SIZE(abc->slot_info);
+ store_needed = true;
+ }
+
+ slot = -1;
+ for (i = 0; i < abc->nb_slot; ++i) {
+ if (abc->slot_info[i].verity_corrupted ||
+ !abc->slot_info[i].tries_remaining) {
+ log_debug("ANDROID: unbootable slot %d tries: %d, ",
+ i, abc->slot_info[i].tries_remaining);
+ log_debug("corrupt: %d\n",
+ abc->slot_info[i].verity_corrupted);
+ continue;
+ }
+ log_debug("ANDROID: bootable slot %d pri: %d, tries: %d, ",
+ i, abc->slot_info[i].priority,
+ abc->slot_info[i].tries_remaining);
+ log_debug("corrupt: %d, successful: %d\n",
+ abc->slot_info[i].verity_corrupted,
+ abc->slot_info[i].successful_boot);
+
+ if (slot < 0 ||
+ ab_compare_slots(&abc->slot_info[i],
+ &abc->slot_info[slot]) < 0) {
+ slot = i;
+ }
+ }
+
+ if (slot >= 0 && !abc->slot_info[slot].successful_boot) {
+ log_err("ANDROID: Attempting slot %c, tries remaining %d\n",
+ BOOT_SLOT_NAME(slot),
+ abc->slot_info[slot].tries_remaining);
+ abc->slot_info[slot].tries_remaining--;
+ store_needed = true;
+ }
+
+ if (slot >= 0) {
+ /*
+ * Legacy user-space requires this field to be set in the BCB.
+ * Newer releases load this slot suffix from the command line
+ * or the device tree.
+ */
+ memset(slot_suffix, 0, sizeof(slot_suffix));
+ slot_suffix[0] = BOOT_SLOT_NAME(slot);
+ if (memcmp(abc->slot_suffix, slot_suffix,
+ sizeof(slot_suffix))) {
+ memcpy(abc->slot_suffix, slot_suffix,
+ sizeof(slot_suffix));
+ store_needed = true;
+ }
+ }
+
+ if (store_needed) {
+ abc->crc32_le = ab_control_compute_crc(abc);
+ ab_control_store(dev_desc, part_info, abc);
+ }
+ free(abc);
+
+ if (slot < 0)
+ return -EINVAL;
+
+ return slot;
+}
diff --git a/common/command.c b/common/command.c
index e192bb2..db25bf5 100644
--- a/common/command.c
+++ b/common/command.c
@@ -356,8 +356,13 @@
int i, j, k, len, seplen, argc;
int cnt;
char last_char;
+#ifdef CONFIG_CMDLINE_PS_SUPPORT
+ const char *ps_prompt = env_get("PS1");
+#else
+ const char *ps_prompt = CONFIG_SYS_PROMPT;
+#endif
- if (strcmp(prompt, CONFIG_SYS_PROMPT) != 0)
+ if (strcmp(prompt, ps_prompt) != 0)
return 0; /* not in normal console */
cnt = strlen(buf);
diff --git a/common/fdt_support.c b/common/fdt_support.c
index f31e9b0..86de5b8 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -671,30 +671,33 @@
dma_range[0] = 0;
if (size >= 0x100000000ull)
- dma_range[0] |= FDT_PCI_MEM64;
+ dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM64);
else
- dma_range[0] |= FDT_PCI_MEM32;
+ dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM32);
if (hose->regions[r].flags & PCI_REGION_PREFETCH)
- dma_range[0] |= FDT_PCI_PREFETCH;
+ dma_range[0] |= cpu_to_fdt32(FDT_PCI_PREFETCH);
#ifdef CONFIG_SYS_PCI_64BIT
- dma_range[1] = bus_start >> 32;
+ dma_range[1] = cpu_to_fdt32(bus_start >> 32);
#else
dma_range[1] = 0;
#endif
- dma_range[2] = bus_start & 0xffffffff;
+ dma_range[2] = cpu_to_fdt32(bus_start & 0xffffffff);
if (addrcell == 2) {
- dma_range[3] = phys_start >> 32;
- dma_range[4] = phys_start & 0xffffffff;
+ dma_range[3] = cpu_to_fdt32(phys_start >> 32);
+ dma_range[4] = cpu_to_fdt32(phys_start & 0xffffffff);
} else {
- dma_range[3] = phys_start & 0xffffffff;
+ dma_range[3] = cpu_to_fdt32(phys_start & 0xffffffff);
}
if (sizecell == 2) {
- dma_range[3 + addrcell + 0] = size >> 32;
- dma_range[3 + addrcell + 1] = size & 0xffffffff;
+ dma_range[3 + addrcell + 0] =
+ cpu_to_fdt32(size >> 32);
+ dma_range[3 + addrcell + 1] =
+ cpu_to_fdt32(size & 0xffffffff);
} else {
- dma_range[3 + addrcell + 0] = size & 0xffffffff;
+ dma_range[3 + addrcell + 0] =
+ cpu_to_fdt32(size & 0xffffffff);
}
dma_range += (3 + addrcell + sizecell);
@@ -1292,6 +1295,12 @@
return __of_translate_address(blob, node_offset, in_addr, "ranges");
}
+u64 fdt_translate_dma_address(const void *blob, int node_offset,
+ const fdt32_t *in_addr)
+{
+ return __of_translate_address(blob, node_offset, in_addr, "dma-ranges");
+}
+
/**
* fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
* who's reg property matches a physical cpu address
@@ -1546,7 +1555,7 @@
prop = fdt_getprop(fdt, node, "reg", &size);
- return prop ? fdt_translate_address(fdt, node, prop) : 0;
+ return prop ? fdt_translate_address(fdt, node, prop) : OF_BAD_ADDR;
}
/*
diff --git a/common/image-android.c b/common/image-android.c
index 8b0f6b3..6c9568a 100644
--- a/common/image-android.c
+++ b/common/image-android.c
@@ -52,6 +52,8 @@
ulong *os_data, ulong *os_len)
{
u32 kernel_addr = android_image_get_kernel_addr(hdr);
+ const struct image_header *ihdr = (const struct image_header *)
+ ((uintptr_t)hdr + hdr->page_size);
/*
* Not all Android tools use the id field for signing the image with
@@ -93,11 +95,19 @@
env_set("bootargs", newbootargs);
if (os_data) {
- *os_data = (ulong)hdr;
- *os_data += hdr->page_size;
+ if (image_get_magic(ihdr) == IH_MAGIC) {
+ *os_data = image_get_data(ihdr);
+ } else {
+ *os_data = (ulong)hdr;
+ *os_data += hdr->page_size;
+ }
}
- if (os_len)
- *os_len = hdr->kernel_size;
+ if (os_len) {
+ if (image_get_magic(ihdr) == IH_MAGIC)
+ *os_len = image_get_data_size(ihdr);
+ else
+ *os_len = hdr->kernel_size;
+ }
return 0;
}
@@ -131,7 +141,9 @@
{
const void *p = (void *)((uintptr_t)hdr + hdr->page_size);
- if (get_unaligned_le32(p) == LZ4F_MAGIC)
+ if (image_get_magic((image_header_t *)p) == IH_MAGIC)
+ return image_get_comp((image_header_t *)p);
+ else if (get_unaligned_le32(p) == LZ4F_MAGIC)
return IH_COMP_LZ4;
else
return IH_COMP_NONE;
diff --git a/common/menu.c b/common/menu.c
index 0f0a29a..7b66d19 100644
--- a/common/menu.c
+++ b/common/menu.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2010-2011 Calxeda, Inc.
+ * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
*/
#include <common.h>
@@ -39,6 +40,7 @@
char *(*item_choice)(void *);
void *item_choice_data;
struct list_head items;
+ int item_cnt;
};
/*
@@ -271,7 +273,7 @@
if (!m || !choice)
return -EINVAL;
- if (!m->prompt)
+ if (!m->prompt || m->item_cnt == 1)
return menu_default_choice(m, choice);
return menu_interactive_choice(m, choice);
@@ -323,6 +325,7 @@
item->data = item_data;
list_add_tail(&item->list, &m->items);
+ m->item_cnt++;
return 1;
}
@@ -374,6 +377,7 @@
m->item_data_print = item_data_print;
m->item_choice = item_choice;
m->item_choice_data = item_choice_data;
+ m->item_cnt = 0;
if (title) {
m->title = strdup(title);
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 7122c06..5d6da5d 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -248,6 +248,16 @@
info. Disabling this option could be useful to reduce SPL boot time
(e.g. approx. 6 ms faster, when output on i.MX6 with 115200 baud).
+config SPL_EARLY_BSS
+ depends on ARM && !ARM64
+ bool "Allows initializing BSS early before entering board_init_f"
+ help
+ On some platform we have sufficient memory available early on to
+ allow setting up and using a basic BSS prior to entering
+ board_init_f. Activating this option will also de-activate the
+ clearing of BSS during the SPL relocation process, thus allowing
+ to carry state from board_init_f to board_init_r by way of BSS.
+
config SPL_DISPLAY_PRINT
bool "Display a board-specific message in SPL"
help
@@ -908,6 +918,20 @@
expense and power consumption. This enables loading from SATA
using a configured device.
+config SPL_SATA_RAW_U_BOOT_USE_SECTOR
+ bool "SATA raw mode: by sector"
+ depends on SPL_SATA_SUPPORT
+ help
+ Use sector number for specifying U-Boot location on SATA disk in
+ raw mode.
+
+config SPL_SATA_RAW_U_BOOT_SECTOR
+ hex "Sector on the SATA disk to load U-Boot from"
+ depends on SPL_SATA_RAW_U_BOOT_USE_SECTOR
+ help
+ Sector on the SATA disk to load U-Boot from, when the SATA disk is being
+ used in raw mode. Units: SATA disk sectors (1 sector = 512 bytes).
+
config SPL_SERIAL_SUPPORT
bool "Support serial"
select SPL_PRINTF
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 87ecf0b..969f777 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -340,6 +340,16 @@
#endif
}
+/*
+ * Weak default function to allow customizing SPL fit loading for load-only
+ * use cases by allowing to skip the parsing/processing of the FIT contents
+ * (so that this can be done separately in a more customized fashion)
+ */
+__weak bool spl_load_simple_fit_skip_processing(void)
+{
+ return false;
+}
+
int spl_load_simple_fit(struct spl_image_info *spl_image,
struct spl_load_info *info, ulong sector, void *fit)
{
@@ -389,6 +399,10 @@
if (count == 0)
return -EIO;
+ /* skip further processing if requested to enable load-only use cases */
+ if (spl_load_simple_fit_skip_processing())
+ return 0;
+
/* find the node holding the images information */
images = fdt_path_offset(fit, FIT_IMAGES_PATH);
if (images < 0) {
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index 324d91c..b361988 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -151,7 +151,8 @@
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
static int mmc_load_image_raw_partition(struct spl_image_info *spl_image,
- struct mmc *mmc, int partition)
+ struct mmc *mmc, int partition,
+ unsigned long sector)
{
disk_partition_t info;
int err;
@@ -180,8 +181,7 @@
}
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
- return mmc_load_image_raw_sector(spl_image, mmc,
- info.start + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR);
+ return mmc_load_image_raw_sector(spl_image, mmc, info.start + sector);
#else
return mmc_load_image_raw_sector(spl_image, mmc, info.start);
#endif
@@ -234,7 +234,8 @@
#endif
#ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION
-static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc)
+static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc,
+ const char *filename)
{
int err = -ENOSYS;
@@ -248,7 +249,7 @@
#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
err = spl_load_image_fat(spl_image, mmc_get_blk_desc(mmc),
CONFIG_SYS_MMCSD_FS_BOOT_PARTITION,
- CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
+ filename);
if (!err)
return err;
#endif
@@ -263,7 +264,7 @@
#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
err = spl_load_image_ext(spl_image, mmc_get_blk_desc(mmc),
CONFIG_SYS_MMCSD_FS_BOOT_PARTITION,
- CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
+ filename);
if (!err)
return err;
#endif
@@ -276,7 +277,8 @@
return err;
}
#else
-static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc)
+static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc,
+ const char *filename)
{
return -ENOSYS;
}
@@ -301,24 +303,31 @@
}
#endif
-int spl_mmc_load_image(struct spl_image_info *spl_image,
- struct spl_boot_device *bootdev)
+int spl_mmc_load(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev,
+ const char *filename,
+ int raw_part,
+ unsigned long raw_sect)
{
- struct mmc *mmc = NULL;
+ static struct mmc *mmc;
u32 boot_mode;
int err = 0;
__maybe_unused int part;
- err = spl_mmc_find_device(&mmc, bootdev->boot_device);
- if (err)
- return err;
+ /* Perform peripheral init only once */
+ if (!mmc) {
+ err = spl_mmc_find_device(&mmc, bootdev->boot_device);
+ if (err)
+ return err;
- err = mmc_init(mmc);
- if (err) {
+ err = mmc_init(mmc);
+ if (err) {
+ mmc = NULL;
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
- printf("spl: mmc init failed with error: %d\n", err);
+ printf("spl: mmc init failed with error: %d\n", err);
#endif
- return err;
+ return err;
+ }
}
boot_mode = spl_boot_mode(bootdev->boot_device);
@@ -356,17 +365,13 @@
return err;
}
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
- err = spl_boot_partition(bootdev->boot_device);
- if (!err)
- return err;
-
- err = mmc_load_image_raw_partition(spl_image, mmc, err);
+ err = mmc_load_image_raw_partition(spl_image, mmc, raw_part,
+ raw_sect);
if (!err)
return err;
#endif
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
- err = mmc_load_image_raw_sector(spl_image, mmc,
- CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR);
+ err = mmc_load_image_raw_sector(spl_image, mmc, raw_sect);
if (!err)
return err;
#endif
@@ -374,7 +379,7 @@
case MMCSD_MODE_FS:
debug("spl: mmc boot mode: fs\n");
- err = spl_mmc_do_fs_boot(spl_image, mmc);
+ err = spl_mmc_do_fs_boot(spl_image, mmc, filename);
if (!err)
return err;
@@ -388,6 +393,27 @@
return err;
}
+int spl_mmc_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ return spl_mmc_load(spl_image, bootdev,
+#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
+ CONFIG_SPL_FS_LOAD_PAYLOAD_NAME,
+#else
+ NULL,
+#endif
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION
+ spl_boot_partition(bootdev->boot_device),
+#else
+ 0,
+#endif
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
+ CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR);
+#else
+ 0);
+#endif
+}
+
SPL_LOAD_IMAGE_METHOD("MMC1", 0, BOOT_DEVICE_MMC1, spl_mmc_load_image);
SPL_LOAD_IMAGE_METHOD("MMC2", 0, BOOT_DEVICE_MMC2, spl_mmc_load_image);
SPL_LOAD_IMAGE_METHOD("MMC2_2", 0, BOOT_DEVICE_MMC2_2, spl_mmc_load_image);
diff --git a/common/spl/spl_sata.c b/common/spl/spl_sata.c
index f0af9f3..e108af0 100644
--- a/common/spl/spl_sata.c
+++ b/common/spl/spl_sata.c
@@ -25,6 +25,37 @@
#define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "u-boot.img"
#endif
+#ifndef CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR
+/* Dummy value to make the compiler happy */
+#define CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR 0x100
+#endif
+
+static int spl_sata_load_image_raw(struct spl_image_info *spl_image,
+ struct blk_desc *stor_dev, unsigned long sector)
+{
+ struct image_header *header;
+ unsigned long count;
+ u32 image_size_sectors;
+ int ret;
+
+ header = spl_get_load_buffer(-sizeof(*header), stor_dev->blksz);
+ count = blk_dread(stor_dev, sector, 1, header);
+ if (count == 0)
+ return -EIO;
+
+ ret = spl_parse_image_header(spl_image, header);
+ if (ret)
+ return ret;
+
+ image_size_sectors = DIV_ROUND_UP(spl_image->size, stor_dev->blksz);
+ count = blk_dread(stor_dev, sector, image_size_sectors,
+ (void *)spl_image->load_addr);
+ if (count != image_size_sectors)
+ return -EIO;
+
+ return 0;
+}
+
static int spl_sata_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
@@ -59,6 +90,9 @@
err = spl_load_image_fat(spl_image, stor_dev,
CONFIG_SYS_SATA_FAT_BOOT_PARTITION,
CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
+ } else if (IS_ENABLED(CONFIG_SPL_SATA_RAW_U_BOOT_USE_SECTOR)) {
+ err = spl_sata_load_image_raw(spl_image, stor_dev,
+ CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR);
}
}
if (err) {
diff --git a/configs/UCP1020_SPIFLASH_defconfig b/configs/UCP1020_SPIFLASH_defconfig
deleted file mode 100644
index a2d7e66..0000000
--- a/configs/UCP1020_SPIFLASH_defconfig
+++ /dev/null
@@ -1,60 +0,0 @@
-CONFIG_PPC=y
-CONFIG_SYS_TEXT_BASE=0x11000000
-CONFIG_MPC85xx=y
-CONFIG_TARGET_UCP1020=y
-CONFIG_TARGET_UCP1020_SPIFLASH=y
-CONFIG_FIT=y
-CONFIG_FIT_VERBOSE=y
-CONFIG_OF_BOARD_SETUP=y
-CONFIG_OF_STDOUT_VIA_ALIAS=y
-# CONFIG_MISC_INIT_R is not set
-CONFIG_BOARD_EARLY_INIT_F=y
-CONFIG_BOARD_EARLY_INIT_R=y
-CONFIG_LAST_STAGE_INIT=y
-CONFIG_HUSH_PARSER=y
-# CONFIG_AUTO_COMPLETE is not set
-CONFIG_AUTOBOOT_KEYED=y
-CONFIG_AUTOBOOT_PROMPT="Autobooting in %d seconds, press \"<Esc>\" to stop\n"
-CONFIG_AUTOBOOT_STOP_STR="\x1b"
-CONFIG_CMD_IMLS=y
-CONFIG_CMD_GPIO=y
-CONFIG_CMD_I2C=y
-CONFIG_CMD_MMC=y
-# CONFIG_CMD_NAND is not set
-CONFIG_CMD_MMC_SPI=y
-CONFIG_CMD_SF=y
-CONFIG_CMD_SPI=y
-CONFIG_CMD_USB=y
-CONFIG_CMD_DHCP=y
-CONFIG_CMD_MII=y
-CONFIG_CMD_PING=y
-CONFIG_CMD_DATE=y
-CONFIG_MP=y
-# CONFIG_CMD_HASH is not set
-CONFIG_CMD_CRAMFS=y
-CONFIG_CMD_EXT2=y
-CONFIG_CMD_FAT=y
-CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_FSL_ESDHC=y
-CONFIG_MTD_NOR_FLASH=y
-CONFIG_FLASH_CFI_DRIVER=y
-CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
-CONFIG_SYS_FLASH_CFI=y
-CONFIG_SPI_FLASH=y
-CONFIG_SF_DEFAULT_MODE=0
-CONFIG_SF_DEFAULT_SPEED=10000000
-CONFIG_SPI_FLASH_STMICRO=y
-CONFIG_SPI_FLASH_SST=y
-CONFIG_SPI_FLASH_WINBOND=y
-CONFIG_PHY_MARVELL=y
-CONFIG_PHY_GIGE=y
-CONFIG_E1000=y
-CONFIG_MII=y
-CONFIG_TSEC_ENET=y
-CONFIG_SYS_NS16550=y
-CONFIG_SPI=y
-CONFIG_FSL_ESPI=y
-CONFIG_USB=y
-CONFIG_USB_STORAGE=y
-CONFIG_FS_CRAMFS=y
-CONFIG_OF_LIBFDT=y
diff --git a/configs/am335x_boneblack_vboot_defconfig b/configs/am335x_boneblack_vboot_defconfig
index ffe013f..9ccbd68 100644
--- a/configs/am335x_boneblack_vboot_defconfig
+++ b/configs/am335x_boneblack_vboot_defconfig
@@ -1,4 +1,8 @@
CONFIG_ARM=y
+# CONFIG_SPL_USE_ARCH_MEMCPY is not set
+# CONFIG_TPL_USE_ARCH_MEMCPY is not set
+# CONFIG_SPL_USE_ARCH_MEMSET is not set
+# CONFIG_TPL_USE_ARCH_MEMSET is not set
CONFIG_ARCH_OMAP2PLUS=y
CONFIG_TI_COMMON_CMD_OPTIONS=y
CONFIG_AM33XX=y
diff --git a/configs/am3517_evm_defconfig b/configs/am3517_evm_defconfig
index b9f59f3..5cb7632 100644
--- a/configs/am3517_evm_defconfig
+++ b/configs/am3517_evm_defconfig
@@ -44,6 +44,7 @@
CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
CONFIG_SYS_NAND_U_BOOT_OFFS=0x80000
CONFIG_SPL_NAND_SIMPLE=y
+CONFIG_DM_ETH=y
CONFIG_MII=y
CONFIG_DRIVER_TI_EMAC=y
CONFIG_PINCTRL=y
diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig
index b940af3..9d4c6a2 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -2,7 +2,7 @@
CONFIG_ARCH_K3=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SYS_MALLOC_F_LEN=0x8000
CONFIG_SOC_K3_AM6=y
CONFIG_TARGET_AM654_A53_EVM=y
CONFIG_SPL_MMC_SUPPORT=y
@@ -16,12 +16,14 @@
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPL_LOAD_FIT=y
CONFIG_OF_BOARD_SETUP=y
-CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run run_kern"
+CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run get_overlay_${boot}; run run_kern"
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_SPL_TEXT_BASE=0x80080000
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_STACK_R=y
CONFIG_SPL_SEPARATE_BSS=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1400
CONFIG_SPL_I2C_SUPPORT=y
CONFIG_SPL_DM_MAILBOX=y
CONFIG_SPL_DM_RESET=y
@@ -30,35 +32,41 @@
CONFIG_SPL_YMODEM_SUPPORT=y
CONFIG_CMD_ASKENV=y
# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPT=y
+CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_REMOTEPROC=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_TIME=y
# CONFIG_ISO_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
CONFIG_OF_CONTROL=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_DEFAULT_DEVICE_TREE="k3-am654-base-board"
CONFIG_SPL_MULTI_DTB_FIT=y
CONFIG_SPL_MULTI_DTB_FIT_NO_COMPRESSION=y
-CONFIG_ENV_IS_IN_FAT=y
-CONFIG_ENV_FAT_INTERFACE="mmc"
-CONFIG_ENV_FAT_DEVICE_AND_PART="1:1"
+CONFIG_ENV_IS_IN_MMC=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_DM=y
CONFIG_SPL_DM=y
CONFIG_SPL_DM_SEQ_ALIAS=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
CONFIG_CLK=y
CONFIG_SPL_CLK=y
CONFIG_CLK_TI_SCI=y
CONFIG_DMA_CHANNELS=y
CONFIG_TI_K3_NAVSS_UDMA=y
CONFIG_TI_SCI_PROTOCOL=y
+CONFIG_DM_GPIO=y
+CONFIG_DM_PCA953X=y
+CONFIG_DM_I2C=y
+CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
+CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
CONFIG_DM_MMC=y
CONFIG_MMC_SDHCI=y
-CONFIG_MMC_SDHCI_K3_ARASAN=y
+CONFIG_MMC_SDHCI_AM654=y
CONFIG_PHY_TI=y
CONFIG_PHY_FIXED=y
CONFIG_DM_ETH=y
@@ -80,3 +88,5 @@
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
CONFIG_SYSRESET_TI_SCI=y
+CONFIG_FAT_WRITE=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/am65x_evm_r5_defconfig b/configs/am65x_evm_r5_defconfig
index 3814872..7e81a98 100644
--- a/configs/am65x_evm_r5_defconfig
+++ b/configs/am65x_evm_r5_defconfig
@@ -3,7 +3,7 @@
CONFIG_SPL_GPIO_SUPPORT=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SYS_MALLOC_F_LEN=0x55000
CONFIG_SOC_K3_AM6=y
CONFIG_TARGET_AM654_R5_EVM=y
CONFIG_SPL_MMC_SUPPORT=y
@@ -18,9 +18,11 @@
CONFIG_USE_BOOTCOMMAND=y
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_SPL_TEXT_BASE=0x41c00000
-CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_STACK_R=y
CONFIG_SPL_SEPARATE_BSS=y
+CONFIG_SPL_EARLY_BSS=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x400
CONFIG_SPL_I2C_SUPPORT=y
CONFIG_SPL_DM_MAILBOX=y
CONFIG_SPL_DM_RESET=y
@@ -35,6 +37,7 @@
CONFIG_CMD_ASKENV=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_GPT=y
+CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_REMOTEPROC=y
# CONFIG_CMD_SETEXPR is not set
@@ -51,6 +54,8 @@
CONFIG_DM=y
CONFIG_SPL_DM=y
CONFIG_SPL_DM_SEQ_ALIAS=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
CONFIG_SPL_OF_TRANSLATE=y
CONFIG_CLK=y
CONFIG_SPL_CLK=y
@@ -58,12 +63,15 @@
CONFIG_TI_SCI_PROTOCOL=y
CONFIG_DM_GPIO=y
CONFIG_DA8XX_GPIO=y
+CONFIG_DM_I2C=y
+CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
+CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
CONFIG_MISC=y
CONFIG_DM_MMC=y
CONFIG_MMC_SDHCI=y
-CONFIG_MMC_SDHCI_K3_ARASAN=y
+CONFIG_MMC_SDHCI_AM654=y
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_GENERIC is not set
CONFIG_SPL_PINCTRL=y
@@ -88,3 +96,4 @@
CONFIG_TIMER=y
CONFIG_SPL_TIMER=y
CONFIG_OMAP_TIMER=y
+CONFIG_FS_FAT_MAX_CLUSTSIZE=16384
diff --git a/configs/am65x_hs_evm_a53_defconfig b/configs/am65x_hs_evm_a53_defconfig
index 9c55cd3..56052f7 100644
--- a/configs/am65x_hs_evm_a53_defconfig
+++ b/configs/am65x_hs_evm_a53_defconfig
@@ -3,7 +3,7 @@
CONFIG_TI_SECURE_DEVICE=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SYS_MALLOC_F_LEN=0x8000
CONFIG_SOC_K3_AM6=y
CONFIG_TARGET_AM654_A53_EVM=y
CONFIG_SPL_MMC_SUPPORT=y
@@ -19,12 +19,14 @@
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
CONFIG_OF_BOARD_SETUP=y
-CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run run_kern"
+CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run get_overlay_${boot}; run run_kern"
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_SPL_TEXT_BASE=0x80080000
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_STACK_R=y
CONFIG_SPL_SEPARATE_BSS=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1400
CONFIG_SPL_I2C_SUPPORT=y
CONFIG_SPL_DM_MAILBOX=y
CONFIG_SPL_DM_RESET=y
@@ -33,6 +35,7 @@
CONFIG_SPL_YMODEM_SUPPORT=y
CONFIG_CMD_ASKENV=y
# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_REMOTEPROC=y
# CONFIG_CMD_SETEXPR is not set
@@ -56,6 +59,11 @@
CONFIG_DMA_CHANNELS=y
CONFIG_TI_K3_NAVSS_UDMA=y
CONFIG_TI_SCI_PROTOCOL=y
+CONFIG_DM_GPIO=y
+CONFIG_DM_PCA953X=y
+CONFIG_DM_I2C=y
+CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
+CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
CONFIG_DM_MMC=y
@@ -77,3 +85,4 @@
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
CONFIG_SYSRESET_TI_SCI=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/am65x_hs_evm_r5_defconfig b/configs/am65x_hs_evm_r5_defconfig
index 0b12f15..d378d1e 100644
--- a/configs/am65x_hs_evm_r5_defconfig
+++ b/configs/am65x_hs_evm_r5_defconfig
@@ -4,7 +4,7 @@
CONFIG_SPL_GPIO_SUPPORT=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SYS_MALLOC_F_LEN=0x55000
CONFIG_SOC_K3_AM6=y
CONFIG_TARGET_AM654_R5_EVM=y
CONFIG_SPL_MMC_SUPPORT=y
@@ -20,9 +20,11 @@
CONFIG_USE_BOOTCOMMAND=y
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_SPL_TEXT_BASE=0x41c00000
-CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_STACK_R=y
CONFIG_SPL_SEPARATE_BSS=y
+CONFIG_SPL_EARLY_BSS=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x400
CONFIG_SPL_I2C_SUPPORT=y
CONFIG_SPL_DM_MAILBOX=y
CONFIG_SPL_DM_RESET=y
@@ -37,6 +39,7 @@
CONFIG_CMD_ASKENV=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_GPT=y
+CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_REMOTEPROC=y
# CONFIG_CMD_SETEXPR is not set
@@ -60,6 +63,9 @@
CONFIG_TI_SCI_PROTOCOL=y
CONFIG_DM_GPIO=y
CONFIG_DA8XX_GPIO=y
+CONFIG_DM_I2C=y
+CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
+CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
CONFIG_MISC=y
@@ -90,3 +96,4 @@
CONFIG_TIMER=y
CONFIG_SPL_TIMER=y
CONFIG_OMAP_TIMER=y
+CONFIG_FS_FAT_MAX_CLUSTSIZE=16384
diff --git a/configs/chromebit_mickey_defconfig b/configs/chromebit_mickey_defconfig
index 1a34309..cf815dc 100644
--- a/configs/chromebit_mickey_defconfig
+++ b/configs/chromebit_mickey_defconfig
@@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00100000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
# CONFIG_SPL_MMC_SUPPORT is not set
CONFIG_TARGET_CHROMEBIT_MICKEY=y
diff --git a/configs/chromebook_bob_defconfig b/configs/chromebook_bob_defconfig
index e61e27c..1c04f0a 100644
--- a/configs/chromebook_bob_defconfig
+++ b/configs/chromebook_bob_defconfig
@@ -2,9 +2,6 @@
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
CONFIG_SPL_GPIO_SUPPORT=y
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_BOOT_MODE_REG=0
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x4000
diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig
index 7c7986e..f6056f8 100644
--- a/configs/chromebook_jerry_defconfig
+++ b/configs/chromebook_jerry_defconfig
@@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00100000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
# CONFIG_SPL_MMC_SUPPORT is not set
CONFIG_TARGET_CHROMEBOOK_JERRY=y
diff --git a/configs/chromebook_minnie_defconfig b/configs/chromebook_minnie_defconfig
index 17c1ea6..b4bae3b 100644
--- a/configs/chromebook_minnie_defconfig
+++ b/configs/chromebook_minnie_defconfig
@@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00100000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
# CONFIG_SPL_MMC_SUPPORT is not set
CONFIG_TARGET_CHROMEBOOK_MINNIE=y
diff --git a/configs/chromebook_speedy_defconfig b/configs/chromebook_speedy_defconfig
index 0cc1eb6..999dc69 100644
--- a/configs/chromebook_speedy_defconfig
+++ b/configs/chromebook_speedy_defconfig
@@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00100000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
# CONFIG_SPL_MMC_SUPPORT is not set
CONFIG_TARGET_CHROMEBOOK_SPEEDY=y
diff --git a/configs/da850_am18xxevm_defconfig b/configs/da850_am18xxevm_defconfig
index 7ecdc36..adcbe1d 100644
--- a/configs/da850_am18xxevm_defconfig
+++ b/configs/da850_am18xxevm_defconfig
@@ -50,6 +50,7 @@
CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_DM_ETH=y
CONFIG_MII=y
CONFIG_DRIVER_TI_EMAC=y
CONFIG_DM_SERIAL=y
diff --git a/configs/da850evm_defconfig b/configs/da850evm_defconfig
index c095058..f7c679d 100644
--- a/configs/da850evm_defconfig
+++ b/configs/da850evm_defconfig
@@ -59,6 +59,7 @@
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SPI_FLASH_MTD=y
+CONFIG_DM_ETH=y
CONFIG_MII=y
CONFIG_DRIVER_TI_EMAC=y
CONFIG_PINCTRL=y
diff --git a/configs/da850evm_direct_nor_defconfig b/configs/da850evm_direct_nor_defconfig
index 166e77b..9b1da07 100644
--- a/configs/da850evm_direct_nor_defconfig
+++ b/configs/da850evm_direct_nor_defconfig
@@ -50,6 +50,7 @@
CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_DM_ETH=y
CONFIG_MII=y
CONFIG_DRIVER_TI_EMAC=y
CONFIG_PINCTRL=y
diff --git a/configs/da850evm_nand_defconfig b/configs/da850evm_nand_defconfig
index 7271016..8f06b85 100644
--- a/configs/da850evm_nand_defconfig
+++ b/configs/da850evm_nand_defconfig
@@ -59,6 +59,7 @@
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SPI_FLASH_MTD=y
+CONFIG_DM_ETH=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_SINGLE=y
CONFIG_DM_SERIAL=y
diff --git a/configs/evb-ast2500_defconfig b/configs/evb-ast2500_defconfig
index b73da72..59d41cb 100644
--- a/configs/evb-ast2500_defconfig
+++ b/configs/evb-ast2500_defconfig
@@ -11,16 +11,19 @@
CONFIG_PRE_CONSOLE_BUFFER=y
CONFIG_PRE_CON_BUF_ADDR=0x1e720000
# CONFIG_DISPLAY_CPUINFO is not set
+CONFIG_HUSH_PARSER=y
# CONFIG_AUTO_COMPLETE is not set
CONFIG_CMD_I2C=y
CONFIG_CMD_DHCP=y
CONFIG_CMD_MII=y
CONFIG_CMD_PING=y
CONFIG_DEFAULT_DEVICE_TREE="ast2500-evb"
+CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_REGMAP=y
CONFIG_CLK=y
CONFIG_DM_I2C=y
CONFIG_SYS_I2C_ASPEED=y
+# CONFIG_MMC is not set
CONFIG_PHY_REALTEK=y
CONFIG_DM_ETH=y
CONFIG_FTGMAC100=y
diff --git a/configs/evb-px5_defconfig b/configs/evb-px5_defconfig
index 9601b12..a2b72c7 100644
--- a/configs/evb-px5_defconfig
+++ b/configs/evb-px5_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3368=y
CONFIG_TPL_LDSCRIPT="arch/arm/mach-rockchip/u-boot-tpl-v8.lds"
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x40000
@@ -70,10 +67,6 @@
CONFIG_DEBUG_UART_SHIFT=2
CONFIG_DEBUG_UART_SKIP_INIT=y
CONFIG_SYSRESET=y
-CONFIG_TIMER=y
-CONFIG_SPL_TIMER=y
-CONFIG_TPL_TIMER=y
-CONFIG_ROCKCHIP_TIMER=y
CONFIG_USE_TINY_PRINTF=y
CONFIG_PANIC_HANG=y
CONFIG_SPL_TINY_MEMSET=y
diff --git a/configs/evb-rk3229_defconfig b/configs/evb-rk3229_defconfig
index 31c1b17..2032978 100644
--- a/configs/evb-rk3229_defconfig
+++ b/configs/evb-rk3229_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x61000000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x800
CONFIG_ROCKCHIP_RK322X=y
CONFIG_TPL_LDSCRIPT="arch/arm/mach-rockchip/u-boot-tpl.lds"
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0
diff --git a/configs/evb-rk3288_defconfig b/configs/evb-rk3288_defconfig
index 843c59d..a6df143 100644
--- a/configs/evb-rk3288_defconfig
+++ b/configs/evb-rk3288_defconfig
@@ -1,12 +1,10 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
-CONFIG_SYS_TEXT_BASE=0x00000000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SYS_TEXT_BASE=0x01000000
CONFIG_ROCKCHIP_RK3288=y
-CONFIG_SPL_ROCKCHIP_BACK_TO_BROM=y
CONFIG_TARGET_EVB_RK3288=y
CONFIG_NR_DRAM_BANKS=1
-CONFIG_SPL_STACK_R_ADDR=0x80000
+CONFIG_SPL_SIZE_LIMIT=307200
CONFIG_DEBUG_UART_BASE=0xff690000
CONFIG_DEBUG_UART_CLOCK=24000000
CONFIG_DEBUG_UART=y
@@ -15,9 +13,7 @@
CONFIG_DEFAULT_FDT_FILE="rk3288-evb-rk808.dtb"
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_DISPLAY_BOARDINFO_LATE=y
-CONFIG_SPL_TEXT_BASE=0xff704000
-CONFIG_SPL_STACK_R=y
-CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000
+CONFIG_SPL_TEXT_BASE=0
CONFIG_CMD_GPIO=y
CONFIG_CMD_GPT=y
CONFIG_CMD_I2C=y
diff --git a/configs/evb-rk3328_defconfig b/configs/evb-rk3328_defconfig
index 92d6817..fcc04f2 100644
--- a/configs/evb-rk3328_defconfig
+++ b/configs/evb-rk3328_defconfig
@@ -1,7 +1,5 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SYS_TEXT_BASE=0x00200000
CONFIG_ROCKCHIP_RK3328=y
CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig
index f10502c..764d32f 100644
--- a/configs/evb-rk3399_defconfig
+++ b/configs/evb-rk3399_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x50000
CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/fennec-rk3288_defconfig b/configs/fennec-rk3288_defconfig
index 6dfaff5..16d8fb1 100644
--- a/configs/fennec-rk3288_defconfig
+++ b/configs/fennec-rk3288_defconfig
@@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00000000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
CONFIG_SPL_ROCKCHIP_BACK_TO_BROM=y
CONFIG_TARGET_FENNEC_RK3288=y
diff --git a/configs/ficus-rk3399_defconfig b/configs/ficus-rk3399_defconfig
index 6a1b279..d1425dc 100644
--- a/configs/ficus-rk3399_defconfig
+++ b/configs/ficus-rk3399_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x4000
CONFIG_TARGET_ROCK960_RK3399=y
diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig
index 4cedb28..8abe8a6 100644
--- a/configs/firefly-rk3288_defconfig
+++ b/configs/firefly-rk3288_defconfig
@@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00000000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
CONFIG_SPL_ROCKCHIP_BACK_TO_BROM=y
CONFIG_TARGET_FIREFLY_RK3288=y
diff --git a/configs/firefly-rk3399_defconfig b/configs/firefly-rk3399_defconfig
index 61f05b7..9f05f33 100644
--- a/configs/firefly-rk3399_defconfig
+++ b/configs/firefly-rk3399_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x50000
CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/lion-rk3368_defconfig b/configs/lion-rk3368_defconfig
index 75e8583..2c4e11c 100644
--- a/configs/lion-rk3368_defconfig
+++ b/configs/lion-rk3368_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3368=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0
CONFIG_TPL_LIBCOMMON_SUPPORT=y
@@ -91,10 +88,6 @@
CONFIG_DEBUG_UART_SKIP_INIT=y
CONFIG_ROCKCHIP_SPI=y
CONFIG_SYSRESET=y
-CONFIG_TIMER=y
-CONFIG_SPL_TIMER=y
-CONFIG_TPL_TIMER=y
-CONFIG_ROCKCHIP_TIMER=y
CONFIG_USE_TINY_PRINTF=y
CONFIG_SPL_TINY_MEMSET=y
CONFIG_LZO=y
diff --git a/configs/ls1021atsn_qspi_defconfig b/configs/ls1021atsn_qspi_defconfig
new file mode 100644
index 0000000..d1a6dad
--- /dev/null
+++ b/configs/ls1021atsn_qspi_defconfig
@@ -0,0 +1,79 @@
+CONFIG_ARM=y
+CONFIG_TARGET_LS1021ATSN=y
+CONFIG_SYS_TEXT_BASE=0x40100000
+CONFIG_DEFAULT_DEVICE_TREE="ls1021a-tsn"
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_MISC_INIT_R=y
+CONFIG_SYS_EXTRA_OPTIONS="QSPI_BOOT"
+CONFIG_QSPI_BOOT=y
+CONFIG_BOOTDELAY=3
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_GREPENV=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_FAT=y
+CONFIG_FSL_ESDHC=y
+CONFIG_CMD_SF=y
+CONFIG_OF_CONTROL=y
+CONFIG_OF_BOARD_SETUP=y
+CONFIG_OF_STDOUT_VIA_ALIAS=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_DM=y
+CONFIG_FSL_CAAM=y
+CONFIG_SPI=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_BAR=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_NETDEVICES=y
+CONFIG_DM_ETH=y
+CONFIG_TSEC_ENET=y
+CONFIG_MII=y
+CONFIG_SYS_NS16550=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_DATAFLASH=y
+CONFIG_FSL_DSPI=y
+CONFIG_FSL_QSPI=y
+CONFIG_PCI=y
+CONFIG_CMD_PCI=y
+CONFIG_DM_PCI=y
+CONFIG_DM_PCI_COMPAT=y
+CONFIG_CMD_MMC=y
+CONFIG_DM_MMC=y
+CONFIG_FSL_SPI_ALIGNED_TXFIFO=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_CMD_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_FSL=y
+CONFIG_USB_XHCI_DWC3=y
+CONFIG_HAS_FSL_XHCI_USB=y
+CONFIG_USB_STORAGE=y
+CONFIG_CMD_EXT2=y
+CONFIG_PCIE_LAYERSCAPE=y
+CONFIG_PHYLIB=y
+CONFIG_PHY_GIGE=y
+CONFIG_PHY_ATHEROS=y
+CONFIG_PHY_BROADCOM=y
+CONFIG_PHY_FIXED=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
+CONFIG_CMDLINE_TAG=y
+CONFIG_CMDLINE_EDITING=y
+CONFIG_AUTO_COMPLETE=y
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_CMD_BOOTZ=y
+CONFIG_SYS_LONGHELP=y
+CONFIG_FIT=y
+CONFIG_CMD_DM=y
+CONFIG_AHCI=y
+CONFIG_CMD_I2C=y
+CONFIG_BLK=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_FS_UUID=y
+CONFIG_SILENT_CONSOLE=y
+CONFIG_DISTRO_DEFAULTS=y
diff --git a/configs/ls1021atsn_sdcard_defconfig b/configs/ls1021atsn_sdcard_defconfig
new file mode 100644
index 0000000..299b300
--- /dev/null
+++ b/configs/ls1021atsn_sdcard_defconfig
@@ -0,0 +1,91 @@
+CONFIG_ARM=y
+CONFIG_TARGET_LS1021ATSN=y
+CONFIG_SPL_TEXT_BASE=0x10000000
+CONFIG_SYS_TEXT_BASE=0x82000000
+CONFIG_DEFAULT_DEVICE_TREE="ls1021a-tsn"
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_MISC_INIT_R=y
+CONFIG_SPL=y
+CONFIG_SPL_FRAMEWORK=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SPL_WATCHDOG_SUPPORT=y
+CONFIG_SPL_MPC8XXX_INIT_DDR_SUPPORT=y
+CONFIG_SYS_EXTRA_OPTIONS="RAMBOOT_PBL,SPL_FSL_PBL,SD_BOOT,SD_BOOT_QSPI"
+CONFIG_SD_BOOT=y
+CONFIG_BOOTDELAY=3
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0xe8
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_GREPENV=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_MMC=y
+CONFIG_FSL_ESDHC=y
+CONFIG_CMD_SF=y
+CONFIG_OF_CONTROL=y
+CONFIG_OF_BOARD_SETUP=y
+CONFIG_OF_STDOUT_VIA_ALIAS=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_DM=y
+CONFIG_FSL_CAAM=y
+CONFIG_SPI=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_BAR=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_NETDEVICES=y
+CONFIG_DM_ETH=y
+CONFIG_TSEC_ENET=y
+CONFIG_MII=y
+CONFIG_SYS_NS16550=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_DATAFLASH=y
+CONFIG_FSL_DSPI=y
+CONFIG_FSL_QSPI=y
+CONFIG_PCI=y
+CONFIG_CMD_PCI=y
+CONFIG_DM_PCI=y
+CONFIG_DM_PCI_COMPAT=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_CMD_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_FSL=y
+CONFIG_USB_XHCI_DWC3=y
+CONFIG_HAS_FSL_XHCI_USB=y
+CONFIG_USB_STORAGE=y
+CONFIG_CMD_EXT2=y
+CONFIG_PCIE_LAYERSCAPE=y
+CONFIG_PHYLIB=y
+CONFIG_PHY_GIGE=y
+CONFIG_PHY_ATHEROS=y
+CONFIG_PHY_BROADCOM=y
+CONFIG_PHY_FIXED=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
+CONFIG_CMDLINE_TAG=y
+CONFIG_CMDLINE_EDITING=y
+CONFIG_AUTO_COMPLETE=y
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_CMD_BOOTZ=y
+CONFIG_SYS_LONGHELP=y
+CONFIG_FIT=y
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_I2C_SUPPORT=y
+CONFIG_SPL_ENV_SUPPORT=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_CMD_DM=y
+CONFIG_AHCI=y
+CONFIG_CMD_I2C=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_FS_UUID=y
+CONFIG_SILENT_CONSOLE=y
+CONFIG_DISTRO_DEFAULTS=y
diff --git a/configs/ls1021atwr_nor_SECURE_BOOT_defconfig b/configs/ls1021atwr_nor_SECURE_BOOT_defconfig
index 6c4bb9a..830affc 100644
--- a/configs/ls1021atwr_nor_SECURE_BOOT_defconfig
+++ b/configs/ls1021atwr_nor_SECURE_BOOT_defconfig
@@ -40,7 +40,9 @@
CONFIG_PHY_GIGE=y
CONFIG_E1000=y
CONFIG_MII=y
+CONFIG_DM_ETH=y
CONFIG_TSEC_ENET=y
+CONFIG_PHY_ATHEROS=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
diff --git a/configs/ls1021atwr_nor_defconfig b/configs/ls1021atwr_nor_defconfig
index 9d8c202..c4d18c6 100644
--- a/configs/ls1021atwr_nor_defconfig
+++ b/configs/ls1021atwr_nor_defconfig
@@ -40,7 +40,9 @@
CONFIG_PHY_GIGE=y
CONFIG_E1000=y
CONFIG_MII=y
+CONFIG_DM_ETH=y
CONFIG_TSEC_ENET=y
+CONFIG_PHY_ATHEROS=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
diff --git a/configs/ls1021atwr_nor_lpuart_defconfig b/configs/ls1021atwr_nor_lpuart_defconfig
index b9cfdb6..b74d58a 100644
--- a/configs/ls1021atwr_nor_lpuart_defconfig
+++ b/configs/ls1021atwr_nor_lpuart_defconfig
@@ -42,7 +42,9 @@
CONFIG_PHY_GIGE=y
CONFIG_E1000=y
CONFIG_MII=y
+CONFIG_DM_ETH=y
CONFIG_TSEC_ENET=y
+CONFIG_PHY_ATHEROS=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
diff --git a/configs/ls1021atwr_qspi_defconfig b/configs/ls1021atwr_qspi_defconfig
index 8c27c59..911061a 100644
--- a/configs/ls1021atwr_qspi_defconfig
+++ b/configs/ls1021atwr_qspi_defconfig
@@ -42,7 +42,9 @@
CONFIG_PHY_GIGE=y
CONFIG_E1000=y
CONFIG_MII=y
+CONFIG_DM_ETH=y
CONFIG_TSEC_ENET=y
+CONFIG_PHY_ATHEROS=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
diff --git a/configs/ls1021atwr_sdcard_ifc_SECURE_BOOT_defconfig b/configs/ls1021atwr_sdcard_ifc_SECURE_BOOT_defconfig
index 979878d..d8c2639 100644
--- a/configs/ls1021atwr_sdcard_ifc_SECURE_BOOT_defconfig
+++ b/configs/ls1021atwr_sdcard_ifc_SECURE_BOOT_defconfig
@@ -53,7 +53,9 @@
CONFIG_PHY_GIGE=y
CONFIG_E1000=y
CONFIG_MII=y
+CONFIG_DM_ETH=y
CONFIG_TSEC_ENET=y
+CONFIG_PHY_ATHEROS=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
diff --git a/configs/ls1021atwr_sdcard_ifc_defconfig b/configs/ls1021atwr_sdcard_ifc_defconfig
index 59af172..d23c875 100644
--- a/configs/ls1021atwr_sdcard_ifc_defconfig
+++ b/configs/ls1021atwr_sdcard_ifc_defconfig
@@ -54,7 +54,9 @@
CONFIG_PHY_GIGE=y
CONFIG_E1000=y
CONFIG_MII=y
+CONFIG_DM_ETH=y
CONFIG_TSEC_ENET=y
+CONFIG_PHY_ATHEROS=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
diff --git a/configs/ls1021atwr_sdcard_qspi_defconfig b/configs/ls1021atwr_sdcard_qspi_defconfig
index d7fec5e..7b2c290 100644
--- a/configs/ls1021atwr_sdcard_qspi_defconfig
+++ b/configs/ls1021atwr_sdcard_qspi_defconfig
@@ -53,7 +53,9 @@
CONFIG_PHY_GIGE=y
CONFIG_E1000=y
CONFIG_MII=y
+CONFIG_DM_ETH=y
CONFIG_TSEC_ENET=y
+CONFIG_PHY_ATHEROS=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
diff --git a/configs/ls1028aqds_tfa_SECURE_BOOT_defconfig b/configs/ls1028aqds_tfa_SECURE_BOOT_defconfig
index ef78f0d..4a2b354 100644
--- a/configs/ls1028aqds_tfa_SECURE_BOOT_defconfig
+++ b/configs/ls1028aqds_tfa_SECURE_BOOT_defconfig
@@ -39,13 +39,17 @@
CONFIG_SPI_FLASH_STMICRO=y
# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
CONFIG_PHYLIB=y
+CONFIG_PHY_AQUANTIA=y
CONFIG_PHY_ATHEROS=y
+CONFIG_PHY_VITESSE=y
CONFIG_DM_ETH=y
-CONFIG_PHY_GIGE=y
+CONFIG_DM_MDIO=y
CONFIG_E1000=y
+CONFIG_FSL_ENETC=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
+CONFIG_PCIE_ECAM_GENERIC=y
CONFIG_PCIE_LAYERSCAPE=y
CONFIG_SCSI=y
CONFIG_DM_SCSI=y
diff --git a/configs/ls1028aqds_tfa_defconfig b/configs/ls1028aqds_tfa_defconfig
index 93d22a2..b315910 100644
--- a/configs/ls1028aqds_tfa_defconfig
+++ b/configs/ls1028aqds_tfa_defconfig
@@ -42,10 +42,13 @@
CONFIG_SPI_FLASH_STMICRO=y
# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
CONFIG_PHYLIB=y
+CONFIG_PHY_AQUANTIA=y
CONFIG_PHY_ATHEROS=y
+CONFIG_PHY_VITESSE=y
CONFIG_DM_ETH=y
-CONFIG_PHY_GIGE=y
+CONFIG_DM_MDIO=y
CONFIG_E1000=y
+CONFIG_FSL_ENETC=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
diff --git a/configs/ls1028ardb_tfa_SECURE_BOOT_defconfig b/configs/ls1028ardb_tfa_SECURE_BOOT_defconfig
index a2a2181..63976ae 100644
--- a/configs/ls1028ardb_tfa_SECURE_BOOT_defconfig
+++ b/configs/ls1028ardb_tfa_SECURE_BOOT_defconfig
@@ -40,12 +40,16 @@
# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
CONFIG_PHYLIB=y
CONFIG_PHY_ATHEROS=y
+CONFIG_PHY_VITESSE=y
CONFIG_DM_ETH=y
+CONFIG_DM_MDIO=y
CONFIG_PHY_GIGE=y
CONFIG_E1000=y
+CONFIG_FSL_ENETC=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
+CONFIG_PCIE_ECAM_GENERIC=y
CONFIG_PCIE_LAYERSCAPE=y
CONFIG_SCSI=y
CONFIG_DM_SCSI=y
diff --git a/configs/ls1028ardb_tfa_defconfig b/configs/ls1028ardb_tfa_defconfig
index 2d0c2b1..8ab778d 100644
--- a/configs/ls1028ardb_tfa_defconfig
+++ b/configs/ls1028ardb_tfa_defconfig
@@ -43,9 +43,12 @@
# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
CONFIG_PHYLIB=y
CONFIG_PHY_ATHEROS=y
+CONFIG_PHY_VITESSE=y
CONFIG_DM_ETH=y
+CONFIG_DM_MDIO=y
CONFIG_PHY_GIGE=y
CONFIG_E1000=y
+CONFIG_FSL_ENETC=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_DM_PCI_COMPAT=y
diff --git a/configs/miqi-rk3288_defconfig b/configs/miqi-rk3288_defconfig
index 936192f..c9a3511 100644
--- a/configs/miqi-rk3288_defconfig
+++ b/configs/miqi-rk3288_defconfig
@@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00000000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
CONFIG_SPL_ROCKCHIP_BACK_TO_BROM=y
CONFIG_TARGET_MIQI_RK3288=y
diff --git a/configs/mt7629_rfb_defconfig b/configs/mt7629_rfb_defconfig
index d8efba6..c0a586f 100644
--- a/configs/mt7629_rfb_defconfig
+++ b/configs/mt7629_rfb_defconfig
@@ -1,4 +1,5 @@
CONFIG_ARM=y
+CONFIG_SYS_ARCH_TIMER=y
CONFIG_SYS_THUMB_BUILD=y
CONFIG_ARCH_MEDIATEK=y
CONFIG_SYS_TEXT_BASE=0x41e00000
@@ -67,9 +68,6 @@
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
CONFIG_SYSRESET_WATCHDOG=y
-CONFIG_TIMER=y
-CONFIG_SPL_TIMER=y
-CONFIG_MTK_TIMER=y
CONFIG_WDT_MTK=y
CONFIG_LZMA=y
# CONFIG_EFI_LOADER is not set
diff --git a/configs/nanopc-t4-rk3399_defconfig b/configs/nanopc-t4-rk3399_defconfig
index 7863e45..bca4f08 100644
--- a/configs/nanopc-t4-rk3399_defconfig
+++ b/configs/nanopc-t4-rk3399_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x50000
CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/nanopi-m4-rk3399_defconfig b/configs/nanopi-m4-rk3399_defconfig
index 8b9237c..dd2065d 100644
--- a/configs/nanopi-m4-rk3399_defconfig
+++ b/configs/nanopi-m4-rk3399_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x50000
CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/nanopi-neo4-rk3399_defconfig b/configs/nanopi-neo4-rk3399_defconfig
index 5799ab3..46039d1 100644
--- a/configs/nanopi-neo4-rk3399_defconfig
+++ b/configs/nanopi-neo4-rk3399_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x50000
CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/omapl138_lcdk_defconfig b/configs/omapl138_lcdk_defconfig
index 48f251e..466ae86 100644
--- a/configs/omapl138_lcdk_defconfig
+++ b/configs/omapl138_lcdk_defconfig
@@ -49,6 +49,7 @@
CONFIG_SF_DEFAULT_SPEED=30000000
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_DM_ETH=y
CONFIG_MII=y
CONFIG_DRIVER_TI_EMAC=y
CONFIG_DM_SERIAL=y
diff --git a/configs/orangepi-rk3399_defconfig b/configs/orangepi-rk3399_defconfig
index 82ec242..16a0a17 100644
--- a/configs/orangepi-rk3399_defconfig
+++ b/configs/orangepi-rk3399_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x50000
CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/phycore-rk3288_defconfig b/configs/phycore-rk3288_defconfig
index 2e6a4a7..dfddc4a 100644
--- a/configs/phycore-rk3288_defconfig
+++ b/configs/phycore-rk3288_defconfig
@@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00000000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
CONFIG_SPL_ROCKCHIP_BACK_TO_BROM=y
CONFIG_TARGET_PHYCORE_RK3288=y
diff --git a/configs/popmetal-rk3288_defconfig b/configs/popmetal-rk3288_defconfig
index 902294b..4c9a7f0 100644
--- a/configs/popmetal-rk3288_defconfig
+++ b/configs/popmetal-rk3288_defconfig
@@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00000000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
CONFIG_SPL_ROCKCHIP_BACK_TO_BROM=y
CONFIG_TARGET_POPMETAL_RK3288=y
diff --git a/configs/puma-rk3399_defconfig b/configs/puma-rk3399_defconfig
index 5cb2273..37f845c 100644
--- a/configs/puma-rk3399_defconfig
+++ b/configs/puma-rk3399_defconfig
@@ -2,9 +2,6 @@
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
CONFIG_SPL_GPIO_SUPPORT=y
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_BOOT_MODE_REG=0x0
CONFIG_TARGET_PUMA_RK3399=y
diff --git a/configs/rock-pi-4-rk3399_defconfig b/configs/rock-pi-4-rk3399_defconfig
index be670df..14ae39a 100644
--- a/configs/rock-pi-4-rk3399_defconfig
+++ b/configs/rock-pi-4-rk3399_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x50000
CONFIG_NR_DRAM_BANKS=1
@@ -28,6 +25,7 @@
CONFIG_DEFAULT_DEVICE_TREE="rk3399-rock-pi-4"
CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
CONFIG_ENV_IS_IN_MMC=y
+CONFIG_RAM_RK3399_LPDDR4=y
CONFIG_ROCKCHIP_GPIO=y
CONFIG_SYS_I2C_ROCKCHIP=y
CONFIG_MMC_DW=y
diff --git a/configs/rock64-rk3328_defconfig b/configs/rock64-rk3328_defconfig
index 6529ded..ef453e7 100644
--- a/configs/rock64-rk3328_defconfig
+++ b/configs/rock64-rk3328_defconfig
@@ -2,9 +2,6 @@
CONFIG_SMBIOS_PRODUCT_NAME="rock64_rk3328"
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_SYS_TEXT_BASE=0x00200000
CONFIG_ROCKCHIP_RK3328=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x40000
diff --git a/configs/rock960-rk3399_defconfig b/configs/rock960-rk3399_defconfig
index 1958b7e..ed11fef 100644
--- a/configs/rock960-rk3399_defconfig
+++ b/configs/rock960-rk3399_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x4000
CONFIG_TARGET_ROCK960_RK3399=y
@@ -21,7 +18,8 @@
CONFIG_CMD_BOOTZ=y
CONFIG_CMD_GPT=y
CONFIG_CMD_MMC=y
-CONFIG_CMD_SF=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
CONFIG_CMD_USB=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_TIME=y
@@ -34,8 +32,8 @@
CONFIG_MMC_DW=y
CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_SDMA=y
CONFIG_MMC_SDHCI_ROCKCHIP=y
-CONFIG_SF_DEFAULT_SPEED=20000000
CONFIG_PMIC_RK8XX=y
CONFIG_REGULATOR_PWM=y
CONFIG_REGULATOR_RK8XX=y
@@ -47,5 +45,15 @@
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_GENERIC=y
CONFIG_ROCKCHIP_USB2_PHY=y
+CONFIG_DM_ETH=y
+CONFIG_USB_HOST_ETHER=y
+CONFIG_USB_ETHER_ASIX88179=y
+CONFIG_USB_ETHER_ASIX=y
+CONFIG_USB_ETHER_MCS7830=y
+CONFIG_USB_ETHER_RTL8152=y
+CONFIG_USB_ETHER_SMSC95XX=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DWC3=y
+# CONFIG_USB_XHCI_ROCKCHIP is not set
CONFIG_USE_TINY_PRINTF=y
CONFIG_ERRNO_STR=y
diff --git a/configs/rockpro64-rk3399_defconfig b/configs/rockpro64-rk3399_defconfig
index e8fc7ae..72bfff2 100644
--- a/configs/rockpro64-rk3399_defconfig
+++ b/configs/rockpro64-rk3399_defconfig
@@ -1,9 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SPL_LIBCOMMON_SUPPORT=y
-CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ROCKCHIP_RK3399=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x50000
CONFIG_NR_DRAM_BANKS=1
@@ -28,6 +25,7 @@
CONFIG_DEFAULT_DEVICE_TREE="rk3399-rockpro64"
CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
CONFIG_ENV_IS_IN_MMC=y
+CONFIG_RAM_RK3399_LPDDR4=y
CONFIG_ROCKCHIP_GPIO=y
CONFIG_SYS_I2C_ROCKCHIP=y
CONFIG_MMC_DW=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 61391a7..11cc097 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -20,6 +20,7 @@
CONFIG_LOG_MAX_LEVEL=6
CONFIG_LOG_ERROR_RETURN=y
CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_ANDROID_AB=y
CONFIG_CMD_CPU=y
CONFIG_CMD_LICENSE=y
CONFIG_CMD_BOOTZ=y
@@ -47,6 +48,7 @@
CONFIG_CMD_SPI=y
CONFIG_CMD_USB=y
CONFIG_CMD_AXI=y
+CONFIG_CMD_AB_SELECT=y
CONFIG_CMD_TFTPPUT=y
CONFIG_CMD_TFTPSRV=y
CONFIG_CMD_RARP=y
diff --git a/configs/sheep-rk3368_defconfig b/configs/sheep-rk3368_defconfig
index cff1905..4883f59 100644
--- a/configs/sheep-rk3368_defconfig
+++ b/configs/sheep-rk3368_defconfig
@@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
-CONFIG_SYS_MALLOC_F_LEN=0x1000
CONFIG_ROCKCHIP_RK3368=y
CONFIG_TARGET_SHEEP=y
CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/sifive_fu540_defconfig b/configs/sifive_fu540_defconfig
index f784123..f192037 100644
--- a/configs/sifive_fu540_defconfig
+++ b/configs/sifive_fu540_defconfig
@@ -7,4 +7,5 @@
CONFIG_FIT=y
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_MISC_INIT_R=y
CONFIG_OF_PRIOR_STAGE=y
diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
index adf7b61..27b8525 100644
--- a/configs/stm32mp15_basic_defconfig
+++ b/configs/stm32mp15_basic_defconfig
@@ -101,6 +101,9 @@
CONFIG_DM_REGULATOR_GPIO=y
CONFIG_DM_REGULATOR_STM32_VREFBUF=y
CONFIG_DM_REGULATOR_STPMIC1=y
+CONFIG_REMOTEPROC_STM32_COPRO=y
+CONFIG_DM_RTC=y
+CONFIG_RTC_STM32=y
CONFIG_SERIAL_RX_BUFFER=y
CONFIG_STM32_SERIAL=y
CONFIG_SPI=y
diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig
index a205f47..0565e5e 100644
--- a/configs/stm32mp15_optee_defconfig
+++ b/configs/stm32mp15_optee_defconfig
@@ -88,6 +88,9 @@
CONFIG_DM_REGULATOR_GPIO=y
CONFIG_DM_REGULATOR_STM32_VREFBUF=y
CONFIG_DM_REGULATOR_STPMIC1=y
+CONFIG_REMOTEPROC_STM32_COPRO=y
+CONFIG_DM_RTC=y
+CONFIG_RTC_STM32=y
CONFIG_SERIAL_RX_BUFFER=y
CONFIG_STM32_SERIAL=y
CONFIG_SPI=y
diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
index cdb4d95..844cbcd 100644
--- a/configs/stm32mp15_trusted_defconfig
+++ b/configs/stm32mp15_trusted_defconfig
@@ -87,6 +87,9 @@
CONFIG_DM_REGULATOR_GPIO=y
CONFIG_DM_REGULATOR_STM32_VREFBUF=y
CONFIG_DM_REGULATOR_STPMIC1=y
+CONFIG_REMOTEPROC_STM32_COPRO=y
+CONFIG_DM_RTC=y
+CONFIG_RTC_STM32=y
CONFIG_SERIAL_RX_BUFFER=y
CONFIG_STM32_SERIAL=y
CONFIG_SPI=y
diff --git a/configs/ti816x_evm_defconfig b/configs/ti816x_evm_defconfig
index 19519f8..d341633 100644
--- a/configs/ti816x_evm_defconfig
+++ b/configs/ti816x_evm_defconfig
@@ -47,6 +47,7 @@
CONFIG_MMC_OMAP_HS=y
CONFIG_NAND=y
CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
+CONFIG_DM_ETH=y
CONFIG_MII=y
CONFIG_DRIVER_TI_EMAC=y
CONFIG_SYS_NS16550=y
diff --git a/configs/tinker-rk3288_defconfig b/configs/tinker-rk3288_defconfig
index 482ee7d..b234539 100644
--- a/configs/tinker-rk3288_defconfig
+++ b/configs/tinker-rk3288_defconfig
@@ -1,9 +1,7 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x01000000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
-CONFIG_TPL_LDSCRIPT="arch/arm/mach-rockchip/u-boot-tpl.lds"
CONFIG_TARGET_TINKER_RK3288=y
CONFIG_NR_DRAM_BANKS=1
CONFIG_SPL_SIZE_LIMIT=307200
diff --git a/configs/vyasa-rk3288_defconfig b/configs/vyasa-rk3288_defconfig
index 1108c6a..eaea625 100644
--- a/configs/vyasa-rk3288_defconfig
+++ b/configs/vyasa-rk3288_defconfig
@@ -3,7 +3,6 @@
# CONFIG_SPL_USE_ARCH_MEMSET is not set
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00100000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RK3288=y
CONFIG_TARGET_VYASA_RK3288=y
CONFIG_NR_DRAM_BANKS=1
diff --git a/disk/part.c b/disk/part.c
index f14bc22..7e84214 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -674,6 +674,74 @@
return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
}
+/**
+ * Get partition info from device number and partition name.
+ *
+ * Parse a device number and partition name string in the form of
+ * "device_num#partition_name", for example "0#misc". If the partition
+ * is found, sets dev_desc and part_info accordingly with the information
+ * of the partition with the given partition_name.
+ *
+ * @param[in] dev_iface Device interface
+ * @param[in] dev_part_str Input string argument, like "0#misc"
+ * @param[out] dev_desc Place to store the device description pointer
+ * @param[out] part_info Place to store the partition information
+ * @return 0 on success, or a negative on error
+ */
+static int part_get_info_by_dev_and_name(const char *dev_iface,
+ const char *dev_part_str,
+ struct blk_desc **dev_desc,
+ disk_partition_t *part_info)
+{
+ char *ep;
+ const char *part_str;
+ int dev_num;
+
+ part_str = strchr(dev_part_str, '#');
+ if (!part_str || part_str == dev_part_str)
+ return -EINVAL;
+
+ dev_num = simple_strtoul(dev_part_str, &ep, 16);
+ if (ep != part_str) {
+ /* Not all the first part before the # was parsed. */
+ return -EINVAL;
+ }
+ part_str++;
+
+ *dev_desc = blk_get_dev(dev_iface, dev_num);
+ if (!*dev_desc) {
+ printf("Could not find %s %d\n", dev_iface, dev_num);
+ return -EINVAL;
+ }
+ if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) {
+ printf("Could not find \"%s\" partition\n", part_str);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
+ const char *dev_part_str,
+ struct blk_desc **dev_desc,
+ disk_partition_t *part_info)
+{
+ /* Split the part_name if passed as "$dev_num#part_name". */
+ if (!part_get_info_by_dev_and_name(dev_iface, dev_part_str,
+ dev_desc, part_info))
+ return 0;
+ /*
+ * Couldn't lookup by name, try looking up the partition description
+ * directly.
+ */
+ if (blk_get_device_part_str(dev_iface, dev_part_str,
+ dev_desc, part_info, 1) < 0) {
+ printf("Couldn't find partition %s %s\n",
+ dev_iface, dev_part_str);
+ return -EINVAL;
+ }
+ return 0;
+}
+
void part_set_generic_name(const struct blk_desc *dev_desc,
int part_num, char *name)
{
diff --git a/disk/part_dos.c b/disk/part_dos.c
index 936cee0..aae9d95 100644
--- a/disk/part_dos.c
+++ b/disk/part_dos.c
@@ -23,6 +23,10 @@
#define DOS_PART_DEFAULT_SECTOR 512
+/* should this be configurable? It looks like it's not very common at all
+ * to use large numbers of partitions */
+#define MAX_EXT_PARTS 256
+
/* Convert char[4] in little endian format to the host format integer
*/
static inline unsigned int le32_to_int(unsigned char *le32)
@@ -126,6 +130,13 @@
dos_partition_t *pt;
int i;
+ /* set a maximum recursion level */
+ if (part_num > MAX_EXT_PARTS)
+ {
+ printf("** Nested DOS partitions detected, stopping **\n");
+ return;
+ }
+
if (blk_dread(dev_desc, ext_part_sector, 1, (ulong *)buffer) != 1) {
printf ("** Can't read partition table on %d:" LBAFU " **\n",
dev_desc->devnum, ext_part_sector);
@@ -191,6 +202,13 @@
int i;
int dos_type;
+ /* set a maximum recursion level */
+ if (part_num > MAX_EXT_PARTS)
+ {
+ printf("** Nested DOS partitions detected, stopping **\n");
+ return -1;
+ }
+
if (blk_dread(dev_desc, ext_part_sector, 1, (ulong *)buffer) != 1) {
printf ("** Can't read partition table on %d:" LBAFU " **\n",
dev_desc->devnum, ext_part_sector);
diff --git a/disk/part_efi.c b/disk/part_efi.c
index 3e02669..359b55a8 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -670,9 +670,18 @@
return ret;
}
-static void gpt_convert_efi_name_to_char(char *s, efi_char16_t *es, int n)
+/**
+ * gpt_convert_efi_name_to_char() - convert u16 string to char string
+ *
+ * TODO: this conversion only supports ANSI characters
+ *
+ * @s: target buffer
+ * @es: u16 string to be converted
+ * @n: size of target buffer
+ */
+static void gpt_convert_efi_name_to_char(char *s, void *es, int n)
{
- char *ess = (char *)es;
+ char *ess = es;
int i, j;
memset(s, '\0', n);
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..53752db
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1 @@
+output
diff --git a/doc/README.AX25 b/doc/README.AX25
deleted file mode 100644
index 7a607dd..0000000
--- a/doc/README.AX25
+++ /dev/null
@@ -1,46 +0,0 @@
-AX25 is Andes CPU IP to adopt RISC-V architecture.
-
-Features
-========
-
-CPU Core
- - 5-stage in-order execution pipeline
- - Hardware Multiplier
- - radix-2/radix-4/radix-16/radix-256/fast
- - Hardware Divider
- - Optional branch prediction
- - Machine mode and optional user mode
- - Optional performance monitoring
-
-ISA
- - RV64I base integer instructions
- - RVC for 16-bit compressed instructions
- - RVM for multiplication and division instructions
-
-Memory subsystem
- - I & D local memory
- - Size: 4KB to 16MB
- - Memory subsyetem soft-error protection
- - Protection scheme: parity-checking or error-checking-and-correction (ECC)
- - Automatic hardware error correction
-
-Bus
- - Interface Protocol
- - Synchronous AHB (32-bit/64-bit data-width), or
- - Synchronous AXI4 (64-bit data-width)
-
-Power management
- - Wait for interrupt (WFI) mode
-
-Debug
- - Configurable number of breakpoints: 2/4/8
- - External Debug Module
- - AHB slave port
- - External JTAG debug transport module
-
-Platform Level Interrupt Controller (PLIC)
- - AHB slave port
- - Configurable number of interrupts: 1-1023
- - Configurable number of interrupt priorities: 3/7/15/63/127/255
- - Configurable number of targets: 1-16
- - Preempted interrupt priority stack
diff --git a/doc/README.N1213 b/doc/README.N1213
deleted file mode 100644
index e107166..0000000
--- a/doc/README.N1213
+++ /dev/null
@@ -1,55 +0,0 @@
-N1213 is a configurable hard/soft core of NDS32's N12 CPU family.
-
-Features
-========
-
-CPU Core
- - 16-/32-bit mixable instruction format.
- - 32 general-purpose 32-bit registers.
- - 8-stage pipeline.
- - Dynamic branch prediction.
- - 32/64/128/256 BTB.
- - Return address stack (RAS).
- - Vector interrupts for internal/external.
- interrupt controller with 6 hardware interrupt signals.
- - 3 HW-level nested interruptions.
- - User and super-user mode support.
- - Memory-mapped I/O.
- - Address space up to 4GB.
-
-Memory Management Unit
- - TLB
- - 4/8-entry fully associative iTLB/dTLB.
- - 32/64/128-entry 4-way set-associati.ve main TLB.
- - TLB locking support
- - Optional hardware page table walker.
- - Two groups of page size support.
- - 4KB & 1MB.
- - 8KB & 1MB.
-
-Memory Subsystem
- - I & D cache.
- - Virtually indexed and physically tagged.
- - Cache size: 8KB/16KB/32KB/64KB.
- - Cache line size: 16B/32B.
- - Set associativity: 2-way, 4-way or direct-mapped.
- - Cache locking support.
- - I & D local memory (LM).
- - Size: 4KB to 1MB.
- - Bank numbers: 1 or 2.
- - Optional 1D/2D DMA engine.
- - Internal or external to CPU core.
-
-Bus Interface
- - Synchronous/Asynchronous AHB bus: 0, 1 or 2 ports.
- - Synchronous High speed memory port.
- (HSMP): 0, 1 or 2 ports.
-
-Debug
- - JTAG debug interface.
- - Embedded debug module (EDM).
- - Optional embedded program tracer interface.
-
-Miscellaneous
- - Programmable data endian control.
- - Performance monitoring mechanism.
diff --git a/doc/README.NDS32 b/doc/README.NDS32
deleted file mode 100644
index b2b58fc..0000000
--- a/doc/README.NDS32
+++ /dev/null
@@ -1,41 +0,0 @@
-NDS32 is a new high-performance 32-bit RISC microprocessor core.
-
-http://www.andestech.com/
-
-AndeStar ISA
-============
-AndeStar is a patent-pending 16-bit/32-bit mixed-length instruction set to
-achieve optimal system performance, code density, and power efficiency.
-
-It contains the following features:
- - Intermixable 32-bit and 16-bit instruction sets without the need for
- mode switch.
- - 16-bit instructions as a frequently used subset of 32-bit instructions.
- - RISC-style register-based instruction set.
- - 32 32-bit General Purpose Registers (GPR).
- - Upto 1024 User Special Registers (USR) for existing and extension
- instructions.
- - Rich load/store instructions for...
- - Single memory access with base address update.
- - Multiple aligned and unaligned memory accesses for memory copy and stack
- operations.
- - Data prefetch to improve data cache performance.
- - Non-bus locking synchronization instructions.
- - PC relative jump and PC read instructions for efficient position independent
- code.
- - Multiply-add and multiple-sub with 64-bit accumulator.
- - Instruction for efficient power management.
- - Bi-endian support.
- - Three instruction extension space for application acceleration:
- - Performance extension.
- - Andes future extensions (for floating-point, multimedia, etc.)
- - Customer extensions.
-
-AndesCore CPU
-=============
-Andes Technology has 4 families of CPU cores: N12, N10, N9, N8.
-
-For details about N12 CPU family, please check doc/README.N1213.
-
-The NDS32 ports of u-boot, the Linux kernel, the GNU toolchain and
-other associated software are actively supported by Andes Technology Corporation.
diff --git a/doc/README.ae350 b/doc/README.ae350
deleted file mode 100644
index 189a6b7..0000000
--- a/doc/README.ae350
+++ /dev/null
@@ -1,275 +0,0 @@
-Andes Technology SoC AE350
-===========================
-
-AE350 is the mainline SoC produced by Andes Technology using AX25 CPU core
-base on RISC-V architecture.
-
-AE350 has integrated both AHB and APB bus and many periphals for application
-and product development.
-
-AX25-AE350
-=========
-
-AX25-AE350 is the SoC with AE350 hardcore CPU.
-
-Configurations
-==============
-
-CONFIG_SKIP_LOWLEVEL_INIT:
- If you want to boot this system from SPI ROM and bypass e-bios (the
- other boot loader on ROM). You should undefine CONFIG_SKIP_LOWLEVEL_INIT
- in "include/configs/ax25-ae350.h".
-
-Build and boot steps
-====================
-
-build:
-1. Prepare the toolchains and make sure the $PATH to toolchains is correct.
-2. Use `make ae350_rv[32|64]_defconfig` in u-boot root to build the image for 32 or 64 bit.
-
-Verification
-====================
-
-Target
-====================
-1. startup
-2. relocation
-3. timer driver
-4. uart driver
-5. mac driver
-6. mmc driver
-7. spi driver
-
-Steps
-====================
-1. Define CONFIG_SKIP_LOWLEVEL_INIT to build u-boot which is loaded via gdb from ram.
-2. Undefine CONFIG_SKIP_LOWLEVEL_INIT to build u-boot which is booted from spi rom.
-3. Ping a server by mac driver
-4. Scan sd card and copy u-boot image which is booted from flash to ram by sd driver.
-5. Burn this u-boot image to spi rom by spi driver
-6. Re-boot u-boot from spi flash with power off and power on.
-
-Messages of U-Boot boot on AE350 board
-======================================
-U-Boot 2018.01-rc2-00033-g824f89a (Dec 21 2017 - 16:51:26 +0800)
-
-DRAM: 1 GiB
-MMC: mmc@f0e00000: 0
-SF: Detected mx25u1635e with page size 256 Bytes, erase size 4 KiB, total 2 MiB
-In: serial@f0300000
-Out: serial@f0300000
-Err: serial@f0300000
-Net:
-Warning: mac@e0100000 (eth0) using random MAC address - be:dd:d7:e4:e8:10
-eth0: mac@e0100000
-
-RISC-V # version
-U-Boot 2018.01-rc2-00033-gb265b91-dirty (Dec 22 2017 - 13:54:21 +0800)
-
-riscv32-unknown-linux-gnu-gcc (GCC) 7.2.0
-GNU ld (GNU Binutils) 2.29
-
-RISC-V # setenv ipaddr 10.0.4.200 ;
-RISC-V # setenv serverip 10.0.4.97 ;
-RISC-V # ping 10.0.4.97 ;
-Using mac@e0100000 device
-host 10.0.4.97 is alive
-
-RISC-V # mmc rescan
-RISC-V # fatls mmc 0:1
- 318907 u-boot-ae350-64.bin
- 1252 hello_world_ae350_32.bin
- 328787 u-boot-ae350-32.bin
-
-3 file(s), 0 dir(s)
-
-RISC-V # sf probe 0:0 50000000 0
-SF: Detected mx25u1635e with page size 256 Bytes, erase size 4 KiB, total 2 MiB
-
-RISC-V # sf test 0x100000 0x1000
-SPI flash test:
-0 erase: 36 ticks, 111 KiB/s 0.888 Mbps
-1 check: 29 ticks, 137 KiB/s 1.096 Mbps
-2 write: 40 ticks, 100 KiB/s 0.800 Mbps
-3 read: 20 ticks, 200 KiB/s 1.600 Mbps
-Test passed
-0 erase: 36 ticks, 111 KiB/s 0.888 Mbps
-1 check: 29 ticks, 137 KiB/s 1.096 Mbps
-2 write: 40 ticks, 100 KiB/s 0.800 Mbps
-3 read: 20 ticks, 200 KiB/s 1.600 Mbps
-
-RISC-V # fatload mmc 0:1 0x600000 u-boot-ae350-32.bin
-reading u-boot-ae350-32.bin
-328787 bytes read in 324 ms (990.2 KiB/s)
-
-RISC-V # sf erase 0x0 0x51000
-SF: 331776 bytes @ 0x0 Erased: OK
-
-RISC-V # sf write 0x600000 0x0 0x50453
-device 0 offset 0x0, size 0x50453
-SF: 328787 bytes @ 0x0 Written: OK
-
-RISC-V # crc32 0x600000 0x50453
-crc32 for 00600000 ... 00650452 ==> 692dc44a
-
-RISC-V # crc32 0x80000000 0x50453
-crc32 for 80000000 ... 80050452 ==> 692dc44a
-RISC-V #
-
-*** power-off and power-on, this U-Boot is booted from spi flash ***
-
-U-Boot 2018.01-rc2-00032-gf67dd47-dirty (Dec 21 2017 - 13:56:03 +0800)
-
-DRAM: 1 GiB
-MMC: mmc@f0e00000: 0
-SF: Detected mx25u1635e with page size 256 Bytes, erase size 4 KiB, total 2 MiB
-In: serial@f0300000
-Out: serial@f0300000
-Err: serial@f0300000
-Net:
-Warning: mac@e0100000 (eth0) using random MAC address - ee:4c:58:29:32:f5
-eth0: mac@e0100000
-RISC-V #
-
-
-Boot bbl and riscv-linux via U-Boot on QEMU
-===========================================
-1. Build riscv-linux
-2. Build bbl and riscv-linux with --with-payload
-3. Prepare ae350.dtb
-4. Creating OS-kernel images
- ./mkimage -A riscv -O linux -T kernel -C none -a 0x0000 -e 0x0000 -d bbl.bin bootmImage-bbl.bin
- Image Name:
- Created: Tue Mar 13 10:06:42 2018
- Image Type: RISC-V Linux Kernel Image (uncompressed)
- Data Size: 17901204 Bytes = 17481.64 KiB = 17.07 MiB
- Load Address: 00000000
- Entry Point: 00000000
-
-4. Copy bootmImage-bbl.bin and ae350.dtb to qemu sd card image
-5. Message of booting riscv-linux from bbl via u-boot on qemu
-
-U-Boot 2018.03-rc4-00031-g2631273 (Mar 13 2018 - 15:02:55 +0800)
-
-DRAM: 1 GiB
-main-loop: WARNING: I/O thread spun for 1000 iterations
-MMC: mmc@f0e00000: 0
-Loading Environment from SPI Flash... *** Warning - spi_flash_probe_bus_cs() failed, using default environment
-
-Failed (-22)
-In: serial@f0300000
-Out: serial@f0300000
-Err: serial@f0300000
-Net:
-Warning: mac@e0100000 (eth0) using random MAC address - 02:00:00:00:00:00
-eth0: mac@e0100000
-RISC-V # mmc rescan
-RISC-V # mmc part
-
-Partition Map for MMC device 0 -- Partition Type: DOS
-
-Part Start Sector Num Sectors UUID Type
-RISC-V # fatls mmc 0:0
- 17901268 bootmImage-bbl.bin
- 1954 ae2xx.dtb
-
-2 file(s), 0 dir(s)
-
-RISC-V # fatload mmc 0:0 0x00600000 bootmImage-bbl.bin
-17901268 bytes read in 4642 ms (3.7 MiB/s)
-RISC-V # fatload mmc 0:0 0x2000000 ae350.dtb
-1954 bytes read in 1 ms (1.9 MiB/s)
-RISC-V # setenv bootm_size 0x2000000
-RISC-V # setenv fdt_high 0x1f00000
-RISC-V # bootm 0x00600000 - 0x2000000
-## Booting kernel from Legacy Image at 00600000 ...
- Image Name:
- Image Type: RISC-V Linux Kernel Image (uncompressed)
- Data Size: 17901204 Bytes = 17.1 MiB
- Load Address: 00000000
- Entry Point: 00000000
- Verifying Checksum ... OK
-## Flattened Device Tree blob at 02000000
- Booting using the fdt blob at 0x2000000
- Loading Kernel Image ... OK
- Loading Device Tree to 0000000001efc000, end 0000000001eff7a1 ... OK
-[ 0.000000] OF: fdt: Ignoring memory range 0x0 - 0x200000
-[ 0.000000] Linux version 4.14.0-00046-gf3e439f-dirty (rick@atcsqa06) (gcc version 7.1.1 20170509 (GCC)) #1 Tue Jan 9 16:34:25 CST 2018
-[ 0.000000] bootconsole [early0] enabled
-[ 0.000000] Initial ramdisk at: 0xffffffe000016a98 (12267008 bytes)
-[ 0.000000] Zone ranges:
-[ 0.000000] DMA [mem 0x0000000000200000-0x000000007fffffff]
-[ 0.000000] Normal empty
-[ 0.000000] Movable zone start for each node
-[ 0.000000] Early memory node ranges
-[ 0.000000] node 0: [mem 0x0000000000200000-0x000000007fffffff]
-[ 0.000000] Initmem setup node 0 [mem 0x0000000000200000-0x000000007fffffff]
-[ 0.000000] elf_hwcap is 0x112d
-[ 0.000000] random: fast init done
-[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 516615
-[ 0.000000] Kernel command line: console=ttyS0,38400n8 earlyprintk=uart8250-32bit,0xf0300000 debug loglevel=7
-[ 0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
-[ 0.000000] Dentry cache hash table entries: 262144 (order: 9, 2097152 bytes)
-[ 0.000000] Inode-cache hash table entries: 131072 (order: 8, 1048576 bytes)
-[ 0.000000] Sorting __ex_table...
-[ 0.000000] Memory: 2047832K/2095104K available (1856K kernel code, 204K rwdata, 532K rodata, 12076K init, 756K bss, 47272K reserved, 0K cma-reserved)
-[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
-[ 0.000000] NR_IRQS: 0, nr_irqs: 0, preallocated irqs: 0
-[ 0.000000] riscv,cpu_intc,0: 64 local interrupts mapped
-[ 0.000000] riscv,plic0,e4000000: mapped 31 interrupts to 1/2 handlers
-[ 0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x24e6a1710, max_idle_ns: 440795202120 ns
-[ 0.000000] Calibrating delay loop (skipped), value calculated using timer frequency.. 20.00 BogoMIPS (lpj=40000)
-[ 0.000000] pid_max: default: 32768 minimum: 301
-[ 0.004000] Mount-cache hash table entries: 4096 (order: 3, 32768 bytes)
-[ 0.004000] Mountpoint-cache hash table entries: 4096 (order: 3, 32768 bytes)
-[ 0.056000] devtmpfs: initialized
-[ 0.060000] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
-[ 0.064000] futex hash table entries: 256 (order: 0, 6144 bytes)
-[ 0.068000] NET: Registered protocol family 16
-[ 0.080000] vgaarb: loaded
-[ 0.084000] clocksource: Switched to clocksource riscv_clocksource
-[ 0.088000] NET: Registered protocol family 2
-[ 0.092000] TCP established hash table entries: 16384 (order: 5, 131072 bytes)
-[ 0.096000] TCP bind hash table entries: 16384 (order: 5, 131072 bytes)
-[ 0.096000] TCP: Hash tables configured (established 16384 bind 16384)
-[ 0.100000] UDP hash table entries: 1024 (order: 3, 32768 bytes)
-[ 0.100000] UDP-Lite hash table entries: 1024 (order: 3, 32768 bytes)
-[ 0.104000] NET: Registered protocol family 1
-[ 0.616000] Unpacking initramfs...
-[ 1.220000] workingset: timestamp_bits=62 max_order=19 bucket_order=0
-[ 1.244000] io scheduler noop registered
-[ 1.244000] io scheduler cfq registered (default)
-[ 1.244000] io scheduler mq-deadline registered
-[ 1.248000] io scheduler kyber registered
-[ 1.360000] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
-[ 1.368000] console [ttyS0] disabled
-[ 1.372000] f0300000.serial: ttyS0 at MMIO 0xf0300020 (irq = 10, base_baud = 1228800) is a 16550A
-[ 1.392000] console [ttyS0] enabled
-[ 1.392000] ftmac100: Loading version 0.2 ...
-[ 1.396000] ftmac100 e0100000.mac eth0: irq 8, mapped at ffffffd002005000
-[ 1.400000] ftmac100 e0100000.mac eth0: generated random MAC address 6e:ac:c3:92:36:c0
-[ 1.404000] IR NEC protocol handler initialized
-[ 1.404000] IR RC5(x/sz) protocol handler initialized
-[ 1.404000] IR RC6 protocol handler initialized
-[ 1.404000] IR JVC protocol handler initialized
-[ 1.408000] IR Sony protocol handler initialized
-[ 1.408000] IR SANYO protocol handler initialized
-[ 1.408000] IR Sharp protocol handler initialized
-[ 1.408000] IR MCE Keyboard/mouse protocol handler initialized
-[ 1.412000] IR XMP protocol handler initialized
-[ 1.456000] ftsdc010 f0e00000.mmc: mmc0 - using hw SDIO IRQ
-[ 1.464000] bootconsole [early0] uses init memory and must be disabled even before the real one is ready
-[ 1.464000] bootconsole [early0] disabled
-[ 1.508000] Freeing unused kernel memory: 12076K
-[ 1.512000] This architecture does not have kernel memory protection.
-[ 1.520000] mmc0: new SD card at address 4567
-[ 1.524000] mmcblk0: mmc0:4567 QEMU! 20.0 MiB
-[ 1.844000] mmcblk0:
-Wed Dec 1 10:00:00 CST 2010
-/ #
-
-
-
-TODO
-==================================================
-Boot bbl and riscv-linux via U-Boot on AE350 board
diff --git a/doc/README.at91 b/doc/README.at91
deleted file mode 100644
index 39dd563..0000000
--- a/doc/README.at91
+++ /dev/null
@@ -1,174 +0,0 @@
-Atmel AT91 Evaluation kits
-
-Index
- - I. Board mapping & boot media
- - II. NAND partition table
- - III. watchdog support
-
-I. Board mapping & boot media
-------------------------------------------------------------------------------
-AT91SAM9260EK, AT91SAM9G20EK & AT91SAM9XEEK
-------------------------------------------------------------------------------
-
-Memory map
- 0x20000000 - 23FFFFFF SDRAM (64 MB)
- 0xC0000000 - Cxxxxxxx Atmel Dataflash card (J13)
- 0xD0000000 - D07FFFFF Soldered Atmel Dataflash (AT45DB642)
-
-Environment variables
-
- U-Boot environment variables can be stored at different places:
- - Dataflash on SPI chip select 1 (default)
- - Dataflash on SPI chip select 0 (dataflash card)
- - Nand flash.
-
- You can choose your storage location at config step (here for at91sam9260ek) :
- make at91sam9260ek_nandflash_config - use nand flash
- make at91sam9260ek_dataflash_cs0_config - use data flash (spi cs0)
- make at91sam9260ek_dataflash_cs1_config - use data flash (spi cs1)
-
-
-------------------------------------------------------------------------------
-AT91SAM9261EK, AT91SAM9G10EK
-------------------------------------------------------------------------------
-
-Memory map
- 0x20000000 - 23FFFFFF SDRAM (64 MB)
- 0xC0000000 - C07FFFFF Soldered Atmel Dataflash (AT45DB642)
- 0xD0000000 - Dxxxxxxx Atmel Dataflash card (J22)
-
-Environment variables
-
- U-Boot environment variables can be stored at different places:
- - Dataflash on SPI chip select 0 (default)
- - Dataflash on SPI chip select 3 (dataflash card)
- - Nand flash.
-
- You can choose your storage location at config step (here for at91sam9260ek) :
- make at91sam9261ek_nandflash_config - use nand flash
- make at91sam9261ek_dataflash_cs0_config - use data flash (spi cs0)
- make at91sam9261ek_dataflash_cs3_config - use data flash (spi cs3)
-
-
-------------------------------------------------------------------------------
-AT91SAM9263EK
-------------------------------------------------------------------------------
-
-Memory map
- 0x20000000 - 23FFFFFF SDRAM (64 MB)
- 0xC0000000 - Cxxxxxxx Atmel Dataflash card (J9)
-
-Environment variables
-
- U-Boot environment variables can be stored at different places:
- - Dataflash on SPI chip select 0 (dataflash card)
- - Nand flash.
- - Nor flash (not populate by default)
-
- You can choose your storage location at config step (here for at91sam9260ek) :
- make at91sam9263ek_nandflash_config - use nand flash
- make at91sam9263ek_dataflash_cs0_config - use data flash (spi cs0)
- make at91sam9263ek_norflash_config - use nor flash
-
- You can choose to boot directly from U-Boot at config step
- make at91sam9263ek_norflash_boot_config - boot from nor flash
-
-
-------------------------------------------------------------------------------
-AT91SAM9M10G45EK
-------------------------------------------------------------------------------
-
-Memory map
- 0x70000000 - 77FFFFFF SDRAM (128 MB)
-
-Environment variables
-
- U-Boot environment variables can be stored at different places:
- - Nand flash.
-
- You can choose your storage location at config step (here for at91sam9m10g45ek) :
- make at91sam9m10g45ek_nandflash_config - use nand flash
-
-
-------------------------------------------------------------------------------
-AT91SAM9RLEK
-------------------------------------------------------------------------------
-
-Memory map
- 0x20000000 - 23FFFFFF SDRAM (64 MB)
- 0xC0000000 - C07FFFFF Soldered Atmel Dataflash (AT45DB642)
-
-Environment variables
-
- U-Boot environment variables can be stored at different places:
- - Dataflash on SPI chip select 0
- - Nand flash.
-
- You can choose your storage location at config step (here for at91sam9rlek) :
- make at91sam9rlek_nandflash_config - use nand flash
-
-
-------------------------------------------------------------------------------
-AT91SAM9N12EK, AT91SAM9X5EK
-------------------------------------------------------------------------------
-
-Memory map
- 0x20000000 - 27FFFFFF SDRAM (128 MB)
-
-Environment variables
-
- U-Boot environment variables can be stored at different places:
- - Nand flash.
- - SD/MMC card
- - Serialflash/Dataflash on SPI chip select 0
-
- You can choose your storage location at config step (here for at91sam9x5ek) :
- make at91sam9x5ek_dataflash_config - use data flash
- make at91sam9x5ek_mmc_config - use sd/mmc card
- make at91sam9x5ek_nandflash_config - use nand flash
- make at91sam9x5ek_spiflash_config - use serial flash
-
-
-------------------------------------------------------------------------------
-SAMA5D3XEK
-------------------------------------------------------------------------------
-
-Memory map
- 0x20000000 - 3FFFFFFF SDRAM (512 MB)
-
-Environment variables
-
- U-Boot environment variables can be stored at different places:
- - Nand flash.
- - SD/MMC card
- - Serialflash on SPI chip select 0
-
- You can choose your storage location at config step (here for sama5d3xek) :
- make sama5d3xek_mmc_config - use SD/MMC card
- make sama5d3xek_nandflash_config - use nand flash
- make sama5d3xek_serialflash_config - use serial flash
-
-
-II. NAND partition table
-
- All the board support boot from NAND flash will use the following NAND
- partition table
-
- 0x00000000 - 0x0003FFFF bootstrap (256 KiB)
- 0x00040000 - 0x000BFFFF u-boot (512 KiB)
- 0x000C0000 - 0x000FFFFF env (256 KiB)
- 0x00100000 - 0x0013FFFF env_redundant (256 KiB)
- 0x00140000 - 0x0017FFFF spare (256 KiB)
- 0x00180000 - 0x001FFFFF dtb (512 KiB)
- 0x00200000 - 0x007FFFFF kernel (6 MiB)
- 0x00800000 - 0xxxxxxxxx rootfs (All left)
-
-III. Watchdog support
-
- For security reasons, the at91 watchdog is running at boot time and,
- if deactivated, cannot be used anymore.
- If you want to use the watchdog, you will need to keep it running in
- your code (make sure not to disable it in AT91Bootstrap for instance).
-
- In the U-Boot configuration, the AT91 watchdog support is enabled using
- the CONFIG_WDT and CONFIG_WDT_AT91 options.
diff --git a/doc/README.b4860qds b/doc/README.b4860qds
deleted file mode 100644
index 889c8a9..0000000
--- a/doc/README.b4860qds
+++ /dev/null
@@ -1,366 +0,0 @@
-Overview
---------
-The B4860QDS is a Freescale reference board that hosts the B4860 SoC (and variants).
-
-B4860 Overview
--------------
-The B4860 QorIQ Qonverge device is a Freescale high-end, multicore SoC based on
-StarCore and Power Architecture® cores. It targets the broadband wireless
-infrastructure and builds upon the proven success of the existing multicore
-DSPs and Power CPUs. It is designed to bolster the rapidly changing and
-expanding wireless markets, such as 3GLTE (FDD and TDD), LTE-Advanced, and UMTS.
-
-The B4860 is a highly-integrated StarCore and Power Architecture processor that
-contains:
-. Six fully-programmable StarCore SC3900 FVP subsystems, divided into three
-clusters-each core runs up to 1.2 GHz, with an architecture highly optimized for
-wireless base station applications
-. Four dual-thread e6500 Power Architecture processors organized in one cluster-each
-core runs up to 1.8 GHz
-. Two DDR3/3L controllers for high-speed, industry-standard memory interface each
-runs at up to 1866.67 MHz
-. MAPLE-B3 hardware acceleration-for forward error correction schemes including
-Turbo or Viterbi decoding, Turbo encoding and rate matching, MIMO MMSE
-equalization scheme, matrix operations, CRC insertion and check, DFT/iDFT and
-FFT/iFFT calculations, PUSCH/PDSCH acceleration, and UMTS chip rate
-acceleration
-. CoreNet fabric that fully supports coherency using MESI protocol between the
- e6500 cores, SC3900 FVP cores, memories and external interfaces.
- CoreNet fabric interconnect runs at 667 MHz and supports coherent and
- non-coherent out of order transactions with prioritization and bandwidth
- allocation amongst CoreNet endpoints.
-. Data Path Acceleration Architecture, which includes the following:
-. Frame Manager (FMan), which supports in-line packet parsing and general
- classification to enable policing and QoS-based packet distribution
-. Queue Manager (QMan) and Buffer Manager (BMan), which allow offloading
- of queue management, task management, load distribution, flow ordering, buffer
- management, and allocation tasks from the cores
-. Security engine (SEC 5.3)-crypto-acceleration for protocols such as IPsec,
- SSL, and 802.16
-. RapidIO manager (RMAN) - Support SRIO types 8, 9, 10, and 11 (inbound and
- outbound). Supports types 5, 6 (outbound only)
-. Large internal cache memory with snooping and stashing capabilities for
- bandwidth saving and high utilization of processor elements. The 9856-Kbyte
- internal memory space includes the following:
-. 32 Kbyte L1 ICache per e6500/SC3900 core
-. 32 Kbyte L1 DCache per e6500/SC3900 core
-. 2048 Kbyte unified L2 cache for each SC3900 FVP cluster
-. 2048 Kbyte unified L2 cache for the e6500 cluster
-. Two 512 Kbyte shared L3 CoreNet platform caches (CPC)
-. Sixteen 10-GHz SerDes lanes serving:
-. Two Serial RapidIO interfaces.
- - Each supports up to 4 lanes and a total of up to 8 lanes
-. Up to 8-lanes Common Public Radio Interface (CPRI) controller for glue-less
- antenna connection
-. Two 10-Gbit Ethernet controllers (10GEC)
-. Six 1G/2.5-Gbit Ethernet controllers for network communications
-. PCI Express controller
-. Debug (Aurora)
-. Two OCeaN DMAs
-. Various system peripherals
-. 182 32-bit timers
-
-B4860QDS Overview
-------------------
-- DDRC1: Ten separate DDR3 parts of 16-bit to support 72-bit (ECC) at 1866MT/s, ECC, 4 GB
- of memory in two ranks of 2 GB.
-- DDRC2: Five separate DDR3 parts of 16-bit to support 72-bit (ECC) at 1866MT/s, ECC, 2 GB
- of memory. Single rank.
-- SerDes 1 multiplexing: Two Vitesse (transmit and receive path) cross-point 16x16 switch
- VSC3316
-- SerDes 2 multiplexing: Two Vitesse (transmit and receive path) cross-point 8x8 switch VSC3308
-- USB 2.0 ULPI PHY USB3315 by SMSC supports USB port in host mode.
- B4860 UART port is available over USB-to-UART translator USB2SER or over RS232 flat cable.
-- A Vitesse dual SGMII phy VSC8662 links the B4860 SGMII lines to 2xRJ-45 copper connectors
- for Stand-alone mode and to the 1000Base-X over AMC MicroTCA connector ports 0 and 2 for
- AMC mode.
-- The B4860 configuration may be loaded from nine bits coded reset configuration reset source. The
- RCW source is set by appropriate DIP-switches:
-- 16-bit NOR Flash / PROMJet
-- QIXIS 8-bit NOR Flash Emulator
-- 8-bit NAND Flash
-- 24-bit SPI Flash
-- Long address I2C EEPROM
-- Available debug interfaces are:
- - On-board eCWTAP controller with ETH and USB I/F
- - JTAG/COP 16-pin header for any external TAP controller
- - External JTAG source over AMC to support B2B configuration
- - 70-pin Aurora debug connector
-- QIXIS (FPGA) logic:
- - 2 KB internal memory space including
-- IDT840NT4 clock synthesizer provides B4860 essential clocks : SYSCLK, DDRCLK1,2 and
- RTCCLK.
-- Two 8T49N222A SerDes ref clock devices support two SerDes port clock frequency - total four
- refclk, including CPRI clock scheme.
-
-B4420 Personality
---------------------
-
-B4420 Personality
---------------------
-B4420 is a reduced personality of B4860 with less core/clusters(both SC3900 and e6500), less DDR
-controllers, less serdes lanes, less SGMII interfaces and reduced target frequencies.
-
-Key differences between B4860 and B4420
-----------------------------------------
-
-B4420 has:
-1. Less e6500 cores: 1 cluster with 2 e6500 cores
-2. Less SC3900 cores/clusters: 1 cluster with 2 SC3900 cores per cluster.
-3. Single DDRC
-4. 2X 4 lane serdes
-5. 3 SGMII interfaces
-6. no sRIO
-7. no 10G
-
-B4860QDS Default Settings
--------------------------
-
-Switch Settings
-----------------
-
-SW1 OFF [0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0]
-SW2 ON ON ON ON ON ON OFF OFF
-SW3 OFF OFF OFF ON OFF OFF ON OFF
-SW5 OFF OFF OFF OFF OFF OFF ON ON
-
-Note: PCIe slots modes: All the PCIe devices work as Root Complex.
-Note: Boot location: NOR flash.
-
-SysClk/Core(e6500)/CCB/DDR/FMan/DDRCLK/StarCore/CPRI-Maple/eTVPE-Maple/ULB-Maple
-66MHz/1.6GHz/667MHz/1.6GHz data rate/667MHz/133MHz/1200MHz/500MHz/800MHz/667MHz
-
-a) NAND boot
- SW1 [1.1] = 0
- SW2 [1.1] = 1
- SW3 [1:4] = 0001
-b) NOR boot
- SW1 [1.1] = 1
- SW2 [1.1] = 0
- SW3 [1:4] = 1000.
-
-B4420QDS Default Settings
--------------------------
-
-Switch Settings
-----------------
-SW1 OFF[0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0]
-SW2 ON OFF ON OFF ON ON OFF OFF
-SW3 OFF OFF OFF ON OFF OFF ON OFF
-SW5 OFF OFF OFF OFF OFF OFF ON ON
-
-Note: PCIe slots modes: All the PCIe devices work as Root Complex.
-Note: Boot location: NOR flash.
-
-SysClk/Core(e6500)/CCB/DDR/FMan/DDRCLK/StarCore/CPRI-Maple/eTVPE-Maple/ULB-Maple
-66MHz/1.6GHz/667MHz/1.6GHz data rate/667MHz/133MHz/1200MHz/500MHz/800MHz/667MHz
-
-a) NAND boot
- SW1 [1.1] = 0
- SW2 [1.1] = 1
- SW3 [1:4] = 0001
-b) NOR boot
- SW1 [1.1] = 1
- SW2 [1.1] = 0
- SW3 [1:4] = 1000.
-
-Memory map on B4860QDS
-----------------------
-The addresses in brackets are physical addresses.
-
-Start Address End Address Description Size
-0xF_FFDF_1000 0xF_FFFF_FFFF Free 2 MB
-0xF_FFDF_0000 0xF_FFDF_0FFF IFC - FPGA 4 KB
-0xF_FF81_0000 0xF_FFDE_FFFF Free 5 MB
-0xF_FF80_0000 0xF_FF80_FFFF IFC NAND Flash 64 KB
-0xF_FF00_0000 0xF_FF7F_FFFF Free 8 MB
-0xF_FE00_0000 0xF_FEFF_FFFF CCSRBAR 16 MB
-0xF_F801_0000 0xF_FDFF_FFFF Free 95 MB
-0xF_F800_0000 0xF_F800_FFFF PCIe I/O Space 64 KB
-0xF_F600_0000 0xF_F7FF_FFFF QMAN s/w portal 32 MB
-0xF_F400_0000 0xF_F5FF_FFFF BMAN s/w portal 32 MB
-0xF_F000_0000 0xF_F3FF_FFFF Free 64 MB
-0xF_E800_0000 0xF_EFFF_FFFF IFC NOR Flash 128 MB
-0xF_E000_0000 0xF_E7FF_FFFF Promjet 128 MB
-0xF_A0C0_0000 0xF_DFFF_FFFF Free 1012 MB
-0xF_A000_0000 0xF_A0BF_FFFF MAPLE0/1/2 12 MB
-0xF_0040_0000 0xF_9FFF_FFFF Free 12 GB
-0xF_0000_0000 0xF_01FF_FFFF DCSR 32 MB
-0xC_4000_0000 0xE_FFFF_FFFF Free 11 GB
-0xC_3000_0000 0xC_3FFF_FFFF sRIO-2 I/O 256 MB
-0xC_2000_0000 0xC_2FFF_FFFF sRIO-1 I/O 256 MB
-0xC_0000_0000 0xC_1FFF_FFFF PCIe Mem Space 512 MB
-0x1_0000_0000 0xB_FFFF_FFFF Free 44 GB
-0x0_8000_0000 0x0_FFFF_FFFF DDRC1 2 GB
-0x0_0000_0000 0x0_7FFF_FFFF DDRC2 2 GB
-
-Memory map on B4420QDS
-----------------------
-The addresses in brackets are physical addresses.
-
-Start Address End Address Description Size
-0xF_FFDF_1000 0xF_FFFF_FFFF Free 2 MB
-0xF_FFDF_0000 0xF_FFDF_0FFF IFC - FPGA 4 KB
-0xF_FF81_0000 0xF_FFDE_FFFF Free 5 MB
-0xF_FF80_0000 0xF_FF80_FFFF IFC NAND Flash 64 KB
-0xF_FF00_0000 0xF_FF7F_FFFF Free 8 MB
-0xF_FE00_0000 0xF_FEFF_FFFF CCSRBAR 16 MB
-0xF_F801_0000 0xF_FDFF_FFFF Free 95 MB
-0xF_F800_0000 0xF_F800_FFFF PCIe I/O Space 64 KB
-0xF_F600_0000 0xF_F7FF_FFFF QMAN s/w portal 32 MB
-0xF_F400_0000 0xF_F5FF_FFFF BMAN s/w portal 32 MB
-0xF_F000_0000 0xF_F3FF_FFFF Free 64 MB
-0xF_E800_0000 0xF_EFFF_FFFF IFC NOR Flash 128 MB
-0xF_E000_0000 0xF_E7FF_FFFF Promjet 128 MB
-0xF_A0C0_0000 0xF_DFFF_FFFF Free 1012 MB
-0xF_A000_0000 0xF_A0BF_FFFF MAPLE0/1/2 12 MB
-0xF_0040_0000 0xF_9FFF_FFFF Free 12 GB
-0xF_0000_0000 0xF_01FF_FFFF DCSR 32 MB
-0xC_4000_0000 0xE_FFFF_FFFF Free 11 GB
-0xC_3000_0000 0xC_3FFF_FFFF sRIO-2 I/O 256 MB
-0xC_2000_0000 0xC_2FFF_FFFF sRIO-1 I/O 256 MB
-0xC_0000_0000 0xC_1FFF_FFFF PCIe Mem Space 512 MB
-0x1_0000_0000 0xB_FFFF_FFFF Free 44 GB
-0x0_0000_0000 0x0_FFFF_FFFF DDRC1 4 GB
-
-
-NOR Flash memory Map on B4860 and B4420QDS
-------------------------------------------
- Start End Definition Size
-0xEFF40000 0xEFFFFFFF U-Boot (current bank) 768KB
-0xEFF20000 0xEFF3FFFF U-Boot env (current bank) 128KB
-0xEFF00000 0xEFF1FFFF FMAN Ucode (current bank) 128KB
-0xEF300000 0xEFEFFFFF rootfs (alternate bank) 12MB
-0xEE800000 0xEE8FFFFF device tree (alternate bank) 1MB
-0xEE020000 0xEE6FFFFF Linux.uImage (alternate bank) 6MB+896KB
-0xEE000000 0xEE01FFFF RCW (alternate bank) 128KB
-0xEDF40000 0xEDFFFFFF U-Boot (alternate bank) 768KB
-0xEDF20000 0xEDF3FFFF U-Boot env (alternate bank) 128KB
-0xEDF00000 0xEDF1FFFF FMAN ucode (alternate bank) 128KB
-0xED300000 0xEDEFFFFF rootfs (current bank) 12MB
-0xEC800000 0xEC8FFFFF device tree (current bank) 1MB
-0xEC020000 0xEC6FFFFF Linux.uImage (current bank) 6MB+896KB
-0xEC000000 0xEC01FFFF RCW (current bank) 128KB
-
-Various Software configurations/environment variables/commands
---------------------------------------------------------------
-The below commands apply to both B4860QDS and B4420QDS.
-
-1. U-Boot environment variable hwconfig
- The default hwconfig is:
- hwconfig=fsl_ddr:ctlr_intlv=null,bank_intlv=cs0_cs1;usb1:
- dr_mode=host,phy_type=ulpi
- Note: For USB gadget set "dr_mode=peripheral"
-
-2. FMAN Ucode versions
- fsl_fman_ucode_B4860_106_3_6.bin
-
-3. Switching to alternate bank
- Commands for switching to alternate bank.
-
- 1. To change from vbank0 to vbank2
- => qixis_reset altbank (it will boot using vbank2)
-
- 2.To change from vbank2 to vbank0
- => qixis reset (it will boot using vbank0)
-
-4. To change personality of board
- For changing personality from B4860 to B4420
- 1)Boot from vbank0
- 2)Flash vbank2 with b4420 rcw and U-Boot
- 3)Give following commands to uboot prompt
- => mw.b ffdf0040 0x30;
- => mw.b ffdf0010 0x00;
- => mw.b ffdf0062 0x02;
- => mw.b ffdf0050 0x02;
- => mw.b ffdf0010 0x30;
- => reset
-
- Note: Power off cycle will lead to default switch settings.
- Note: 0xffdf0000 is the address of the QIXIS FPGA.
-
-5. Switching between NOR and NAND boot(RCW src changed from NOR <-> NAND)
-
- To change from NOR to NAND boot give following command on uboot prompt
- => mw.b ffdf0040 0x30
- => mw.b ffdf0010 0x00
- => mw.b 0xffdf0050 0x08
- => mw.b 0xffdf0060 0x82
- => mw.b ffdf0061 0x00
- => mw.b ffdf0010 0x30
- => reset
-
- To change from NAND to NOR boot give following command on uboot prompt:
- => mw.b ffdf0040 0x30
- => mw.b ffdf0010 0x00
- => mw.b 0xffdf0050 0x00(for vbank0) or (mw.b 0xffdf0050 0x02 for vbank2)
- => mw.b 0xffdf0060 0x12
- => mw.b ffdf0061 0x01
- => mw.b ffdf0010 0x30
- => reset
-
- Note: Power off cycle will lead to default switch settings.
- Note: 0xffdf0000 is the address of the QIXIS FPGA.
-
-6. Ethernet interfaces for B4860QDS
- Serdes protocosl tested:
- 0x2a, 0x8d (serdes1, serdes2) [DEFAULT]
- 0x2a, 0xb2 (serdes1, serdes2)
-
- When using [DEFAULT] RCW, which including 2 * 1G SGMII on board and 2 * 1G
- SGMII on SGMII riser card.
- Under U-Boot these network interfaces are recognized as:
- FM1@DTSEC3, FM1@DTSEC4, FM1@DTSEC5 and FM1@DTSEC6.
-
- On Linux the interfaces are renamed as:
- . eth2 -> fm1-gb2
- . eth3 -> fm1-gb3
- . eth4 -> fm1-gb4
- . eth5 -> fm1-gb5
-
-7. RCW and Ethernet interfaces for B4420QDS
- Serdes protocosl tested:
- 0x18, 0x9e (serdes1, serdes2)
-
- Under U-Boot these network interfaces are recognized as:
- FM1@DTSEC3, FM1@DTSEC4 and e1000#0.
-
- On Linux the interfaces are renamed as:
- . eth2 -> fm1-gb2
- . eth3 -> fm1-gb3
-
-NAND boot with 2 Stage boot loader
-----------------------------------
-PBL initialise the internal SRAM and copy SPL(160KB) in SRAM.
-SPL further initialise DDR using SPD and environment variables and copy
-U-Boot(768 KB) from flash to DDR.
-Finally SPL transer control to U-Boot for futher booting.
-
-SPL has following features:
- - Executes within 256K
- - No relocation required
-
- Run time view of SPL framework during boot :-
- -----------------------------------------------
- Area | Address |
------------------------------------------------
- Secure boot | 0xFFFC0000 (32KB) |
- headers | |
- -----------------------------------------------
- GD, BD | 0xFFFC8000 (4KB) |
- -----------------------------------------------
- ENV | 0xFFFC9000 (8KB) |
- -----------------------------------------------
- HEAP | 0xFFFCB000 (30KB) |
- -----------------------------------------------
- STACK | 0xFFFD8000 (22KB) |
- -----------------------------------------------
- U-Boot SPL | 0xFFFD8000 (160KB) |
- -----------------------------------------------
-
-NAND Flash memory Map on B4860 and B4420QDS
-------------------------------------------
- Start End Definition Size
-0x000000 0x0FFFFF U-Boot 1MB
-0x140000 0x15FFFF U-Boot env 128KB
-0x1A0000 0x1BFFFF FMAN Ucode 128KB
diff --git a/doc/README.blackfin b/doc/README.blackfin
deleted file mode 100644
index a837d90..0000000
--- a/doc/README.blackfin
+++ /dev/null
@@ -1,46 +0,0 @@
-Notes for the Blackfin architecture port of Das U-Boot
-
- =========
- ! ABOUT !
- =========
-
-<marketing blurb>
-Blackfin Processors embody a new breed of 16/32-bit embedded processor, ideally
-suited for products where a convergence of capabilities are necessary -
-multi-format audio, video, voice and image processing; multi-mode baseband and
-packet processing; control processing; and real-time security. The Blackfin's
-unique combination of software flexibility and scalability has gained it
-widespread adoption in convergent applications.
-</marketing blurb>
-
-The Blackfin processor is wholly developed by Analog Devices Inc.
-
- ===========
- ! SUPPORT !
- ===========
-
-All open source code for the Blackfin processors are being handled via our
-collaborative website:
-http://blackfin.uclinux.org/
-
-In particular, bug reports, feature requests, help etc... for Das U-Boot are
-handled in the Das U-Boot sub project:
-http://blackfin.uclinux.org/gf/project/u-boot
-
-This website is backed both by an open source community as well as a dedicated
-team from Analog Devices Inc.
-
- =============
- ! TOOLCHAIN !
- =============
-
-To compile the Blackfin aspects, you'll need the GNU toolchain configured for
-the Blackfin processor. You can obtain such a cross-compiler here:
-http://blackfin.uclinux.org/gf/project/toolchain
-
- =================
- ! DOCUMENTATION !
- =================
-
-For Blackfin specific documentation, you can visit our dedicated doc wiki:
-http://docs.blackfin.uclinux.org/doku.php?id=bootloaders:u-boot
diff --git a/doc/README.chromium b/doc/README.chromium
index 096bc4f..8f67da6 100644
--- a/doc/README.chromium
+++ b/doc/README.chromium
@@ -33,12 +33,18 @@
cd u-boot
git checkout cros-master
+ cd ..
+ git clone https://chromium.googlesource.com/chromiumos/platform/vboot_reference
+ cd vboot_reference
+ git checkout 45964294
+ # futility: updater: Correct output version for Snow
+
To build for sandbox:
UB=/tmp/b/chromeos_sandbox # U-Boot build directory
- CROS=/home/sglass/cosarm # Chromium OS directory
- make O=$UB/chromeos_sandbox_defconfig
- make O=$UB -j20 -s VBOOT_SOURCE=$CROS/src/platform/vboot_reference \
+ cd u-boot
+ make O=$UB chromeos_sandbox_defconfig
+ make O=$UB -j20 -s VBOOT_SOURCE=/path/to/vboot_reference \
MAKEFLAGS_VBOOT=DEBUG=1 QUIET=1
Replace sandbox with another supported target.
diff --git a/doc/README.m68k b/doc/README.m68k
deleted file mode 100644
index f867ca1..0000000
--- a/doc/README.m68k
+++ /dev/null
@@ -1,150 +0,0 @@
-
-U-Boot for Motorola (or Freescale/NXP) ColdFire processors
-
-===============================================================================
-History
-
-November 02, 2017 Angelo Dureghello <angelo@sysam.it>
-August 08, 2005 Jens Scharsig <esw@bus-elektronik.de>
- MCF5282 implementation without preloader
-January 12, 2004 <josef.baumgartner@telex.de>
-===============================================================================
-
-
-This file contains status information for the port of U-Boot to the
-Motorola ColdFire series of CPUs.
-
-
-1. Overview
-
-The ColdFire instruction set is "assembly source" compatible but an evolution
-of the original 68000 instruction set. Some not much used instructions has
-been removed. The instructions are only 16, 32, or 48 bits long, a
-simplification compared to the 68000 series.
-
-Bernhard Kuhn ported U-Boot 0.4.0 to the Motorola ColdFire architecture.
-The patches of Bernhard support the MCF5272 and MCF5282. A great disadvantage
-of these patches was that they needed a pre-bootloader to start U-Boot.
-Because of this, a new port was created which no longer needs a first stage
-booter.
-
-Thanks mainly to Freescale but also to several other contributors, U-Boot now
-supports nearly the entire range of ColdFire processors and their related
-development boards.
-
-
-2. Supported CPU families
-
-Please "make menuconfig" with ARCH=m68k, or check arch/m68k/cpu to see the
-currently supported processor and families.
-
-
-3. Supported boards
-
-U-Boot supports actually more than 40 ColdFire based boards.
-Board configuration can be done trough include/configs/<boardname>.h but the
-current recommended method is to use the new and more friendly approach as
-the "make menuconfig" way, very similar to the Linux way.
-
-To know details as memory map, build targets, default setup, etc, of a
-specific board please check:
-
-include/configs/<boardname>.h
-and/or
-configs/<boardname>_defconfig
-
-It is possible to build all ColdFire boards in a single command-line command,
-from u-boot root directory, as:
-
-./tools/buildman/buildman m68k
-
-
-3.1. Build U-Boot for a specific board
-
-A bash script similar to the one below may be used:
-
-#!/bin/bash
-
-export CROSS_COMPILE=/opt/toolchains/m68k/gcc-4.9.0-nolibc/bin/m68k-linux-
-
-board=M5475DFE
-
-make distclean
-make ARCH=m68k ${board}_defconfig
-make ARCH=m68k KBUILD_VERBOSE=1
-
-
-4. Adopted toolchains
-
-Please check:
-https://www.denx.de/wiki/U-Boot/ColdFireNotes
-
-
-5. ColdFire specific configuration options/settings
-
-
-5.1. Configuration to use a pre-loader
-
-If U-Boot should be loaded to RAM and started by a pre-loader
-CONFIG_MONITOR_IS_IN_RAM must be defined. If it is defined the
-initial vector table and basic processor initialization will not
-be compiled in. The start address of U-Boot must be adjusted in
-the boards config header file (CONFIG_SYS_MONITOR_BASE) and Makefile
-(CONFIG_SYS_TEXT_BASE) to the load address.
-
-
-5.2 ColdFire CPU specific options/settings
-
-To specify a CPU model, some defines shoudl be used, i.e.:
-
-CONFIG_MCF52x2 -- defined for all MCF52x2 CPUs
-CONFIG_M5272 -- defined for all Motorola MCF5272 CPUs
-
-Other options, generally set inside include/configs/<boardname>.h, they may
-apply to one or more cpu for the ColdFire family:
-
-CONFIG_SYS_MBAR -- defines the base address of the MCF5272 configuration
- registers
-CONFIG_SYS_ENET_BD_BASE
- -- defines the base address of the FEC buffer descriptors
-CONFIG_SYS_SCR -- defines the contents of the System Configuration Register
-CONFIG_SYS_SPR -- defines the contents of the System Protection Register
-CONFIG_SYS_MFD -- defines the PLL Multiplication Factor Divider
- (see table 9-4 of MCF user manual)
-CONFIG_SYS_RFD -- defines the PLL Reduce Frequency Devider
- (see table 9-4 of MCF user manual)
-CONFIG_SYS_CSx_BASE
- -- defines the base address of chip select x
-CONFIG_SYS_CSx_SIZE
- -- defines the memory size (address range) of chip select x
-CONFIG_SYS_CSx_WIDTH
- -- defines the bus with of chip select x
-CONFIG_SYS_CSx_MASK
- -- defines the mask for the related chip select x
-CONFIG_SYS_CSx_RO
- -- if set to 0 chip select x is read/write else chip select
- is read only
-CONFIG_SYS_CSx_WS
- -- defines the number of wait states of chip select x
-CONFIG_SYS_CACHE_ICACR
-CONFIG_SYS_CACHE_DCACR
-CONFIG_SYS_CACHE_ACRX
- -- cache-related registers config
-CONFIG_SYS_SDRAM_BASE
-CONFIG_SYS_SDRAM_SIZE
-CONFIG_SYS_SDRAM_BASEX
-CONFIG_SYS_SDRAM_CFG1
-CONFIG_SYS_SDRAM_CFG2
-CONFIG_SYS_SDRAM_CTRL
-CONFIG_SYS_SDRAM_MODE
-CONFIG_SYS_SDRAM_EMOD
- -- SDRAM config for SDRAM controller-specific registers, please
- see arch/m68k/cpu/<specific_cpu>/start.S files to see how
- these options are used.
-CONFIG_MCFUART
- -- defines enabling of ColdFire UART driver
-CONFIG_SYS_UART_PORT
- -- defines the UART port to be used (only a single UART can be
- actually enabled)
-CONFIG_SYS_SBFHDR_SIZE
- -- size of the prepended SBF header, if any
diff --git a/doc/README.nios2 b/doc/README.nios2
deleted file mode 100644
index 46c704e..0000000
--- a/doc/README.nios2
+++ /dev/null
@@ -1,95 +0,0 @@
-Nios II is a 32-bit embedded-processor architecture designed
-specifically for the Altera family of FPGAs.
-
-Please refer to the link for more information on Nios II,
-https://www.altera.com/products/processors/overview.html
-
-Please refer to the link for Linux port and toolchains,
-http://rocketboards.org/foswiki/view/Documentation/NiosIILinuxUserManual
-
-The Nios II port of u-boot is controlled by device tree. Please check
-out doc/README.fdt-control.
-
-To add a new board/configuration (eg, mysystem) to u-boot, you will need
-three files.
-
-1. The device tree source which describes the hardware, dts file.
- arch/nios2/dts/mysystem.dts
-
-2. Default configuration of Kconfig, defconfig file.
- configs/mysystem_defconfig
-
-3. The legacy board header file.
- include/configs/mysystem.h
-
-The device tree source must be generated from your qsys/sopc design
-using the sopc2dts tool. Then modified to fit your configuration. Please
-find the sopc2dts download and usage at the wiki,
-http://www.alterawiki.com/wiki/Sopc2dts
-
-$ java -jar sopc2dts.jar --force-altr -i mysystem.sopcinfo -o mysystem.dts
-
-You will need to add additional properties to the dts. Please find an
-example at, arch/nios2/dts/10m50_devboard.dts.
-
-1. Add "stdout-path=..." property with your serial path to the chosen
-node, like this,
- chosen {
- stdout-path = &uart_0;
- };
-
-2. If you use SPI/EPCS or I2C, you will need to add aliases to number
-the sequence of these devices, like this,
- aliases {
- spi0 = &epcs_controller;
- };
-
-Next, you will need a default config file. You may start with
-10m50_defconfig, modify the options and save it.
-
-$ make 10m50_defconfig
-$ make menuconfig
-$ make savedefconfig
-$ cp defconfig configs/mysystem_defconfig
-
-You will need to change the names of board header file and device tree,
-and select the drivers with menuconfig.
-
-Nios II architecture --->
- (mysystem) Board header file
-Device Tree Control --->
- (mysystem) Default Device Tree for DT control
-
-There is a selection of "Provider of DTB for DT control" in the Device
-Tree Control menu.
-
-( ) Separate DTB for DT control, will cat the dtb to end of u-boot
-binary, output u-boot-dtb.bin. This should be used for production.
-If you use boot copier, like EPCS boot copier, make sure the copier
-copies all the u-boot-dtb.bin, not just u-boot.bin.
-
-( ) Embedded DTB for DT control, will include the dtb inside the u-boot
-binary. This is handy for development, eg, using gdb or nios2-download.
-
-The last thing, legacy board header file describes those config options
-not covered in Kconfig yet. You may copy it from 10m50_devboard.h.
-
-$ cp include/configs/10m50_devboard.h include/configs/mysystem.h
-
-Please change the SDRAM base and size to match your board. The base
-should be cached virtual address, for Nios II with MMU it is 0xCxxx_xxxx
-to 0xDxxx_xxxx.
-
-#define CONFIG_SYS_SDRAM_BASE 0xc8000000
-#define CONFIG_SYS_SDRAM_SIZE 0x08000000
-
-You will need to change the environment variables location and setting,
-too. You may change other configs to fit your board.
-
-After all these changes, you may build and test.
-
-$ export CROSS_COMPILE=nios2-elf- (or nios2-linux-gnu-)
-$ make mysystem_defconfig
-$ make
-
-Enjoy!
diff --git a/doc/README.qemu-mips b/doc/README.qemu-mips
deleted file mode 100644
index 3940fac..0000000
--- a/doc/README.qemu-mips
+++ /dev/null
@@ -1,195 +0,0 @@
-By Vlad Lungu vlad.lungu@windriver.com 2007-Oct-01
-----------------------------------------
-Qemu is a full system emulator. See
-
-http://www.nongnu.org/qemu/
-
-Limitations & comments
-----------------------
-Supports the "-M mips" configuration of qemu: serial,NE2000,IDE.
-Supports little and big endian as well as 32 bit and 64 bit.
-Derived from au1x00 with a lot of things cut out.
-
-Supports emulated flash (patch Jean-Christophe PLAGNIOL-VILLARD) with
-recent qemu versions. When using emulated flash, launch with
--pflash <filename> and erase mips_bios.bin.
-
-
-Notes for the Qemu MIPS port
-----------------------------
-
-I) Example usage:
-
-Using u-boot.bin as ROM (replaces Qemu monitor):
-
-32 bit, big endian:
-# make qemu_mips
-# qemu-system-mips -M mips -bios u-boot.bin -nographic
-
-32 bit, little endian:
-# make qemu_mipsel
-# qemu-system-mipsel -M mips -bios u-boot.bin -nographic
-
-64 bit, big endian:
-# make qemu_mips64
-# qemu-system-mips64 -cpu MIPS64R2-generic -M mips -bios u-boot.bin -nographic
-
-64 bit, little endian:
-# make qemu_mips64el
-# qemu-system-mips64el -cpu MIPS64R2-generic -M mips -bios u-boot.bin -nographic
-
-or using u-boot.bin from emulated flash:
-
-if you use a qemu version after commit 4224
-
-create image:
-# dd of=flash bs=1k count=4k if=/dev/zero
-# dd of=flash bs=1k conv=notrunc if=u-boot.bin
-start it (see above):
-# qemu-system-mips[64][el] [-cpu MIPS64R2-generic] -M mips -pflash flash -nographic
-
-2) Download kernel + initrd
-
-On ftp://ftp.denx.de/pub/contrib/Jean-Christophe_Plagniol-Villard/qemu_mips/
-you can downland
-
-#config to build the kernel
-qemu_mips_defconfig
-#patch to fix mips interrupt init on 2.6.24.y kernel
-qemu_mips_kernel.patch
-initrd.gz
-vmlinux
-vmlinux.bin
-System.map
-
-4) Generate uImage
-
-# tools/mkimage -A mips -O linux -T kernel -C gzip -a 0x80010000 -e 0x80245650 -n "Linux 2.6.24.y" -d vmlinux.bin.gz uImage
-
-5) Copy uImage to Flash
-# dd if=uImage bs=1k conv=notrunc seek=224 of=flash
-
-6) Generate Ide Disk
-
-# dd of=ide bs=1k cout=100k if=/dev/zero
-
-# sfdisk -C 261 -d ide
-# partition table of ide
-unit: sectors
-
- ide1 : start= 63, size= 32067, Id=83
- ide2 : start= 32130, size= 32130, Id=83
- ide3 : start= 64260, size= 4128705, Id=83
- ide4 : start= 0, size= 0, Id= 0
-
-7) Copy to ide
-
-# dd if=uImage bs=512 conv=notrunc seek=63 of=ide
-
-8) Generate ext2 on part 2 on Copy uImage and initrd.gz
-
-# Attached as loop device ide offset = 32130 * 512
-# losetup -o 16450560 -f ide
-# Format as ext2 ( arg2 : nb blocks)
-# mke2fs /dev/loop0 16065
-# losetup -d /dev/loop0
-# Mount and copy uImage and initrd.gz to it
-# mount -o loop,offset=16450560 -t ext2 ide /mnt
-# mkdir /mnt/boot
-# cp {initrd.gz,uImage} /mnt/boot/
-# Umount it
-# umount /mnt
-
-9) Set Environment
-
-setenv rd_start 0x80800000
-setenv rd_size 2663940
-setenv kernel BFC38000
-setenv oad_addr 80500000
-setenv load_addr2 80F00000
-setenv kernel_flash BFC38000
-setenv load_addr_hello 80200000
-setenv bootargs 'root=/dev/ram0 init=/bin/sh'
-setenv load_rd_ext2 'ide res; ext2load ide 0:2 ${rd_start} /boot/initrd.gz'
-setenv load_rd_tftp 'tftp ${rd_start} /initrd.gz'
-setenv load_kernel_hda 'ide res; diskboot ${load_addr} 0:2'
-setenv load_kernel_ext2 'ide res; ext2load ide 0:2 ${load_addr} /boot/uImage'
-setenv load_kernel_tftp 'tftp ${load_addr} /qemu_mips/uImage'
-setenv boot_ext2_ext2 'run load_rd_ext2; run load_kernel_ext2; run addmisc; bootm ${load_addr}'
-setenv boot_ext2_flash 'run load_rd_ext2; run addmisc; bootm ${kernel_flash}'
-setenv boot_ext2_hda 'run load_rd_ext2; run load_kernel_hda; run addmisc; bootm ${load_addr}'
-setenv boot_ext2_tftp 'run load_rd_ext2; run load_kernel_tftp; run addmisc; bootm ${load_addr}'
-setenv boot_tftp_hda 'run load_rd_tftp; run load_kernel_hda; run addmisc; bootm ${load_addr}'
-setenv boot_tftp_ext2 'run load_rd_tftp; run load_kernel_ext2; run addmisc; bootm ${load_addr}'
-setenv boot_tftp_flash 'run load_rd_tftp; run addmisc; bootm ${kernel_flash}'
-setenv boot_tftp_tftp 'run load_rd_tftp; run load_kernel_tftp; run addmisc; bootm ${load_addr}'
-setenv load_hello_tftp 'tftp ${load_addr_hello} /examples/hello_world.bin'
-setenv go_tftp 'run load_hello_tftp; go ${load_addr_hello}'
-setenv addmisc 'setenv bootargs ${bootargs} console=ttyS0,${baudrate} rd_start=${rd_start} rd_size=${rd_size} ethaddr=${ethaddr}'
-setenv bootcmd 'run boot_tftp_flash'
-
-10) Now you can boot from flash, ide, ide+ext2 and tfp
-
-# qemu-system-mips -M mips -pflash flash -monitor null -nographic -net nic -net user -tftp `pwd` -hda ide
-
-II) How to debug U-Boot
-
-In order to debug U-Boot you need to start qemu with gdb server support (-s)
-and waiting the connection to start the CPU (-S)
-
-# qemu-system-mips -S -s -M mips -pflash flash -monitor null -nographic -net nic -net user -tftp `pwd` -hda ide
-
-in an other console you start gdb
-
-1) Debugging of U-Boot Before Relocation
-
-Before relocation, the addresses in the ELF file can be used without any problems
-by connecting to the gdb server localhost:1234
-
-# mipsel-unknown-linux-gnu-gdb u-boot
-GNU gdb 6.6
-Copyright (C) 2006 Free Software Foundation, Inc.
-GDB is free software, covered by the GNU General Public License, and you are
-welcome to change it and/or distribute copies of it under certain conditions.
-Type "show copying" to see the conditions.
-There is absolutely no warranty for GDB. Type "show warranty" for details.
-This GDB was configured as "--host=i486-linux-gnu --target=mipsel-unknown-linux-gnu"...
-(gdb) target remote localhost:1234
-Remote debugging using localhost:1234
-_start () at start.S:64
-64 RVECENT(reset,0) /* U-Boot entry point */
-Current language: auto; currently asm
-(gdb) b board.c:289
-Breakpoint 1 at 0xbfc00cc8: file board.c, line 289.
-(gdb) c
-Continuing.
-
-Breakpoint 1, board_init_f (bootflag=<value optimized out>) at board.c:290
-290 relocate_code (addr_sp, id, addr);
-Current language: auto; currently c
-(gdb) p/x addr
-$1 = 0x87fa0000
-
-2) Debugging of U-Boot After Relocation
-
-For debugging U-Boot after relocation we need to know the address to which
-U-Boot relocates itself to 0x87fa0000 by default.
-And replace the symbol table to this offset.
-
-(gdb) symbol-file
-Discard symbol table from `/private/u-boot-arm/u-boot'? (y or n) y
-Error in re-setting breakpoint 1:
-No symbol table is loaded. Use the "file" command.
-No symbol file now.
-(gdb) add-symbol-file u-boot 0x87fa0000
-add symbol table from file "u-boot" at
- .text_addr = 0x87fa0000
-(y or n) y
-Reading symbols from /private/u-boot-arm/u-boot...done.
-Breakpoint 1 at 0x87fa0cc8: file board.c, line 289.
-(gdb) c
-Continuing.
-
-Program received signal SIGINT, Interrupt.
-0xffffffff87fa0de4 in udelay (usec=<value optimized out>) at time.c:78
-78 while ((tmo - read_c0_count()) < 0x7fffffff)
diff --git a/doc/README.rockchip b/doc/README.rockchip
index 02e2497..8ccbb87 100644
--- a/doc/README.rockchip
+++ b/doc/README.rockchip
@@ -123,10 +123,6 @@
Option 2: Package the image with SPL:
- - We need the Python elftools.elf.elffile library for make_fit_atf.py to work
-
- => sudo apt-get install python-pyelftools
-
- Export cross compiler path for aarch64
- Compile ATF
diff --git a/doc/README.sh b/doc/README.sh
deleted file mode 100644
index 766a8c8..0000000
--- a/doc/README.sh
+++ /dev/null
@@ -1,97 +0,0 @@
-
-U-Boot for Renesas SuperH
- Last update 01/18/2008 by Nobuhiro Iwamatsu
-
-================================================================================
-0. What's this?
- This file contains status information for the port of U-Boot to the
- Renesas SuperH series of CPUs.
-
-================================================================================
-1. Overview
- SuperH has an original boot loader. However, source code is dirty, and
- maintenance is not done.
- To improve sharing and the maintenance of the code, Nobuhiro Iwamatsu
- started the porting to u-boot in 2007.
-
-================================================================================
-2. Supported CPUs
-
- 2.1. Renesas SH7750/SH7750R
- This CPU has the SH4 core.
-
- 2.2. Renesas SH7722
- This CPU has the SH4AL-DSP core.
-
- 2.3. Renesas SH7780
- This CPU has the SH4A core.
-
-================================================================================
-3. Supported Boards
-
- 3.1. Hitachi UL MS7750SE01/MS7750RSE01
- Board specific code is in board/ms7750se
- To use this board, type "make ms7750se_config".
- Support devices are :
- - SCIF
- - SDRAM
- - NOR Flash
- - Marubun PCMCIA
-
- 3.2. Hitachi UL MS7722SE01
- Board specific code is in board/ms7722se
- To use this board, type "make ms7722se_config".
- Support devices are :
- - SCIF
- - SDRAM
- - NOR Flash
- - Marubun PCMCIA
- - SMC91x ethernet
-
- 3.2. Hitachi UL MS7720ERP01
- Board specific code is in board/ms7720se
- To use this board, type "make ms7720se_config".
- Support devices are :
- - SCIF
- - SDRAM
- - NOR Flash
- - Marubun PCMCIA
-
- 3.3. Renesas R7780MP
- Board specific code is in board/r7780mp
- To use this board, type "make r7780mp_config".
- Support devices are :
- - SCIF
- - DDR-SDRAM
- - NOR Flash
- - Compact Flash
- - ASIX ethernet
- - SH7780 PCI bridge
- - RTL8110 ethernet
-
- ** README **
- In SuperH, S-record and binary of made u-boot work on the memory.
- When u-boot is written in the flash, it is necessary to change the
- address by using 'objcopy'.
- ex) shX-linux-objcopy -Ibinary -Osrec u-boot.bin u-boot.flash.srec
-
-================================================================================
-4. Compiler
- You can use the following of u-boot to compile.
- - SuperH Linux Open site
- http://www.superh-linux.org/
- - KPIT GNU tools
- http://www.kpitgnutools.com/
-
-================================================================================
-5. Future
- I plan to support the following CPUs and boards.
- 5.1. CPUs
- - SH7751R(SH4)
-
- 5.2. Boards
- - Many boards ;-)
-
-================================================================================
-Copyright (c) 2007,2008
- Nobuhiro Iwamatsu <iwamatsu@nigaur.org>
diff --git a/doc/README.sh7752evb b/doc/README.sh7752evb
deleted file mode 100644
index c1fb54c..0000000
--- a/doc/README.sh7752evb
+++ /dev/null
@@ -1,67 +0,0 @@
-========================================
-Renesas R0P7752C00000RZ board
-========================================
-
-This board specification:
-=========================
-
-The R0P7752C00000RZ(board config name:sh7752evb) has the following device:
-
- - SH7752 (SH-4A)
- - DDR3-SDRAM 512MB
- - SPI ROM 8MB
- - Gigabit Ethernet controllers
- - eMMC 4GB
-
-
-Configuration for This board:
-=============================
-
-You can select the configuration as follows:
-
- - make sh7752evb_config
-
-
-This board specific command:
-============================
-
-This board has the following its specific command:
-
- - write_mac
-
-
-1. write_mac
-
-You can write MAC address to SPI ROM.
-
- Usage 1) Write MAC address
-
- write_mac [GETHERC ch0] [GETHERC ch1]
-
- For example)
- => write_mac 74:90:50:00:33:9e 74:90:50:00:33:9f
- *) We have to input the command as a single line
- (without carriage return)
- *) We have to reset after input the command.
-
- Usage 2) Show current data
-
- write_mac
-
- For example)
- => write_mac
- GETHERC ch0 = 74:90:50:00:33:9e
- GETHERC ch1 = 74:90:50:00:33:9f
-
-
-Update SPI ROM:
-============================
-
-1. Copy u-boot image to RAM area.
-2. Probe SPI device.
- => sf probe 0
- SF: Detected MX25L6405D with page size 64KiB, total 8 MiB
-3. Erase SPI ROM.
- => sf erase 0 80000
-4. Write u-boot image to SPI ROM.
- => sf write 0x48000000 0 80000
diff --git a/doc/README.sh7753evb b/doc/README.sh7753evb
deleted file mode 100644
index 5fe178c..0000000
--- a/doc/README.sh7753evb
+++ /dev/null
@@ -1,67 +0,0 @@
-========================================
-Renesas SH7753 EVB board
-========================================
-
-This board specification:
-=========================
-
-The SH7753 EVB (board config name:sh7753evb) has the following device:
-
- - SH7753 (SH-4A)
- - DDR3-SDRAM 512MB
- - SPI ROM 8MB
- - Gigabit Ethernet controllers
- - eMMC 4GB
-
-
-Configuration for This board:
-=============================
-
-You can select the configuration as follows:
-
- - make sh7753evb_config
-
-
-This board specific command:
-============================
-
-This board has the following its specific command:
-
- - write_mac
-
-
-1. write_mac
-
-You can write MAC address to SPI ROM.
-
- Usage 1) Write MAC address
-
- write_mac [GETHERC ch0] [GETHERC ch1]
-
- For example)
- => write_mac 74:90:50:00:33:9e 74:90:50:00:33:9f
- *) We have to input the command as a single line
- (without carriage return)
- *) We have to reset after input the command.
-
- Usage 2) Show current data
-
- write_mac
-
- For example)
- => write_mac
- GETHERC ch0 = 74:90:50:00:33:9e
- GETHERC ch1 = 74:90:50:00:33:9f
-
-
-Update SPI ROM:
-============================
-
-1. Copy u-boot image to RAM area.
-2. Probe SPI device.
- => sf probe 0
- SF: Detected MX25L6405D with page size 64KiB, total 8 MiB
-3. Erase SPI ROM.
- => sf erase 0 80000
-4. Write u-boot image to SPI ROM.
- => sf write 0x48000000 0 80000
diff --git a/doc/README.sifive-fu540 b/doc/README.sifive-fu540
deleted file mode 100644
index fd9f2a8..0000000
--- a/doc/README.sifive-fu540
+++ /dev/null
@@ -1,303 +0,0 @@
-FU540-C000 RISC-V SoC
-=====================
-The FU540-C000 is the world’s first 4+1 64-bit RISC‑V SoC from SiFive.
-
-The HiFive Unleashed development platform is based on FU540-C000 and capable
-of running Linux.
-
-Mainline support
-================
-The support for following drivers are already enabled:
-1. SiFive UART Driver.
-2. SiFive PRCI Driver for clock.
-3. Cadence MACB ethernet driver for networking support.
-
-TODO:
-1. SPI driver is still missing. So MMC card can't be used in U-Boot as of now.
-2. U-Boot expects the serial console device entry to be present under /chosen
- DT node. Example:
- chosen {
- stdout-path = "/soc/serial@10010000:115200";
- };
-
- Without a serial console U-Boot will panic.
-
-Building
-========
-1. Add the RISC-V toolchain to your PATH.
-2. Setup ARCH & cross compilation enviornment variable.
- a. export ARCH=riscv
- b. export CROSS_COMPILE=<riscv64 toolchain prefix>
-3. make sifive_fu540_defconfig
-4. make
-
-Flashing
-========
-The current U-Boot port is supported in S-mode only and loaded from DRAM.
-
-A prior stage (M-mode) firmware/bootloader (e.g OpenSBI or BBL) is required to
-load the u-boot.bin into memory and provide runtime services. The u-boot.bin
-can be given as a payload to the prior stage (M-mode) firmware/bootloader.
-
-The description of steps required to build the firmware is beyond the scope of
-this document. Please refer OpenSBI or BBL documenation.
-(Note: OpenSBI git repo is at https://github.com/riscv/opensbi.git)
-(Note: BBL git repo is at https://github.com/riscv/riscv-pk.git)
-
-Once the prior stage firmware/bootloader binary is generated, it should be
-copied to the first partition of the sdcard.
-
-sudo dd if=<prior_stage_firmware_binary> of=/dev/disk2s1 bs=1024
-
-Booting
-=======
-Once you plugin the sdcard and power up, you should see the U-Boot prompt.
-
-Sample boot log from HiFive Unleashed board
-===========================================
-U-Boot 2019.01-00019-gc7953536-dirty (Jan 22 2019 - 11:05:40 -0800)
-
-CPU: rv64imafdc
-Model: sifive,hifive-unleashed-a00
-DRAM: 8 GiB
-In: serial@10010000
-Out: serial@10010000
-Err: serial@10010000
-Net:
-Warning: ethernet@10090000 (eth0) using random MAC address - b6:75:4d:48:50:94
-eth0: ethernet@10090000
-Hit any key to stop autoboot: 0
-=> version
-U-Boot 2019.01-00019-gc7953536-dirty (Jan 22 2019 - 11:05:40 -0800)
-
-riscv64-linux-gcc.br_real (Buildroot 2018.11-rc2-00003-ga0787e9) 8.2.0
-GNU ld (GNU Binutils) 2.31.1
-=>
-===============================================================================
-
-Now you can configure your networking, tftp server and use tftp boot method to
-load uImage.
-
-==========================================================================
-=> setenv ethaddr 70:B3:D5:92:F0:C2
-=> setenv ipaddr 10.196.157.189
-=> setenv serverip 10.11.143.218
-=> setenv gatewayip 10.196.156.1
-=> setenv netmask 255.255.252.0
-=> bdinfo
-boot_params = 0x0000000000000000
-DRAM bank = 0x0000000000000000
--> start = 0x0000000080000000
--> size = 0x0000000200000000
-relocaddr = 0x00000000fff90000
-reloc off = 0x000000007fd90000
-ethaddr = 70:B3:D5:92:F0:C2
-IP addr = 10.196.157.189
-baudrate = 115200 bps
-=> tftpboot uImage
-ethernet@10090000: PHY present at 0
-ethernet@10090000: Starting autonegotiation...
-ethernet@10090000: Autonegotiation complete
-ethernet@10090000: link up, 1000Mbps full-duplex (lpa: 0x3800)
-Using ethernet@10090000 device
-TFTP from server 10.11.143.218; our IP address is 10.196.157.189; sending through gateway 10.196.156.1
-Filename 'uImage'.
-Load address: 0x80200000
-Loading: #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- #################################################################
- ##########################################################
- 2.5 MiB/s
-done
-Bytes transferred = 14939132 (e3f3fc hex)
-=> bootm 0x80200000 - 0x82200000
-## Booting kernel from Legacy Image at 80200000 ...
- Image Name: Linux
- Image Type: RISC-V Linux Kernel Image (uncompressed)
- Data Size: 14939068 Bytes = 14.2 MiB
- Load Address: 80200000
- Entry Point: 80200000
- Verifying Checksum ... OK
-## Flattened Device Tree blob at 82200000
- Booting using the fdt blob at 0x82200000
- Loading Kernel Image ... OK
- Using Device Tree in place at 0000000082200000, end 0000000082205c69
-
-Starting kernel ...
-
-[ 0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
-[ 0.000000] Linux version 5.0.0-rc1-00020-g4b51f736 (atish@jedi-01) (gcc version 7.2.0 (GCC)) #262 SMP Mon Jan 21 17:39:27 PST 2019
-[ 0.000000] initrd not found or empty - disabling initrd
-[ 0.000000] Zone ranges:
-[ 0.000000] DMA32 [mem 0x0000000080200000-0x00000000ffffffff]
-[ 0.000000] Normal [mem 0x0000000100000000-0x000027ffffffffff]
-[ 0.000000] Movable zone start for each node
-[ 0.000000] Early memory node ranges
-[ 0.000000] node 0: [mem 0x0000000080200000-0x000000027fffffff]
-[ 0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x000000027fffffff]
-[ 0.000000] software IO TLB: mapped [mem 0xfbfff000-0xfffff000] (64MB)
-[ 0.000000] CPU with hartid=0 has a non-okay status of "masked"
-[ 0.000000] CPU with hartid=0 has a non-okay status of "masked"
-[ 0.000000] elf_hwcap is 0x112d
-[ 0.000000] percpu: Embedded 15 pages/cpu @(____ptrval____) s29720 r0 d31720 u61440
-[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 2067975
-[ 0.000000] Kernel command line: earlyprintk
-[ 0.000000] Dentry cache hash table entries: 1048576 (order: 11, 8388608 bytes)
-[ 0.000000] Inode-cache hash table entries: 524288 (order: 10, 4194304 bytes)
-[ 0.000000] Sorting __ex_table...
-[ 0.000000] Memory: 8178760K/8386560K available (3309K kernel code, 248K rwdata, 872K rodata, 9381K init, 763K bss, 207800K reserved, 0K cma-reserved)
-[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
-[ 0.000000] rcu: Hierarchical RCU implementation.
-[ 0.000000] rcu: RCU event tracing is enabled.
-[ 0.000000] rcu: RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
-[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
-[ 0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
-[ 0.000000] NR_IRQS: 0, nr_irqs: 0, preallocated irqs: 0
-[ 0.000000] plic: mapped 53 interrupts to 4 (out of 9) handlers.
-[ 0.000000] riscv_timer_init_dt: Registering clocksource cpuid [0] hartid [1]
-[ 0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x1d854df40, max_idle_ns: 3526361616960 ns
-[ 0.000008] sched_clock: 64 bits at 1000kHz, resolution 1000ns, wraps every 2199023255500ns
-[ 0.000221] Console: colour dummy device 80x25
-[ 0.000902] printk: console [tty0] enabled
-[ 0.000963] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.00 BogoMIPS (lpj=10000)
-[ 0.001034] pid_max: default: 32768 minimum: 301
-[ 0.001541] Mount-cache hash table entries: 16384 (order: 5, 131072 bytes)
-[ 0.001912] Mountpoint-cache hash table entries: 16384 (order: 5, 131072 bytes)
-[ 0.003542] rcu: Hierarchical SRCU implementation.
-[ 0.004347] smp: Bringing up secondary CPUs ...
-[ 1.040259] CPU1: failed to come online
-[ 2.080483] CPU2: failed to come online
-[ 3.120699] CPU3: failed to come online
-[ 3.120765] smp: Brought up 1 node, 1 CPU
-[ 3.121923] devtmpfs: initialized
-[ 3.124649] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
-[ 3.124727] futex hash table entries: 1024 (order: 4, 65536 bytes)
-[ 3.125346] random: get_random_u32 called from bucket_table_alloc+0x72/0x172 with crng_init=0
-[ 3.125578] NET: Registered protocol family 16
-[ 3.126400] sifive-u54-prci 10000000.prci: Registered U54 core clocks
-[ 3.126649] sifive-gemgxl-mgmt 100a0000.cadence-gemgxl-mgmt: Registered clock switch 'cadence-gemgxl-mgmt'
-[ 3.135572] vgaarb: loaded
-[ 3.135858] SCSI subsystem initialized
-[ 3.136193] usbcore: registered new interface driver usbfs
-[ 3.136266] usbcore: registered new interface driver hub
-[ 3.136348] usbcore: registered new device driver usb
-[ 3.136446] pps_core: LinuxPPS API ver. 1 registered
-[ 3.136484] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
-[ 3.136575] PTP clock support registered
-[ 3.137256] clocksource: Switched to clocksource riscv_clocksource
-[ 3.142711] NET: Registered protocol family 2
-[ 3.143322] tcp_listen_portaddr_hash hash table entries: 4096 (order: 4, 65536 bytes)
-[ 3.143634] TCP established hash table entries: 65536 (order: 7, 524288 bytes)
-[ 3.145799] TCP bind hash table entries: 65536 (order: 8, 1048576 bytes)
-[ 3.149121] TCP: Hash tables configured (established 65536 bind 65536)
-[ 3.149591] UDP hash table entries: 4096 (order: 5, 131072 bytes)
-[ 3.150094] UDP-Lite hash table entries: 4096 (order: 5, 131072 bytes)
-[ 3.150781] NET: Registered protocol family 1
-[ 3.230693] workingset: timestamp_bits=62 max_order=21 bucket_order=0
-[ 3.241224] io scheduler mq-deadline registered
-[ 3.241269] io scheduler kyber registered
-[ 3.242143] sifive_gpio 10060000.gpio: SiFive GPIO chip registered 16 GPIOs
-[ 3.242357] pwm-sifivem 10020000.pwm: Unable to find controller clock
-[ 3.242439] pwm-sifivem 10021000.pwm: Unable to find controller clock
-[ 3.243228] xilinx-pcie 2000000000.pci: PCIe Link is DOWN
-[ 3.243289] xilinx-pcie 2000000000.pci: host bridge /soc/pci@2000000000 ranges:
-[ 3.243360] xilinx-pcie 2000000000.pci: No bus range found for /soc/pci@2000000000, using [bus 00-ff]
-[ 3.243447] xilinx-pcie 2000000000.pci: MEM 0x40000000..0x5fffffff -> 0x40000000
-[ 3.243591] xilinx-pcie 2000000000.pci: PCI host bridge to bus 0000:00
-[ 3.243636] pci_bus 0000:00: root bus resource [bus 00-ff]
-[ 3.243676] pci_bus 0000:00: root bus resource [mem 0x40000000-0x5fffffff]
-[ 3.276547] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
-[ 3.277689] 10010000.serial: ttySIF0 at MMIO 0x10010000 (irq = 39, base_baud = 0) is a SiFive UART v0
-[ 3.786963] printk: console [ttySIF0] enabled
-[ 3.791504] 10011000.serial: ttySIF1 at MMIO 0x10011000 (irq = 40, base_baud = 0) is a SiFive UART v0
-[ 3.801251] sifive_spi 10040000.spi: mapped; irq=41, cs=1
-[ 3.806362] m25p80 spi0.0: unrecognized JEDEC id bytes: 9d, 70, 19
-[ 3.812084] m25p80: probe of spi0.0 failed with error -2
-[ 3.817453] sifive_spi 10041000.spi: mapped; irq=42, cs=4
-[ 3.823027] sifive_spi 10050000.spi: mapped; irq=43, cs=1
-[ 3.828604] libphy: Fixed MDIO Bus: probed
-[ 3.832623] macb: GEM doesn't support hardware ptp.
-[ 3.837196] libphy: MACB_mii_bus: probed
-[ 4.041156] Microsemi VSC8541 SyncE 10090000.ethernet-ffffffff:00: attached PHY driver [Microsemi VSC8541 SyncE] (mii_bus:phy_addr=10090000.ethernet-ffffffff:00, irq=POLL)
-[ 4.055779] macb 10090000.ethernet eth0: Cadence GEM rev 0x10070109 at 0x10090000 irq 12 (70:b3:d5:92:f0:c2)
-[ 4.065780] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
-[ 4.072033] ehci-pci: EHCI PCI platform driver
-[ 4.076521] usbcore: registered new interface driver usb-storage
-[ 4.082843] softdog: initialized. soft_noboot=0 soft_margin=60 sec soft_panic=0 (nowayout=0)
-[ 4.127465] mmc_spi spi2.0: SD/MMC host mmc0, no DMA, no WP, no poweroff
-[ 4.133645] usbcore: registered new interface driver usbhid
-[ 4.138980] usbhid: USB HID core driver
-[ 4.143017] NET: Registered protocol family 17
-[ 4.147885] pwm-sifivem 10020000.pwm: SiFive PWM chip registered 4 PWMs
-[ 4.153945] pwm-sifivem 10021000.pwm: SiFive PWM chip registered 4 PWMs
-[ 4.186407] Freeing unused kernel memory: 9380K
-[ 4.190224] This architecture does not have kernel memory protection.
-[ 4.196609] Run /init as init process
-Starting logging: OK
-Starting mdev...
-[ 4.303785] mmc0: host does not support reading read-only switch, assuming write-enable
-[ 4.311109] mmc0: new SDHC card on SPI
-[ 4.317103] mmcblk0: mmc0:0000 SS08G 7.40 GiB
-[ 4.386471] mmcblk0: p1 p2
-sort: /sys/devices/platform/Fixed: No such file or directory
-modprobe: can't change directory to '/lib/modules': No such file or directory
-Initializing random[ 4.759075] random: dd: uninitialized urandom read (512 bytes read)
- number generator... done.
-Starting network...
-udhcpc (v1.24.2) started
-Sending discover...
-Sending discover...
-[ 7.927510] macb 10090000.ethernet eth0: link up (1000/Full)
-Sending discover...
-Sending select for 10.196.157.190...
-Lease of 10.196.157.190 obtained, lease time 499743
-deleting routers
-adding dns 10.86.1.1
-adding dns 10.86.2.1
-/etc/init.d/S50dropbear
-Starting dropbear sshd: [ 12.772393] random: dropbear: uninitialized urandom read (32 bytes read)
-OK
-
-Welcome to Buildroot
-buildroot login:
diff --git a/doc/README.x86 b/doc/README.x86
deleted file mode 100644
index 8e0a3f3..0000000
--- a/doc/README.x86
+++ /dev/null
@@ -1,1202 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+
-#
-# Copyright (C) 2014, Simon Glass <sjg@chromium.org>
-# Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
-
-U-Boot on x86
-=============
-
-This document describes the information about U-Boot running on x86 targets,
-including supported boards, build instructions, todo list, etc.
-
-Status
-------
-U-Boot supports running as a coreboot [1] payload on x86. So far only Link
-(Chromebook Pixel) and QEMU [2] x86 targets have been tested, but it should
-work with minimal adjustments on other x86 boards since coreboot deals with
-most of the low-level details.
-
-U-Boot is a main bootloader on Intel Edison board.
-
-U-Boot also supports booting directly from x86 reset vector, without coreboot.
-In this case, known as bare mode, from the fact that it runs on the
-'bare metal', U-Boot acts like a BIOS replacement. The following platforms
-are supported:
-
- - Bayley Bay CRB
- - Cherry Hill CRB
- - Congatec QEVAL 2.0 & conga-QA3/E3845
- - Cougar Canyon 2 CRB
- - Crown Bay CRB
- - Galileo
- - Link (Chromebook Pixel)
- - Minnowboard MAX
- - Samus (Chromebook Pixel 2015)
- - QEMU x86 (32-bit & 64-bit)
-
-As for loading an OS, U-Boot supports directly booting a 32-bit or 64-bit
-Linux kernel as part of a FIT image. It also supports a compressed zImage.
-U-Boot supports loading an x86 VxWorks kernel. Please check README.vxworks
-for more details.
-
-Build Instructions for U-Boot as coreboot payload
--------------------------------------------------
-Building U-Boot as a coreboot payload is just like building U-Boot for targets
-on other architectures, like below:
-
-$ make coreboot_defconfig
-$ make all
-
-Build Instructions for U-Boot as main bootloader
-------------------------------------------------
-
-Intel Edison instructions:
-
-Simple you can build U-Boot and obtain u-boot.bin
-
-$ make edison_defconfig
-$ make all
-
-Build Instructions for U-Boot as BIOS replacement (bare mode)
--------------------------------------------------------------
-Building a ROM version of U-Boot (hereafter referred to as u-boot.rom) is a
-little bit tricky, as generally it requires several binary blobs which are not
-shipped in the U-Boot source tree. Due to this reason, the u-boot.rom build is
-not turned on by default in the U-Boot source tree. Firstly, you need turn it
-on by enabling the ROM build either via an environment variable
-
- $ export BUILD_ROM=y
-
-or via configuration
-
- CONFIG_BUILD_ROM=y
-
-Both tell the Makefile to build u-boot.rom as a target.
-
----
-
-Chromebook Link specific instructions for bare mode:
-
-First, you need the following binary blobs:
-
-* descriptor.bin - Intel flash descriptor
-* me.bin - Intel Management Engine
-* mrc.bin - Memory Reference Code, which sets up SDRAM
-* video ROM - sets up the display
-
-You can get these binary blobs by:
-
-$ git clone http://review.coreboot.org/p/blobs.git
-$ cd blobs
-
-Find the following files:
-
-* ./mainboard/google/link/descriptor.bin
-* ./mainboard/google/link/me.bin
-* ./northbridge/intel/sandybridge/systemagent-r6.bin
-
-The 3rd one should be renamed to mrc.bin.
-As for the video ROM, you can get it here [3] and rename it to vga.bin.
-Make sure all these binary blobs are put in the board directory.
-
-Now you can build U-Boot and obtain u-boot.rom:
-
-$ make chromebook_link_defconfig
-$ make all
-
----
-
-Chromebook Samus (2015 Pixel) instructions for bare mode:
-
-First, you need the following binary blobs:
-
-* descriptor.bin - Intel flash descriptor
-* me.bin - Intel Management Engine
-* mrc.bin - Memory Reference Code, which sets up SDRAM
-* refcode.elf - Additional Reference code
-* vga.bin - video ROM, which sets up the display
-
-If you have a samus you can obtain them from your flash, for example, in
-developer mode on the Chromebook (use Ctrl-Alt-F2 to obtain a terminal and
-log in as 'root'):
-
- cd /tmp
- flashrom -w samus.bin
- scp samus.bin username@ip_address:/path/to/somewhere
-
-If not see the coreboot tree [4] where you can use:
-
- bash crosfirmware.sh samus
-
-to get the image. There is also an 'extract_blobs.sh' scripts that you can use
-on the 'coreboot-Google_Samus.*' file to short-circuit some of the below.
-
-Then 'ifdtool -x samus.bin' on your development machine will produce:
-
- flashregion_0_flashdescriptor.bin
- flashregion_1_bios.bin
- flashregion_2_intel_me.bin
-
-Rename flashregion_0_flashdescriptor.bin to descriptor.bin
-Rename flashregion_2_intel_me.bin to me.bin
-You can ignore flashregion_1_bios.bin - it is not used.
-
-To get the rest, use 'cbfstool samus.bin print':
-
-samus.bin: 8192 kB, bootblocksize 2864, romsize 8388608, offset 0x700000
-alignment: 64 bytes, architecture: x86
-
-Name Offset Type Size
-cmos_layout.bin 0x700000 cmos_layout 1164
-pci8086,0406.rom 0x7004c0 optionrom 65536
-spd.bin 0x710500 (unknown) 4096
-cpu_microcode_blob.bin 0x711540 microcode 70720
-fallback/romstage 0x722a00 stage 54210
-fallback/ramstage 0x72fe00 stage 96382
-config 0x7476c0 raw 6075
-fallback/vboot 0x748ec0 stage 15980
-fallback/refcode 0x74cd80 stage 75578
-fallback/payload 0x75f500 payload 62878
-u-boot.dtb 0x76eb00 (unknown) 5318
-(empty) 0x770000 null 196504
-mrc.bin 0x79ffc0 (unknown) 222876
-(empty) 0x7d66c0 null 167320
-
-You can extract what you need:
-
- cbfstool samus.bin extract -n pci8086,0406.rom -f vga.bin
- cbfstool samus.bin extract -n fallback/refcode -f refcode.rmod
- cbfstool samus.bin extract -n mrc.bin -f mrc.bin
- cbfstool samus.bin extract -n fallback/refcode -f refcode.bin -U
-
-Note that the -U flag is only supported by the latest cbfstool. It unpacks
-and decompresses the stage to produce a coreboot rmodule. This is a simple
-representation of an ELF file. You need the patch "Support decoding a stage
-with compression".
-
-Put all 5 files into board/google/chromebook_samus.
-
-Now you can build U-Boot and obtain u-boot.rom:
-
-$ make chromebook_link_defconfig
-$ make all
-
-If you are using em100, then this command will flash write -Boot:
-
- em100 -s -d filename.rom -c W25Q64CV -r
-
-Flash map for samus / broadwell:
-
- fffff800 SYS_X86_START16
- ffff0000 RESET_SEG_START
- fffd8000 TPL_TEXT_BASE
- fffa0000 X86_MRC_ADDR
- fff90000 VGA_BIOS_ADDR
- ffed0000 SYS_TEXT_BASE
- ffea0000 X86_REFCODE_ADDR
- ffe70000 SPL_TEXT_BASE
- ffbf8000 CONFIG_ENV_OFFSET (environemnt offset)
- ffbe0000 rw-mrc-cache (Memory-reference-code cache)
- ffa00000 <spare>
- ff801000 intel-me (address set by descriptor.bin)
- ff800000 intel-descriptor
-
----
-
-Intel Crown Bay specific instructions for bare mode:
-
-U-Boot support of Intel Crown Bay board [4] relies on a binary blob called
-Firmware Support Package [5] to perform all the necessary initialization steps
-as documented in the BIOS Writer Guide, including initialization of the CPU,
-memory controller, chipset and certain bus interfaces.
-
-Download the Intel FSP for Atom E6xx series and Platform Controller Hub EG20T,
-install it on your host and locate the FSP binary blob. Note this platform
-also requires a Chipset Micro Code (CMC) state machine binary to be present in
-the SPI flash where u-boot.rom resides, and this CMC binary blob can be found
-in this FSP package too.
-
-* ./FSP/QUEENSBAY_FSP_GOLD_001_20-DECEMBER-2013.fd
-* ./Microcode/C0_22211.BIN
-
-Rename the first one to fsp.bin and second one to cmc.bin and put them in the
-board directory.
-
-Note the FSP release version 001 has a bug which could cause random endless
-loop during the FspInit call. This bug was published by Intel although Intel
-did not describe any details. We need manually apply the patch to the FSP
-binary using any hex editor (eg: bvi). Go to the offset 0x1fcd8 of the FSP
-binary, change the following five bytes values from orginally E8 42 FF FF FF
-to B8 00 80 0B 00.
-
-As for the video ROM, you need manually extract it from the Intel provided
-BIOS for Crown Bay here [6], using the AMI MMTool [7]. Check PCI option ROM
-ID 8086:4108, extract and save it as vga.bin in the board directory.
-
-Now you can build U-Boot and obtain u-boot.rom
-
-$ make crownbay_defconfig
-$ make all
-
----
-
-Intel Cougar Canyon 2 specific instructions for bare mode:
-
-This uses Intel FSP for 3rd generation Intel Core and Intel Celeron processors
-with mobile Intel HM76 and QM77 chipsets platform. Download it from Intel FSP
-website and put the .fd file (CHIEFRIVER_FSP_GOLD_001_09-OCTOBER-2013.fd at the
-time of writing) in the board directory and rename it to fsp.bin.
-
-Now build U-Boot and obtain u-boot.rom
-
-$ make cougarcanyon2_defconfig
-$ make all
-
-The board has two 8MB SPI flashes mounted, which are called SPI-0 and SPI-1 in
-the board manual. The SPI-0 flash should have flash descriptor plus ME firmware
-and SPI-1 flash is used to store U-Boot. For convenience, the complete 8MB SPI-0
-flash image is included in the FSP package (named Rom00_8M_MB_PPT.bin). Program
-this image to the SPI-0 flash according to the board manual just once and we are
-all set. For programming U-Boot we just need to program SPI-1 flash. Since the
-default u-boot.rom image for this board is set to 2MB, it should be programmed
-to the last 2MB of the 8MB chip, address range [600000, 7FFFFF].
-
----
-
-Intel Bay Trail based board instructions for bare mode:
-
-This uses as FSP as with Crown Bay, except it is for the Atom E3800 series.
-Two boards that use this configuration are Bayley Bay and Minnowboard MAX.
-Download this and get the .fd file (BAYTRAIL_FSP_GOLD_003_16-SEP-2014.fd at
-the time of writing). Put it in the corresponding board directory and rename
-it to fsp.bin.
-
-Obtain the VGA RAM (Vga.dat at the time of writing) and put it into the same
-board directory as vga.bin.
-
-You still need two more binary blobs. For Bayley Bay, they can be extracted
-from the sample SPI image provided in the FSP (SPI.bin at the time of writing).
-
- $ ./tools/ifdtool -x BayleyBay/SPI.bin
- $ cp flashregion_0_flashdescriptor.bin board/intel/bayleybay/descriptor.bin
- $ cp flashregion_2_intel_me.bin board/intel/bayleybay/me.bin
-
-For Minnowboard MAX, we can reuse the same ME firmware above, but for flash
-descriptor, we need get that somewhere else, as the one above does not seem to
-work, probably because it is not designed for the Minnowboard MAX. Now download
-the original firmware image for this board from:
-
-http://firmware.intel.com/sites/default/files/2014-WW42.4-MinnowBoardMax.73-64-bit.bin_Release.zip
-
-Unzip it:
-
- $ unzip 2014-WW42.4-MinnowBoardMax.73-64-bit.bin_Release.zip
-
-Use ifdtool in the U-Boot tools directory to extract the images from that
-file, for example:
-
- $ ./tools/ifdtool -x MNW2MAX1.X64.0073.R02.1409160934.bin
-
-This will provide the descriptor file - copy this into the correct place:
-
- $ cp flashregion_0_flashdescriptor.bin board/intel/minnowmax/descriptor.bin
-
-Now you can build U-Boot and obtain u-boot.rom
-Note: below are examples/information for Minnowboard MAX.
-
-$ make minnowmax_defconfig
-$ make all
-
-Checksums are as follows (but note that newer versions will invalidate this):
-
-$ md5sum -b board/intel/minnowmax/*.bin
-ffda9a3b94df5b74323afb328d51e6b4 board/intel/minnowmax/descriptor.bin
-69f65b9a580246291d20d08cbef9d7c5 board/intel/minnowmax/fsp.bin
-894a97d371544ec21de9c3e8e1716c4b board/intel/minnowmax/me.bin
-a2588537da387da592a27219d56e9962 board/intel/minnowmax/vga.bin
-
-The ROM image is broken up into these parts:
-
-Offset Description Controlling config
-------------------------------------------------------------
-000000 descriptor.bin Hard-coded to 0 in ifdtool
-001000 me.bin Set by the descriptor
-500000 <spare>
-6ef000 Environment CONFIG_ENV_OFFSET
-6f0000 MRC cache CONFIG_ENABLE_MRC_CACHE
-700000 u-boot-dtb.bin CONFIG_SYS_TEXT_BASE
-7b0000 vga.bin CONFIG_VGA_BIOS_ADDR
-7c0000 fsp.bin CONFIG_FSP_ADDR
-7f8000 <spare> (depends on size of fsp.bin)
-7ff800 U-Boot 16-bit boot CONFIG_SYS_X86_START16
-
-Overall ROM image size is controlled by CONFIG_ROM_SIZE.
-
-Note that the debug version of the FSP is bigger in size. If this version
-is used, CONFIG_FSP_ADDR needs to be configured to 0xfffb0000 instead of
-the default value 0xfffc0000.
-
----
-
-Intel Cherry Hill specific instructions for bare mode:
-
-This uses Intel FSP for Braswell platform. Download it from Intel FSP website,
-put the .fd file to the board directory and rename it to fsp.bin.
-
-Extract descriptor.bin and me.bin from the original BIOS on the board using
-ifdtool and put them to the board directory as well.
-
-Note the FSP package for Braswell does not ship a traditional legacy VGA BIOS
-image for the integrated graphics device. Instead a new binary called Video
-BIOS Table (VBT) is shipped. Put it to the board directory and rename it to
-vbt.bin if you want graphics support in U-Boot.
-
-Now you can build U-Boot and obtain u-boot.rom
-
-$ make cherryhill_defconfig
-$ make all
-
-An important note for programming u-boot.rom to the on-board SPI flash is that
-you need make sure the SPI flash's 'quad enable' bit in its status register
-matches the settings in the descriptor.bin, otherwise the board won't boot.
-
-For the on-board SPI flash MX25U6435F, this can be done by writing 0x40 to the
-status register by DediProg in: Config > Modify Status Register > Write Status
-Register(s) > Register1 Value(Hex). This is is a one-time change. Once set, it
-persists in SPI flash part regardless of the u-boot.rom image burned.
-
----
-
-Intel Galileo instructions for bare mode:
-
-Only one binary blob is needed for Remote Management Unit (RMU) within Intel
-Quark SoC. Not like FSP, U-Boot does not call into the binary. The binary is
-needed by the Quark SoC itself.
-
-You can get the binary blob from Quark Board Support Package from Intel website:
-
-* ./QuarkSocPkg/QuarkNorthCluster/Binary/QuarkMicrocode/RMU.bin
-
-Rename the file and put it to the board directory by:
-
- $ cp RMU.bin board/intel/galileo/rmu.bin
-
-Now you can build U-Boot and obtain u-boot.rom
-
-$ make galileo_defconfig
-$ make all
-
----
-
-QEMU x86 target instructions for bare mode:
-
-To build u-boot.rom for QEMU x86 targets, just simply run
-
-$ make qemu-x86_defconfig (for 32-bit)
-or
-$ make qemu-x86_64_defconfig (for 64-bit)
-$ make all
-
-Note this default configuration will build a U-Boot for the QEMU x86 i440FX
-board. To build a U-Boot against QEMU x86 Q35 board, you can change the build
-configuration during the 'make menuconfig' process like below:
-
-Device Tree Control --->
- ...
- (qemu-x86_q35) Default Device Tree for DT control
-
-Test with coreboot
-------------------
-For testing U-Boot as the coreboot payload, there are things that need be paid
-attention to. coreboot supports loading an ELF executable and a 32-bit plain
-binary, as well as other supported payloads. With the default configuration,
-U-Boot is set up to use a separate Device Tree Blob (dtb). As of today, the
-generated u-boot-dtb.bin needs to be packaged by the cbfstool utility (a tool
-provided by coreboot) manually as coreboot's 'make menuconfig' does not provide
-this capability yet. The command is as follows:
-
-# in the coreboot root directory
-$ ./build/util/cbfstool/cbfstool build/coreboot.rom add-flat-binary \
- -f u-boot-dtb.bin -n fallback/payload -c lzma -l 0x1110000 -e 0x1110000
-
-Make sure 0x1110000 matches CONFIG_SYS_TEXT_BASE, which is the symbol address
-of _x86boot_start (in arch/x86/cpu/start.S).
-
-If you want to use ELF as the coreboot payload, change U-Boot configuration to
-use CONFIG_OF_EMBED instead of CONFIG_OF_SEPARATE.
-
-To enable video you must enable these options in coreboot:
-
- - Set framebuffer graphics resolution (1280x1024 32k-color (1:5:5))
- - Keep VESA framebuffer
-
-At present it seems that for Minnowboard Max, coreboot does not pass through
-the video information correctly (it always says the resolution is 0x0). This
-works correctly for link though.
-
-Test with QEMU for bare mode
-----------------------------
-QEMU is a fancy emulator that can enable us to test U-Boot without access to
-a real x86 board. Please make sure your QEMU version is 2.3.0 or above test
-U-Boot. To launch QEMU with u-boot.rom, call QEMU as follows:
-
-$ qemu-system-i386 -nographic -bios path/to/u-boot.rom
-
-This will instantiate an emulated x86 board with i440FX and PIIX chipset. QEMU
-also supports emulating an x86 board with Q35 and ICH9 based chipset, which is
-also supported by U-Boot. To instantiate such a machine, call QEMU with:
-
-$ qemu-system-i386 -nographic -bios path/to/u-boot.rom -M q35
-
-Note by default QEMU instantiated boards only have 128 MiB system memory. But
-it is enough to have U-Boot boot and function correctly. You can increase the
-system memory by pass '-m' parameter to QEMU if you want more memory:
-
-$ qemu-system-i386 -nographic -bios path/to/u-boot.rom -m 1024
-
-This creates a board with 1 GiB system memory. Currently U-Boot for QEMU only
-supports 3 GiB maximum system memory and reserves the last 1 GiB address space
-for PCI device memory-mapped I/O and other stuff, so the maximum value of '-m'
-would be 3072.
-
-QEMU emulates a graphic card which U-Boot supports. Removing '-nographic' will
-show QEMU's VGA console window. Note this will disable QEMU's serial output.
-If you want to check both consoles, use '-serial stdio'.
-
-Multicore is also supported by QEMU via '-smp n' where n is the number of cores
-to instantiate. Note, the maximum supported CPU number in QEMU is 255.
-
-The fw_cfg interface in QEMU also provides information about kernel data,
-initrd, command-line arguments and more. U-Boot supports directly accessing
-these informtion from fw_cfg interface, which saves the time of loading them
-from hard disk or network again, through emulated devices. To use it , simply
-providing them in QEMU command line:
-
-$ qemu-system-i386 -nographic -bios path/to/u-boot.rom -m 1024 -kernel /path/to/bzImage
- -append 'root=/dev/ram console=ttyS0' -initrd /path/to/initrd -smp 8
-
-Note: -initrd and -smp are both optional
-
-Then start QEMU, in U-Boot command line use the following U-Boot command to
-setup kernel:
-
- => qfw
-qfw - QEMU firmware interface
-
-Usage:
-qfw <command>
- - list : print firmware(s) currently loaded
- - cpus : print online cpu number
- - load <kernel addr> <initrd addr> : load kernel and initrd (if any) and setup for zboot
-
-=> qfw load
-loading kernel to address 01000000 size 5d9d30 initrd 04000000 size 1b1ab50
-
-Here the kernel (bzImage) is loaded to 01000000 and initrd is to 04000000. Then,
-'zboot' can be used to boot the kernel:
-
-=> zboot 01000000 - 04000000 1b1ab50
-
-To run 64-bit U-Boot, qemu-system-x86_64 should be used instead, e.g.:
-$ qemu-system-x86_64 -nographic -bios path/to/u-boot.rom
-
-A specific CPU can be specified via the '-cpu' parameter but please make
-sure the specified CPU supports 64-bit like '-cpu core2duo'. Conversely
-'-cpu pentium' won't work for obvious reasons that the processor only
-supports 32-bit.
-
-Note 64-bit support is very preliminary at this point. Lots of features
-are missing in the 64-bit world. One notable feature is the VGA console
-support which is currently missing, so that you must specify '-nographic'
-to get 64-bit U-Boot up and running.
-
-Updating U-Boot on Edison
--------------------------
-By default Intel Edison boards are shipped with preinstalled heavily
-patched U-Boot v2014.04. Though it supports DFU which we may be able to
-use.
-
-1. Prepare u-boot.bin as described in chapter above. You still need one
-more step (if and only if you have original U-Boot), i.e. run the
-following command:
-
-$ truncate -s %4096 u-boot.bin
-
-2. Run your board and interrupt booting to U-Boot console. In the console
-call:
-
- => run do_force_flash_os
-
-3. Wait for few seconds, it will prepare environment variable and runs
-DFU. Run DFU command from the host system:
-
-$ dfu-util -v -d 8087:0a99 --alt u-boot0 -D u-boot.bin
-
-4. Return to U-Boot console and following hint. i.e. push Ctrl+C, and
-reset the board:
-
- => reset
-
-CPU Microcode
--------------
-Modern CPUs usually require a special bit stream called microcode [8] to be
-loaded on the processor after power up in order to function properly. U-Boot
-has already integrated these as hex dumps in the source tree.
-
-SMP Support
------------
-On a multicore system, U-Boot is executed on the bootstrap processor (BSP).
-Additional application processors (AP) can be brought up by U-Boot. In order to
-have an SMP kernel to discover all of the available processors, U-Boot needs to
-prepare configuration tables which contain the multi-CPUs information before
-loading the OS kernel. Currently U-Boot supports generating two types of tables
-for SMP, called Simple Firmware Interface (SFI) [9] and Multi-Processor (MP)
-[10] tables. The writing of these two tables are controlled by two Kconfig
-options GENERATE_SFI_TABLE and GENERATE_MP_TABLE.
-
-Driver Model
-------------
-x86 has been converted to use driver model for serial, GPIO, SPI, SPI flash,
-keyboard, real-time clock, USB. Video is in progress.
-
-Device Tree
------------
-x86 uses device tree to configure the board thus requires CONFIG_OF_CONTROL to
-be turned on. Not every device on the board is configured via device tree, but
-more and more devices will be added as time goes by. Check out the directory
-arch/x86/dts/ for these device tree source files.
-
-Useful Commands
----------------
-In keeping with the U-Boot philosophy of providing functions to check and
-adjust internal settings, there are several x86-specific commands that may be
-useful:
-
-fsp - Display information about Intel Firmware Support Package (FSP).
- This is only available on platforms which use FSP, mostly Atom.
-iod - Display I/O memory
-iow - Write I/O memory
-mtrr - List and set the Memory Type Range Registers (MTRR). These are used to
- tell the CPU whether memory is cacheable and if so the cache write
- mode to use. U-Boot sets up some reasonable values but you can
- adjust then with this command.
-
-Booting Ubuntu
---------------
-As an example of how to set up your boot flow with U-Boot, here are
-instructions for starting Ubuntu from U-Boot. These instructions have been
-tested on Minnowboard MAX with a SATA drive but are equally applicable on
-other platforms and other media. There are really only four steps and it's a
-very simple script, but a more detailed explanation is provided here for
-completeness.
-
-Note: It is possible to set up U-Boot to boot automatically using syslinux.
-It could also use the grub.cfg file (/efi/ubuntu/grub.cfg) to obtain the
-GUID. If you figure these out, please post patches to this README.
-
-Firstly, you will need Ubuntu installed on an available disk. It should be
-possible to make U-Boot start a USB start-up disk but for now let's assume
-that you used another boot loader to install Ubuntu.
-
-Use the U-Boot command line to find the UUID of the partition you want to
-boot. For example our disk is SCSI device 0:
-
-=> part list scsi 0
-
-Partition Map for SCSI device 0 -- Partition Type: EFI
-
- Part Start LBA End LBA Name
- Attributes
- Type GUID
- Partition GUID
- 1 0x00000800 0x001007ff ""
- attrs: 0x0000000000000000
- type: c12a7328-f81f-11d2-ba4b-00a0c93ec93b
- guid: 9d02e8e4-4d59-408f-a9b0-fd497bc9291c
- 2 0x00100800 0x037d8fff ""
- attrs: 0x0000000000000000
- type: 0fc63daf-8483-4772-8e79-3d69d8477de4
- guid: 965c59ee-1822-4326-90d2-b02446050059
- 3 0x037d9000 0x03ba27ff ""
- attrs: 0x0000000000000000
- type: 0657fd6d-a4ab-43c4-84e5-0933c84b4f4f
- guid: 2c4282bd-1e82-4bcf-a5ff-51dedbf39f17
- =>
-
-This shows that your SCSI disk has three partitions. The really long hex
-strings are called Globally Unique Identifiers (GUIDs). You can look up the
-'type' ones here [11]. On this disk the first partition is for EFI and is in
-VFAT format (DOS/Windows):
-
- => fatls scsi 0:1
- efi/
-
- 0 file(s), 1 dir(s)
-
-
-Partition 2 is 'Linux filesystem data' so that will be our root disk. It is
-in ext2 format:
-
- => ext2ls scsi 0:2
- <DIR> 4096 .
- <DIR> 4096 ..
- <DIR> 16384 lost+found
- <DIR> 4096 boot
- <DIR> 12288 etc
- <DIR> 4096 media
- <DIR> 4096 bin
- <DIR> 4096 dev
- <DIR> 4096 home
- <DIR> 4096 lib
- <DIR> 4096 lib64
- <DIR> 4096 mnt
- <DIR> 4096 opt
- <DIR> 4096 proc
- <DIR> 4096 root
- <DIR> 4096 run
- <DIR> 12288 sbin
- <DIR> 4096 srv
- <DIR> 4096 sys
- <DIR> 4096 tmp
- <DIR> 4096 usr
- <DIR> 4096 var
- <SYM> 33 initrd.img
- <SYM> 30 vmlinuz
- <DIR> 4096 cdrom
- <SYM> 33 initrd.img.old
- =>
-
-and if you look in the /boot directory you will see the kernel:
-
- => ext2ls scsi 0:2 /boot
- <DIR> 4096 .
- <DIR> 4096 ..
- <DIR> 4096 efi
- <DIR> 4096 grub
- 3381262 System.map-3.13.0-32-generic
- 1162712 abi-3.13.0-32-generic
- 165611 config-3.13.0-32-generic
- 176500 memtest86+.bin
- 178176 memtest86+.elf
- 178680 memtest86+_multiboot.bin
- 5798112 vmlinuz-3.13.0-32-generic
- 165762 config-3.13.0-58-generic
- 1165129 abi-3.13.0-58-generic
- 5823136 vmlinuz-3.13.0-58-generic
- 19215259 initrd.img-3.13.0-58-generic
- 3391763 System.map-3.13.0-58-generic
- 5825048 vmlinuz-3.13.0-58-generic.efi.signed
- 28304443 initrd.img-3.13.0-32-generic
- =>
-
-The 'vmlinuz' files contain a packaged Linux kernel. The format is a kind of
-self-extracting compressed file mixed with some 'setup' configuration data.
-Despite its size (uncompressed it is >10MB) this only includes a basic set of
-device drivers, enough to boot on most hardware types.
-
-The 'initrd' files contain a RAM disk. This is something that can be loaded
-into RAM and will appear to Linux like a disk. Ubuntu uses this to hold lots
-of drivers for whatever hardware you might have. It is loaded before the
-real root disk is accessed.
-
-The numbers after the end of each file are the version. Here it is Linux
-version 3.13. You can find the source code for this in the Linux tree with
-the tag v3.13. The '.0' allows for additional Linux releases to fix problems,
-but normally this is not needed. The '-58' is used by Ubuntu. Each time they
-release a new kernel they increment this number. New Ubuntu versions might
-include kernel patches to fix reported bugs. Stable kernels can exist for
-some years so this number can get quite high.
-
-The '.efi.signed' kernel is signed for EFI's secure boot. U-Boot has its own
-secure boot mechanism - see [12] [13] and cannot read .efi files at present.
-
-To boot Ubuntu from U-Boot the steps are as follows:
-
-1. Set up the boot arguments. Use the GUID for the partition you want to
-boot:
-
- => setenv bootargs root=/dev/disk/by-partuuid/965c59ee-1822-4326-90d2-b02446050059 ro
-
-Here root= tells Linux the location of its root disk. The disk is specified
-by its GUID, using '/dev/disk/by-partuuid/', a Linux path to a 'directory'
-containing all the GUIDs Linux has found. When it starts up, there will be a
-file in that directory with this name in it. It is also possible to use a
-device name here, see later.
-
-2. Load the kernel. Since it is an ext2/4 filesystem we can do:
-
- => ext2load scsi 0:2 03000000 /boot/vmlinuz-3.13.0-58-generic
-
-The address 30000000 is arbitrary, but there seem to be problems with using
-small addresses (sometimes Linux cannot find the ramdisk). This is 48MB into
-the start of RAM (which is at 0 on x86).
-
-3. Load the ramdisk (to 64MB):
-
- => ext2load scsi 0:2 04000000 /boot/initrd.img-3.13.0-58-generic
-
-4. Start up the kernel. We need to know the size of the ramdisk, but can use
-a variable for that. U-Boot sets 'filesize' to the size of the last file it
-loaded.
-
- => zboot 03000000 0 04000000 ${filesize}
-
-Type 'help zboot' if you want to see what the arguments are. U-Boot on x86 is
-quite verbose when it boots a kernel. You should see these messages from
-U-Boot:
-
- Valid Boot Flag
- Setup Size = 0x00004400
- Magic signature found
- Using boot protocol version 2.0c
- Linux kernel version 3.13.0-58-generic (buildd@allspice) #97-Ubuntu SMP Wed Jul 8 02:56:15 UTC 2015
- Building boot_params at 0x00090000
- Loading bzImage at address 100000 (5805728 bytes)
- Magic signature found
- Initial RAM disk at linear address 0x04000000, size 19215259 bytes
- Kernel command line: "root=/dev/disk/by-partuuid/965c59ee-1822-4326-90d2-b02446050059 ro"
-
- Starting kernel ...
-
-U-Boot prints out some bootstage timing. This is more useful if you put the
-above commands into a script since then it will be faster.
-
- Timer summary in microseconds:
- Mark Elapsed Stage
- 0 0 reset
- 241,535 241,535 board_init_r
- 2,421,611 2,180,076 id=64
- 2,421,790 179 id=65
- 2,428,215 6,425 main_loop
- 48,860,584 46,432,369 start_kernel
-
- Accumulated time:
- 240,329 ahci
- 1,422,704 vesa display
-
-Now the kernel actually starts: (if you want to examine kernel boot up message
-on the serial console, append "console=ttyS0,115200" to the kernel command line)
-
- [ 0.000000] Initializing cgroup subsys cpuset
- [ 0.000000] Initializing cgroup subsys cpu
- [ 0.000000] Initializing cgroup subsys cpuacct
- [ 0.000000] Linux version 3.13.0-58-generic (buildd@allspice) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #97-Ubuntu SMP Wed Jul 8 02:56:15 UTC 2015 (Ubuntu 3.13.0-58.97-generic 3.13.11-ckt22)
- [ 0.000000] Command line: root=/dev/disk/by-partuuid/965c59ee-1822-4326-90d2-b02446050059 ro console=ttyS0,115200
-
-It continues for a long time. Along the way you will see it pick up your
-ramdisk:
-
- [ 0.000000] RAMDISK: [mem 0x04000000-0x05253fff]
-...
- [ 0.788540] Trying to unpack rootfs image as initramfs...
- [ 1.540111] Freeing initrd memory: 18768K (ffff880004000000 - ffff880005254000)
-...
-
-Later it actually starts using it:
-
- Begin: Running /scripts/local-premount ... done.
-
-You should also see your boot disk turn up:
-
- [ 4.357243] scsi 1:0:0:0: Direct-Access ATA ADATA SP310 5.2 PQ: 0 ANSI: 5
- [ 4.366860] sd 1:0:0:0: [sda] 62533296 512-byte logical blocks: (32.0 GB/29.8 GiB)
- [ 4.375677] sd 1:0:0:0: Attached scsi generic sg0 type 0
- [ 4.381859] sd 1:0:0:0: [sda] Write Protect is off
- [ 4.387452] sd 1:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
- [ 4.399535] sda: sda1 sda2 sda3
-
-Linux has found the three partitions (sda1-3). Mercifully it doesn't print out
-the GUIDs. In step 1 above we could have used:
-
- setenv bootargs root=/dev/sda2 ro
-
-instead of the GUID. However if you add another drive to your board the
-numbering may change whereas the GUIDs will not. So if your boot partition
-becomes sdb2, it will still boot. For embedded systems where you just want to
-boot the first disk, you have that option.
-
-The last thing you will see on the console is mention of plymouth (which
-displays the Ubuntu start-up screen) and a lot of 'Starting' messages:
-
- * Starting Mount filesystems on boot [ OK ]
-
-After a pause you should see a login screen on your display and you are done.
-
-If you want to put this in a script you can use something like this:
-
- setenv bootargs root=UUID=b2aaf743-0418-4d90-94cc-3e6108d7d968 ro
- setenv boot zboot 03000000 0 04000000 \${filesize}
- setenv bootcmd "ext2load scsi 0:2 03000000 /boot/vmlinuz-3.13.0-58-generic; ext2load scsi 0:2 04000000 /boot/initrd.img-3.13.0-58-generic; run boot"
- saveenv
-
-The \ is to tell the shell not to evaluate ${filesize} as part of the setenv
-command.
-
-You can also bake this behaviour into your build by hard-coding the
-environment variables if you add this to minnowmax.h:
-
-#undef CONFIG_BOOTCOMMAND
-#define CONFIG_BOOTCOMMAND \
- "ext2load scsi 0:2 03000000 /boot/vmlinuz-3.13.0-58-generic; " \
- "ext2load scsi 0:2 04000000 /boot/initrd.img-3.13.0-58-generic; " \
- "run boot"
-
-#undef CONFIG_EXTRA_ENV_SETTINGS
-#define CONFIG_EXTRA_ENV_SETTINGS "boot=zboot 03000000 0 04000000 ${filesize}"
-
-and change CONFIG_BOOTARGS value in configs/minnowmax_defconfig to:
-
-CONFIG_BOOTARGS="root=/dev/sda2 ro"
-
-Test with SeaBIOS
------------------
-SeaBIOS [14] is an open source implementation of a 16-bit x86 BIOS. It can run
-in an emulator or natively on x86 hardware with the use of U-Boot. With its
-help, we can boot some OSes that require 16-bit BIOS services like Windows/DOS.
-
-As U-Boot, we have to manually create a table where SeaBIOS gets various system
-information (eg: E820) from. The table unfortunately has to follow the coreboot
-table format as SeaBIOS currently supports booting as a coreboot payload.
-
-To support loading SeaBIOS, U-Boot should be built with CONFIG_SEABIOS on.
-Booting SeaBIOS is done via U-Boot's bootelf command, like below:
-
- => tftp bios.bin.elf;bootelf
- Using e1000#0 device
- TFTP from server 10.10.0.100; our IP address is 10.10.0.108
- ...
- Bytes transferred = 122124 (1dd0c hex)
- ## Starting application at 0x000ff06e ...
- SeaBIOS (version rel-1.9.0)
- ...
-
-bios.bin.elf is the SeaBIOS image built from SeaBIOS source tree.
-Make sure it is built as follows:
-
- $ make menuconfig
-
-Inside the "General Features" menu, select "Build for coreboot" as the
-"Build Target". Inside the "Debugging" menu, turn on "Serial port debugging"
-so that we can see something as soon as SeaBIOS boots. Leave other options
-as in their default state. Then,
-
- $ make
- ...
- Total size: 121888 Fixed: 66496 Free: 9184 (used 93.0% of 128KiB rom)
- Creating out/bios.bin.elf
-
-Currently this is tested on QEMU x86 target with U-Boot chain-loading SeaBIOS
-to install/boot a Windows XP OS (below for example command to install Windows).
-
- # Create a 10G disk.img as the virtual hard disk
- $ qemu-img create -f qcow2 disk.img 10G
-
- # Install a Windows XP OS from an ISO image 'winxp.iso'
- $ qemu-system-i386 -serial stdio -bios u-boot.rom -hda disk.img -cdrom winxp.iso -smp 2 -m 512
-
- # Boot a Windows XP OS installed on the virutal hard disk
- $ qemu-system-i386 -serial stdio -bios u-boot.rom -hda disk.img -smp 2 -m 512
-
-This is also tested on Intel Crown Bay board with a PCIe graphics card, booting
-SeaBIOS then chain-loading a GRUB on a USB drive, then Linux kernel finally.
-
-If you are using Intel Integrated Graphics Device (IGD) as the primary display
-device on your board, SeaBIOS needs to be patched manually to get its VGA ROM
-loaded and run by SeaBIOS. SeaBIOS locates VGA ROM via the PCI expansion ROM
-register, but IGD device does not have its VGA ROM mapped by this register.
-Its VGA ROM is packaged as part of u-boot.rom at a configurable flash address
-which is unknown to SeaBIOS. An example patch is needed for SeaBIOS below:
-
-diff --git a/src/optionroms.c b/src/optionroms.c
-index 65f7fe0..c7b6f5e 100644
---- a/src/optionroms.c
-+++ b/src/optionroms.c
-@@ -324,6 +324,8 @@ init_pcirom(struct pci_device *pci, int isvga, u64 *sources)
- rom = deploy_romfile(file);
- else if (RunPCIroms > 1 || (RunPCIroms == 1 && isvga))
- rom = map_pcirom(pci);
-+ if (pci->bdf == pci_to_bdf(0, 2, 0))
-+ rom = (struct rom_header *)0xfff90000;
- if (! rom)
- // No ROM present.
- return;
-
-Note: the patch above expects IGD device is at PCI b.d.f 0.2.0 and its VGA ROM
-is at 0xfff90000 which corresponds to CONFIG_VGA_BIOS_ADDR on Minnowboard MAX.
-Change these two accordingly if this is not the case on your board.
-
-Development Flow
-----------------
-These notes are for those who want to port U-Boot to a new x86 platform.
-
-Since x86 CPUs boot from SPI flash, a SPI flash emulator is a good investment.
-The Dediprog em100 can be used on Linux. The em100 tool is available here:
-
- http://review.coreboot.org/p/em100.git
-
-On Minnowboard Max the following command line can be used:
-
- sudo em100 -s -p LOW -d u-boot.rom -c W25Q64DW -r
-
-A suitable clip for connecting over the SPI flash chip is here:
-
- http://www.dediprog.com/pd/programmer-accessories/EM-TC-8
-
-This allows you to override the SPI flash contents for development purposes.
-Typically you can write to the em100 in around 1200ms, considerably faster
-than programming the real flash device each time. The only important
-limitation of the em100 is that it only supports SPI bus speeds up to 20MHz.
-This means that images must be set to boot with that speed. This is an
-Intel-specific feature - e.g. tools/ifttool has an option to set the SPI
-speed in the SPI descriptor region.
-
-If your chip/board uses an Intel Firmware Support Package (FSP) it is fairly
-easy to fit it in. You can follow the Minnowboard Max implementation, for
-example. Hopefully you will just need to create new files similar to those
-in arch/x86/cpu/baytrail which provide Bay Trail support.
-
-If you are not using an FSP you have more freedom and more responsibility.
-The ivybridge support works this way, although it still uses a ROM for
-graphics and still has binary blobs containing Intel code. You should aim to
-support all important peripherals on your platform including video and storage.
-Use the device tree for configuration where possible.
-
-For the microcode you can create a suitable device tree file using the
-microcode tool:
-
- ./tools/microcode-tool -d microcode.dat -m <model> create
-
-or if you only have header files and not the full Intel microcode.dat database:
-
- ./tools/microcode-tool -H BAY_TRAIL_FSP_KIT/Microcode/M0130673322.h \
- -H BAY_TRAIL_FSP_KIT/Microcode/M0130679901.h \
- -m all create
-
-These are written to arch/x86/dts/microcode/ by default.
-
-Note that it is possible to just add the micrcode for your CPU if you know its
-model. U-Boot prints this information when it starts
-
- CPU: x86_64, vendor Intel, device 30673h
-
-so here we can use the M0130673322 file.
-
-If you platform can display POST codes on two little 7-segment displays on
-the board, then you can use post_code() calls from C or assembler to monitor
-boot progress. This can be good for debugging.
-
-If not, you can try to get serial working as early as possible. The early
-debug serial port may be useful here. See setup_internal_uart() for an example.
-
-During the U-Boot porting, one of the important steps is to write correct PIRQ
-routing information in the board device tree. Without it, device drivers in the
-Linux kernel won't function correctly due to interrupt is not working. Please
-refer to U-Boot doc [15] for the device tree bindings of Intel interrupt router.
-Here we have more details on the intel,pirq-routing property below.
-
- intel,pirq-routing = <
- PCI_BDF(0, 2, 0) INTA PIRQA
- ...
- >;
-
-As you see each entry has 3 cells. For the first one, we need describe all pci
-devices mounted on the board. For SoC devices, normally there is a chapter on
-the chipset datasheet which lists all the available PCI devices. For example on
-Bay Trail, this is chapter 4.3 (PCI configuration space). For the second one, we
-can get the interrupt pin either from datasheet or hardware via U-Boot shell.
-The reliable source is the hardware as sometimes chipset datasheet is not 100%
-up-to-date. Type 'pci header' plus the device's pci bus/device/function number
-from U-Boot shell below.
-
- => pci header 0.1e.1
- vendor ID = 0x8086
- device ID = 0x0f08
- ...
- interrupt line = 0x09
- interrupt pin = 0x04
- ...
-
-It shows this PCI device is using INTD pin as it reports 4 in the interrupt pin
-register. Repeat this until you get interrupt pins for all the devices. The last
-cell is the PIRQ line which a particular interrupt pin is mapped to. On Intel
-chipset, the power-up default mapping is INTA/B/C/D maps to PIRQA/B/C/D. This
-can be changed by registers in LPC bridge. So far Intel FSP does not touch those
-registers so we can write down the PIRQ according to the default mapping rule.
-
-Once we get the PIRQ routing information in the device tree, the interrupt
-allocation and assignment will be done by U-Boot automatically. Now you can
-enable CONFIG_GENERATE_PIRQ_TABLE for testing Linux kernel using i8259 PIC and
-CONFIG_GENERATE_MP_TABLE for testing Linux kernel using local APIC and I/O APIC.
-
-This script might be useful. If you feed it the output of 'pci long' from
-U-Boot then it will generate a device tree fragment with the interrupt
-configuration for each device (note it needs gawk 4.0.0):
-
- $ cat console_output |awk '/PCI/ {device=$4} /interrupt line/ {line=$4} \
- /interrupt pin/ {pin = $4; if (pin != "0x00" && pin != "0xff") \
- {patsplit(device, bdf, "[0-9a-f]+"); \
- printf "PCI_BDF(%d, %d, %d) INT%c PIRQ%c\n", strtonum("0x" bdf[1]), \
- strtonum("0x" bdf[2]), bdf[3], strtonum(pin) + 64, 64 + strtonum(pin)}}'
-
-Example output:
- PCI_BDF(0, 2, 0) INTA PIRQA
- PCI_BDF(0, 3, 0) INTA PIRQA
-...
-
-Porting Hints
--------------
-
-Quark-specific considerations:
-
-To port U-Boot to other boards based on the Intel Quark SoC, a few things need
-to be taken care of. The first important part is the Memory Reference Code (MRC)
-parameters. Quark MRC supports memory-down configuration only. All these MRC
-parameters are supplied via the board device tree. To get started, first copy
-the MRC section of arch/x86/dts/galileo.dts to your board's device tree, then
-change these values by consulting board manuals or your hardware vendor.
-Available MRC parameter values are listed in include/dt-bindings/mrc/quark.h.
-The other tricky part is with PCIe. Quark SoC integrates two PCIe root ports,
-but by default they are held in reset after power on. In U-Boot, PCIe
-initialization is properly handled as per Quark's firmware writer guide.
-In your board support codes, you need provide two routines to aid PCIe
-initialization, which are board_assert_perst() and board_deassert_perst().
-The two routines need implement a board-specific mechanism to assert/deassert
-PCIe PERST# pin. Care must be taken that in those routines that any APIs that
-may trigger PCI enumeration process are strictly forbidden, as any access to
-PCIe root port's configuration registers will cause system hang while it is
-held in reset. For more details, check how they are implemented by the Intel
-Galileo board support codes in board/intel/galileo/galileo.c.
-
-coreboot:
-
-See scripts/coreboot.sed which can assist with porting coreboot code into
-U-Boot drivers. It will not resolve all build errors, but will perform common
-transformations. Remember to add attribution to coreboot for new files added
-to U-Boot. This should go at the top of each file and list the coreboot
-filename where the code originated.
-
-Debugging ACPI issues with Windows:
-
-Windows might cache system information and only detect ACPI changes if you
-modify the ACPI table versions. So tweak them liberally when debugging ACPI
-issues with Windows.
-
-ACPI Support Status
--------------------
-Advanced Configuration and Power Interface (ACPI) [16] aims to establish
-industry-standard interfaces enabling OS-directed configuration, power
-management, and thermal management of mobile, desktop, and server platforms.
-
-Linux can boot without ACPI with "acpi=off" command line parameter, but
-with ACPI the kernel gains the capabilities to handle power management.
-For Windows, ACPI is a must-have firmware feature since Windows Vista.
-CONFIG_GENERATE_ACPI_TABLE is the config option to turn on ACPI support in
-U-Boot. This requires Intel ACPI compiler to be installed on your host to
-compile ACPI DSDT table written in ASL format to AML format. You can get
-the compiler via "apt-get install iasl" if you are on Ubuntu or download
-the source from [17] to compile one by yourself.
-
-Current ACPI support in U-Boot is basically complete. More optional features
-can be added in the future. The status as of today is:
-
- * Support generating RSDT, XSDT, FACS, FADT, MADT, MCFG tables.
- * Support one static DSDT table only, compiled by Intel ACPI compiler.
- * Support S0/S3/S4/S5, reboot and shutdown from OS.
- * Support booting a pre-installed Ubuntu distribution via 'zboot' command.
- * Support installing and booting Ubuntu 14.04 (or above) from U-Boot with
- the help of SeaBIOS using legacy interface (non-UEFI mode).
- * Support installing and booting Windows 8.1/10 from U-Boot with the help
- of SeaBIOS using legacy interface (non-UEFI mode).
- * Support ACPI interrupts with SCI only.
-
-Features that are optional:
- * Dynamic AML bytecodes insertion at run-time. We may need this to support
- SSDT table generation and DSDT fix up.
- * SMI support. Since U-Boot is a modern bootloader, we don't want to bring
- those legacy stuff into U-Boot. ACPI spec allows a system that does not
- support SMI (a legacy-free system).
-
-ACPI was initially enabled on BayTrail based boards. Testing was done by booting
-a pre-installed Ubuntu 14.04 from a SATA drive. Installing Ubuntu 14.04 and
-Windows 8.1/10 to a SATA drive and booting from there is also tested. Most
-devices seem to work correctly and the board can respond a reboot/shutdown
-command from the OS.
-
-For other platform boards, ACPI support status can be checked by examining their
-board defconfig files to see if CONFIG_GENERATE_ACPI_TABLE is set to y.
-
-The S3 sleeping state is a low wake latency sleeping state defined by ACPI
-spec where all system context is lost except system memory. To test S3 resume
-with a Linux kernel, simply run "echo mem > /sys/power/state" and kernel will
-put the board to S3 state where the power is off. So when the power button is
-pressed again, U-Boot runs as it does in cold boot and detects the sleeping
-state via ACPI register to see if it is S3, if yes it means we are waking up.
-U-Boot is responsible for restoring the machine state as it is before sleep.
-When everything is done, U-Boot finds out the wakeup vector provided by OSes
-and jump there. To determine whether ACPI S3 resume is supported, check to
-see if CONFIG_HAVE_ACPI_RESUME is set for that specific board.
-
-Note for testing S3 resume with Windows, correct graphics driver must be
-installed for your platform, otherwise you won't find "Sleep" option in
-the "Power" submenu from the Windows start menu.
-
-EFI Support
------------
-U-Boot supports booting as a 32-bit or 64-bit EFI payload, e.g. with UEFI.
-This is enabled with CONFIG_EFI_STUB to boot from both 32-bit and 64-bit
-UEFI BIOS. U-Boot can also run as an EFI application, with CONFIG_EFI_APP.
-The CONFIG_EFI_LOADER option, where U-Boot provides an EFI environment to
-the kernel (i.e. replaces UEFI completely but provides the same EFI run-time
-services) is supported too. For example, we can even use 'bootefi' command
-to load a 'u-boot-payload.efi', see below test logs on QEMU.
-
- => load ide 0 3000000 u-boot-payload.efi
- 489787 bytes read in 138 ms (3.4 MiB/s)
- => bootefi 3000000
- Scanning disk ide.blk#0...
- Found 2 disks
- WARNING: booting without device tree
- ## Starting EFI application at 03000000 ...
- U-Boot EFI Payload
-
-
- U-Boot 2018.07-rc2 (Jun 23 2018 - 17:12:58 +0800)
-
- CPU: x86_64, vendor AMD, device 663h
- DRAM: 2 GiB
- MMC:
- Video: 1024x768x32
- Model: EFI x86 Payload
- Net: e1000: 52:54:00:12:34:56
-
- Warning: e1000#0 using MAC address from ROM
- eth0: e1000#0
- No controllers found
- Hit any key to stop autoboot: 0
-
-See README.u-boot_on_efi and README.uefi for details of EFI support in U-Boot.
-
-TODO List
----------
-- Audio
-- Chrome OS verified boot
-
-References
-----------
-[1] http://www.coreboot.org
-[2] http://www.qemu.org
-[3] http://www.coreboot.org/~stepan/pci8086,0166.rom
-[4] http://www.intel.com/content/www/us/en/embedded/design-tools/evaluation-platforms/atom-e660-eg20t-development-kit.html
-[5] http://www.intel.com/fsp
-[6] http://www.intel.com/content/www/us/en/secure/intelligent-systems/privileged/e6xx-35-b1-cmc22211.html
-[7] http://www.ami.com/products/bios-uefi-tools-and-utilities/bios-uefi-utilities/
-[8] http://en.wikipedia.org/wiki/Microcode
-[9] http://simplefirmware.org
-[10] http://www.intel.com/design/archives/processors/pro/docs/242016.htm
-[11] https://en.wikipedia.org/wiki/GUID_Partition_Table
-[12] http://events.linuxfoundation.org/sites/events/files/slides/chromeos_and_diy_vboot_0.pdf
-[13] http://events.linuxfoundation.org/sites/events/files/slides/elce-2014.pdf
-[14] http://www.seabios.org/SeaBIOS
-[15] doc/device-tree-bindings/misc/intel,irq-router.txt
-[16] http://www.acpi.info
-[17] https://www.acpica.org/downloads
diff --git a/doc/README.zynq b/doc/README.zynq
deleted file mode 100644
index da977b2..0000000
--- a/doc/README.zynq
+++ /dev/null
@@ -1,83 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+
-#
-# Xilinx ZYNQ U-Boot
-#
-# (C) Copyright 2013 Xilinx, Inc.
-
-1. About this
-
-This document describes the information about Xilinx Zynq U-Boot -
-like supported boards, ML status and TODO list.
-
-2. Zynq boards
-
-Xilinx Zynq-7000 All Programmable SoCs enable extensive system level
-differentiation, integration, and flexibility through hardware, software,
-and I/O programmability.
-
-* zc702 (single qspi, gem0, mmc) [1]
-* zc706 (dual parallel qspi, gem0, mmc) [2]
-* zed (single qspi, gem0, mmc) [3]
-* microzed (single qspi, gem0, mmc) [4]
-* zc770
- - zc770-xm010 (single qspi, gem0, mmc)
- - zc770-xm011 (8 or 16 bit nand)
- - zc770-xm012 (nor)
- - zc770-xm013 (dual parallel qspi, gem1)
-
-3. Building
-
- ex. configure and build for zc702 board
- $ make zynq_zc702_config
- $ make
-
-4. Bootmode
-
-Zynq has a facility to read the bootmode from the slcr bootmode register
-once user is setting through jumpers on the board - see page no:1546 on [5]
-
-All possible bootmode values are defined in Table 6-2:Boot_Mode MIO Pins
-on [5].
-
-board_late_init() will read the bootmode values using slcr bootmode register
-at runtime and assign the modeboot variable to specific bootmode string which
-is intern used in autoboot.
-
-SLCR bootmode register Bit[3:0] values
-#define ZYNQ_BM_NOR 0x02
-#define ZYNQ_BM_SD 0x05
-#define ZYNQ_BM_JTAG 0x0
-
-"modeboot" variable can assign any of "norboot", "sdboot" or "jtagboot"
-bootmode strings at runtime.
-
-5. Mainline status
-
-- Added basic board configurations support.
-- Added zynq u-boot bsp code - arch/arm/cpu/armv7/zynq
-- Added zynq boards named - zc70x, zed, microzed, zc770_xm010/xm011/xm012/xm013
-- Added zynq drivers:
- serial - drivers/serial/serial_zynq.c
- net - drivers/net/zynq_gem.c
- mmc - drivers/mmc/zynq_sdhci.c
- spi - drivers/spi/zynq_spi.c
- qspi - drivers/spi/zynq_qspi.c
- i2c - drivers/i2c/zynq_i2c.c
- nand - drivers/mtd/nand/raw/zynq_nand.c
-- Done proper cleanups on board configurations
-- Added basic FDT support for zynq boards
-- d-cache support for zynq_gem.c
-
-6. TODO
-
-- Add FDT support on individual drivers
-
-[1] http://www.xilinx.com/products/boards-and-kits/EK-Z7-ZC702-G.htm
-[2] http://www.xilinx.com/products/boards-and-kits/EK-Z7-ZC706-G.htm
-[3] http://zedboard.org/product/zedboard
-[4] http://zedboard.org/product/microzed
-[5] http://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf
-
---
-Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
-Sun Dec 15 14:52:41 IST 2013
diff --git a/doc/android/ab.txt b/doc/android/ab.txt
new file mode 100644
index 0000000..9f37ed5
--- /dev/null
+++ b/doc/android/ab.txt
@@ -0,0 +1,67 @@
+Android A/B updates
+===================
+
+Overview
+--------
+
+A/B system updates ensures modern approach for system update. This feature
+allows one to use two sets (or more) of partitions referred to as slots
+(normally slot A and slot B). The system runs from the current slot while the
+partitions in the unused slot can be updated [1].
+
+A/B enablement
+--------------
+
+The A/B updates support can be activated by specifying next options in
+your board configuration file:
+
+ CONFIG_ANDROID_AB=y
+ CONFIG_CMD_AB_SELECT=y
+
+The disk space on target device must be partitioned in a way so that each
+partition which needs to be updated has two or more instances. The name of
+each instance must be formed by adding suffixes: _a, _b, _c, etc.
+For example: boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
+
+As a result you can use 'ab_select' command to ensure A/B boot process in your
+boot script. This command analyzes and processes A/B metadata stored on a
+special partition (e.g. "misc") and determines which slot should be used for
+booting up.
+
+Command usage
+-------------
+
+ ab_select <slot_var_name> <interface> <dev[:part_number|#part_name]>
+
+for example:
+
+ => ab_select slot_name mmc 1:4
+
+or
+
+ => ab_select slot_name mmc 1#misc
+
+Result:
+
+ => printenv slot_name
+ slot_name=a
+
+Based on this slot information, the current boot partition should be defined,
+and next kernel command line parameters should be generated:
+
+ - androidboot.slot_suffix=
+ - root=
+
+For example:
+
+ androidboot.slot_suffix=_a root=/dev/mmcblk1p12
+
+A/B metadata is organized according to AOSP reference [2]. On the first system
+start with A/B enabled, when 'misc' partition doesn't contain required data,
+the default A/B metadata will be created and written to 'misc' partition.
+
+References
+----------
+
+[1] https://source.android.com/devices/tech/ota/ab
+[2] bootable/recovery/bootloader_message/include/bootloader_message/bootloader_message.h
diff --git a/doc/README.android-fastboot-protocol b/doc/android/fastboot-protocol.txt
similarity index 100%
rename from doc/README.android-fastboot-protocol
rename to doc/android/fastboot-protocol.txt
diff --git a/doc/android/fastboot.txt b/doc/android/fastboot.txt
index 431191c..ea0d1da 100644
--- a/doc/android/fastboot.txt
+++ b/doc/android/fastboot.txt
@@ -5,8 +5,8 @@
Overview
========
-The protocol that is used over USB and UDP is described in the
-``README.android-fastboot-protocol`` file in the same directory.
+The protocol that is used over USB and UDP is described in
+``doc/android/fastboot-protocol.txt``.
The current implementation supports the following standard commands:
diff --git a/doc/api/efi.rst b/doc/api/efi.rst
new file mode 100644
index 0000000..39e2dba
--- /dev/null
+++ b/doc/api/efi.rst
@@ -0,0 +1,105 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+UEFI subsystem
+==============
+
+Lauching UEFI images
+--------------------
+
+Bootefi command
+~~~~~~~~~~~~~~~
+
+The bootefi command is used to start UEFI applications or to install UEFI
+drivers. It takes two parameters
+
+ bootefi <image address> [fdt address]
+
+* image address - the memory address of the UEFI binary
+* fdt address - the memory address of the flattened device tree
+
+The environment variable 'bootargs' is passed as load options in the UEFI system
+table. The Linux kernel EFI stub uses the load options as command line
+arguments.
+
+.. kernel-doc:: cmd/bootefi.c
+ :internal:
+
+Boot manager
+~~~~~~~~~~~~
+
+The UEFI specification foresees to define boot entries and boot sequence via UEFI
+variables. Booting according to these variables is possible via
+
+ bootefi bootmgr [fdt address]
+
+* fdt address - the memory address of the flattened device tree
+
+The relevant variables are:
+
+* Boot0000-BootFFFF define boot entries
+* BootNext specifies next boot option to be booted
+* BootOrder specifies in which sequence the boot options shall be tried if
+ BootNext is not defined or booting via BootNext fails
+
+.. kernel-doc:: lib/efi_loader/efi_bootmgr.c
+ :internal:
+
+Efidebug command
+~~~~~~~~~~~~~~~~
+
+The efidebug command is used to set and display boot options as well as to
+display information about internal data of the UEFI subsystem (devices,
+drivers, handles, loaded images, and the memory map).
+
+.. kernel-doc:: cmd/efidebug.c
+ :internal:
+
+Initialization of the UEFI sub-system
+-------------------------------------
+
+.. kernel-doc:: lib/efi_loader/efi_setup.c
+ :internal:
+
+Boot services
+-------------
+
+.. kernel-doc:: lib/efi_loader/efi_boottime.c
+ :internal:
+
+Image relocation
+~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: lib/efi_loader/efi_image_loader.c
+ :internal:
+
+Memory services
+~~~~~~~~~~~~~~~
+
+.. kernel-doc:: lib/efi_loader/efi_memory.c
+ :internal:
+
+Runtime services
+----------------
+
+.. kernel-doc:: lib/efi_loader/efi_runtime.c
+ :internal:
+
+Variable services
+~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: lib/efi_loader/efi_variable.c
+ :internal:
+
+UEFI drivers
+------------
+
+UEFI driver uclass
+~~~~~~~~~~~~~~~~~~
+.. kernel-doc:: lib/efi_driver/efi_uclass.c
+ :internal:
+
+Block device driver
+~~~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: lib/efi_driver/efi_block_device.c
+ :internal:
diff --git a/doc/api/index.rst b/doc/api/index.rst
new file mode 100644
index 0000000..d484c06
--- /dev/null
+++ b/doc/api/index.rst
@@ -0,0 +1,11 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+U-Boot API documentation
+========================
+
+.. toctree::
+ :maxdepth: 2
+
+ efi
+ linker_lists
+ serial
diff --git a/doc/linker_lists.rst b/doc/api/linker_lists.rst
similarity index 100%
rename from doc/linker_lists.rst
rename to doc/api/linker_lists.rst
diff --git a/doc/serial.rst b/doc/api/serial.rst
similarity index 100%
rename from doc/serial.rst
rename to doc/api/serial.rst
diff --git a/doc/README.ARC b/doc/arch/arc.rst
similarity index 95%
rename from doc/README.ARC
rename to doc/arch/arc.rst
index 5f414fb..f8e04a3 100644
--- a/doc/README.ARC
+++ b/doc/arch/arc.rst
@@ -1,3 +1,8 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+ARC
+===
+
Synopsys' DesignWare(r) ARC(r) Processors are a family of 32-bit CPUs
that SoC designers can optimize for a wide range of uses, from deeply embedded
to high-performance host applications.
diff --git a/doc/README.arm64 b/doc/arch/arm64.rst
similarity index 82%
rename from doc/README.arm64
rename to doc/arch/arm64.rst
index b0bba0f..80498f6 100644
--- a/doc/README.arm64
+++ b/doc/arch/arm64.rst
@@ -1,14 +1,17 @@
-U-Boot for arm64
+.. SPDX-License-Identifier: GPL-2.0+
+
+ARM64
+=====
Summary
-=======
+-------
The initial arm64 U-Boot port was developed before hardware was available,
so the first supported platforms were the Foundation and Fast Model for ARMv8.
These days U-Boot runs on a variety of 64-bit capable ARM hardware, from
embedded development boards to servers.
Notes
-=====
+-----
1. U-Boot can run at any exception level it is entered in, it is
recommened to enter it in EL3 if U-Boot takes some responsibilities of a
@@ -46,11 +49,11 @@
Contributors
-============
- Tom Rini <trini@ti.com>
- Scott Wood <scottwood@freescale.com>
- York Sun <yorksun@freescale.com>
- Simon Glass <sjg@chromium.org>
- Sharma Bhupesh <bhupesh.sharma@freescale.com>
- Rob Herring <robherring2@gmail.com>
- Sergey Temerkhanov <s.temerkhanov@gmail.com>
+------------
+ * Tom Rini <trini@ti.com>
+ * Scott Wood <scottwood@freescale.com>
+ * York Sun <yorksun@freescale.com>
+ * Simon Glass <sjg@chromium.org>
+ * Sharma Bhupesh <bhupesh.sharma@freescale.com>
+ * Rob Herring <robherring2@gmail.com>
+ * Sergey Temerkhanov <s.temerkhanov@gmail.com>
diff --git a/doc/arch/index.rst b/doc/arch/index.rst
new file mode 100644
index 0000000..369d8ee
--- /dev/null
+++ b/doc/arch/index.rst
@@ -0,0 +1,18 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Architecture-specific doc
+=========================
+
+.. toctree::
+ :maxdepth: 2
+
+ arc
+ arm64
+ m68k
+ mips
+ nds32
+ nios2
+ sandbox
+ sh
+ x86
+ xtensa
diff --git a/doc/arch/m68k.rst b/doc/arch/m68k.rst
new file mode 100644
index 0000000..34b2593
--- /dev/null
+++ b/doc/arch/m68k.rst
@@ -0,0 +1,170 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+M68K / ColdFire
+===============
+
+History
+-------
+* November 02, 2017 Angelo Dureghello <angelo@sysam.it>
+* August 08, 2005 Jens Scharsig <esw@bus-elektronik.de>
+ MCF5282 implementation without preloader
+* January 12, 2004 <josef.baumgartner@telex.de>
+
+This file contains status information for the port of U-Boot to the
+Motorola ColdFire series of CPUs.
+
+Overview
+--------
+
+The ColdFire instruction set is "assembly source" compatible but an evolution
+of the original 68000 instruction set. Some not much used instructions has
+been removed. The instructions are only 16, 32, or 48 bits long, a
+simplification compared to the 68000 series.
+
+Bernhard Kuhn ported U-Boot 0.4.0 to the Motorola ColdFire architecture.
+The patches of Bernhard support the MCF5272 and MCF5282. A great disadvantage
+of these patches was that they needed a pre-bootloader to start U-Boot.
+Because of this, a new port was created which no longer needs a first stage
+booter.
+
+Thanks mainly to Freescale but also to several other contributors, U-Boot now
+supports nearly the entire range of ColdFire processors and their related
+development boards.
+
+
+Supported CPU families
+----------------------
+
+Please "make menuconfig" with ARCH=m68k, or check arch/m68k/cpu to see the
+currently supported processor and families.
+
+
+Supported boards
+----------------
+
+U-Boot supports actually more than 40 ColdFire based boards.
+Board configuration can be done trough include/configs/<boardname>.h but the
+current recommended method is to use the new and more friendly approach as
+the "make menuconfig" way, very similar to the Linux way.
+
+To know details as memory map, build targets, default setup, etc, of a
+specific board please check:
+
+* include/configs/<boardname>.h
+
+and/or
+
+* configs/<boardname>_defconfig
+
+It is possible to build all ColdFire boards in a single command-line command,
+from u-boot root directory, as::
+
+ ./tools/buildman/buildman m68k
+
+Build U-Boot for a specific board
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A bash script similar to the one below may be used:
+
+.. code-block:: shell
+
+ #!/bin/bash
+
+ export CROSS_COMPILE=/opt/toolchains/m68k/gcc-4.9.0-nolibc/bin/m68k-linux-
+
+ board=M5475DFE
+
+ make distclean
+ make ARCH=m68k ${board}_defconfig
+ make ARCH=m68k KBUILD_VERBOSE=1
+
+
+Adopted toolchains
+------------------
+
+Please check:
+https://www.denx.de/wiki/U-Boot/ColdFireNotes
+
+
+ColdFire specific configuration options/settings
+------------------------------------------------
+
+Configuration to use a pre-loader
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If U-Boot should be loaded to RAM and started by a pre-loader
+CONFIG_MONITOR_IS_IN_RAM must be defined. If it is defined the
+initial vector table and basic processor initialization will not
+be compiled in. The start address of U-Boot must be adjusted in
+the boards config header file (CONFIG_SYS_MONITOR_BASE) and Makefile
+(CONFIG_SYS_TEXT_BASE) to the load address.
+
+ColdFire CPU specific options/settings
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To specify a CPU model, some defines shoudl be used, i.e.:
+
+CONFIG_MCF52x2:
+ defined for all MCF52x2 CPUs
+CONFIG_M5272:
+ defined for all Motorola MCF5272 CPUs
+
+Other options, generally set inside include/configs/<boardname>.h, they may
+apply to one or more cpu for the ColdFire family:
+
+CONFIG_SYS_MBAR:
+ defines the base address of the MCF5272 configuration registers
+CONFIG_SYS_ENET_BD_BASE:
+ defines the base address of the FEC buffer descriptors
+CONFIG_SYS_SCR:
+ defines the contents of the System Configuration Register
+CONFIG_SYS_SPR:
+ defines the contents of the System Protection Register
+CONFIG_SYS_MFD:
+ defines the PLL Multiplication Factor Divider
+ (see table 9-4 of MCF user manual)
+CONFIG_SYS_RFD:
+ defines the PLL Reduce Frequency Devider
+ (see table 9-4 of MCF user manual)
+CONFIG_SYS_CSx_BASE:
+ defines the base address of chip select x
+CONFIG_SYS_CSx_SIZE:
+ defines the memory size (address range) of chip select x
+CONFIG_SYS_CSx_WIDTH:
+ defines the bus with of chip select x
+CONFIG_SYS_CSx_MASK:
+ defines the mask for the related chip select x
+CONFIG_SYS_CSx_RO:
+ if set to 0 chip select x is read/write else chip select is read only
+CONFIG_SYS_CSx_WS:
+ defines the number of wait states of chip select x
+CONFIG_SYS_CACHE_ICACR:
+ cache-related registers config
+CONFIG_SYS_CACHE_DCACR:
+ cache-related registers config
+CONFIG_SYS_CACHE_ACRX:
+ cache-related registers config
+CONFIG_SYS_SDRAM_BASE:
+ SDRAM config for SDRAM controller-specific registers
+CONFIG_SYS_SDRAM_SIZE:
+ SDRAM config for SDRAM controller-specific registers
+CONFIG_SYS_SDRAM_BASEX:
+ SDRAM config for SDRAM controller-specific registers
+CONFIG_SYS_SDRAM_CFG1:
+ SDRAM config for SDRAM controller-specific registers
+CONFIG_SYS_SDRAM_CFG2:
+ SDRAM config for SDRAM controller-specific registers
+CONFIG_SYS_SDRAM_CTRL:
+ SDRAM config for SDRAM controller-specific registers
+CONFIG_SYS_SDRAM_MODE:
+ SDRAM config for SDRAM controller-specific registers
+CONFIG_SYS_SDRAM_EMOD:
+ SDRAM config for SDRAM controller-specific registers, please
+ see arch/m68k/cpu/<specific_cpu>/start.S files to see how
+ these options are used.
+CONFIG_MCFUART:
+ defines enabling of ColdFire UART driver
+CONFIG_SYS_UART_PORT:
+ defines the UART port to be used (only a single UART can be actually enabled)
+CONFIG_SYS_SBFHDR_SIZE:
+ size of the prepended SBF header, if any
diff --git a/doc/README.mips b/doc/arch/mips.rst
similarity index 73%
rename from doc/README.mips
rename to doc/arch/mips.rst
index b28f628..b816608 100644
--- a/doc/README.mips
+++ b/doc/arch/mips.rst
@@ -1,17 +1,16 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+MIPS
+====
Notes for the MIPS architecture port of U-Boot
Toolchains
----------
- http://www.denx.de/wiki/DULG/ELDK
- ELDK < DULG < DENX
-
- http://www.emdebian.org/crosstools.html
- Embedded Debian -- Cross-development toolchains
-
- http://buildroot.uclibc.org/
- Buildroot
+ * `ELDK < DULG < DENX <http://www.denx.de/wiki/DULG/ELDK>`_
+ * `Embedded Debian -- Cross-development toolchains <http://www.emdebian.org/crosstools.html>`_
+ * `Buildroot <http://buildroot.uclibc.org/>`_
Known Issues
------------
@@ -24,9 +23,9 @@
re-initializes the cache. The more common uImage 'bootm' command does
not suffer this problem.
- [workaround] To avoid this cache incoherency,
- 1) insert flush_cache(all) before calling dcache_disable(), or
- 2) fix dcache_disable() to do both flushing and disabling cache.
+ [workaround] To avoid this cache incoherency:
+ - insert flush_cache(all) before calling dcache_disable(), or
+ - fix dcache_disable() to do both flushing and disabling cache.
* Note that Linux users need to kill dcache_disable() in do_bootelf_exec()
or override do_bootelf_exec() not to disable I-/D-caches, because most
@@ -36,19 +35,12 @@
-----
* Probe CPU types, I-/D-cache and TLB size etc. automatically
-
* Secondary cache support missing
-
* Initialize TLB entries redardless of their use
-
* R2000/R3000 class parts are not supported
-
* Limited testing across different MIPS variants
-
* Due to cache initialization issues, the DRAM on board must be
initialized in board specific assembler language before the cache init
code is run -- that is, initialize the DRAM in lowlevel_init().
-
* centralize/share more CPU code of MIPS32, MIPS64 and XBurst
-
* support Qemu Malta
diff --git a/doc/arch/nds32.rst b/doc/arch/nds32.rst
new file mode 100644
index 0000000..502397c
--- /dev/null
+++ b/doc/arch/nds32.rst
@@ -0,0 +1,101 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+NDS32
+=====
+
+NDS32 is a new high-performance 32-bit RISC microprocessor core.
+
+http://www.andestech.com/
+
+AndeStar ISA
+------------
+AndeStar is a patent-pending 16-bit/32-bit mixed-length instruction set to
+achieve optimal system performance, code density, and power efficiency.
+
+It contains the following features:
+ - Intermixable 32-bit and 16-bit instruction sets without the need for
+ mode switch.
+ - 16-bit instructions as a frequently used subset of 32-bit instructions.
+ - RISC-style register-based instruction set.
+ - 32 32-bit General Purpose Registers (GPR).
+ - Upto 1024 User Special Registers (USR) for existing and extension
+ instructions.
+ - Rich load/store instructions for...
+ - Single memory access with base address update.
+ - Multiple aligned and unaligned memory accesses for memory copy and stack
+ operations.
+ - Data prefetch to improve data cache performance.
+ - Non-bus locking synchronization instructions.
+ - PC relative jump and PC read instructions for efficient position independent
+ code.
+ - Multiply-add and multiple-sub with 64-bit accumulator.
+ - Instruction for efficient power management.
+ - Bi-endian support.
+ - Three instruction extension space for application acceleration:
+ - Performance extension.
+ - Andes future extensions (for floating-point, multimedia, etc.)
+ - Customer extensions.
+
+AndesCore CPU
+-------------
+Andes Technology has 4 families of CPU cores: N12, N10, N9, N8.
+
+For details about N12 CPU family, please check below N1213 features.
+N1213 is a configurable hard/soft core of NDS32's N12 CPU family.
+
+N1213 Features
+^^^^^^^^^^^^^^
+
+CPU Core
+ - 16-/32-bit mixable instruction format.
+ - 32 general-purpose 32-bit registers.
+ - 8-stage pipeline.
+ - Dynamic branch prediction.
+ - 32/64/128/256 BTB.
+ - Return address stack (RAS).
+ - Vector interrupts for internal/external.
+ interrupt controller with 6 hardware interrupt signals.
+ - 3 HW-level nested interruptions.
+ - User and super-user mode support.
+ - Memory-mapped I/O.
+ - Address space up to 4GB.
+
+Memory Management Unit
+ - TLB
+ - 4/8-entry fully associative iTLB/dTLB.
+ - 32/64/128-entry 4-way set-associati.ve main TLB.
+ - TLB locking support
+ - Optional hardware page table walker.
+ - Two groups of page size support.
+ - 4KB & 1MB.
+ - 8KB & 1MB.
+
+Memory Subsystem
+ - I & D cache.
+ - Virtually indexed and physically tagged.
+ - Cache size: 8KB/16KB/32KB/64KB.
+ - Cache line size: 16B/32B.
+ - Set associativity: 2-way, 4-way or direct-mapped.
+ - Cache locking support.
+ - I & D local memory (LM).
+ - Size: 4KB to 1MB.
+ - Bank numbers: 1 or 2.
+ - Optional 1D/2D DMA engine.
+ - Internal or external to CPU core.
+
+Bus Interface
+ - Synchronous/Asynchronous AHB bus: 0, 1 or 2 ports.
+ - Synchronous High speed memory port.
+ (HSMP): 0, 1 or 2 ports.
+
+Debug
+ - JTAG debug interface.
+ - Embedded debug module (EDM).
+ - Optional embedded program tracer interface.
+
+Miscellaneous
+ - Programmable data endian control.
+ - Performance monitoring mechanism.
+
+The NDS32 ports of u-boot, the Linux kernel, the GNU toolchain and other
+associated software are actively supported by Andes Technology Corporation.
diff --git a/doc/arch/nios2.rst b/doc/arch/nios2.rst
new file mode 100644
index 0000000..35defb0
--- /dev/null
+++ b/doc/arch/nios2.rst
@@ -0,0 +1,111 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Nios II
+=======
+
+Nios II is a 32-bit embedded-processor architecture designed
+specifically for the Altera family of FPGAs.
+
+Please refer to the link for more information on Nios II:
+https://www.altera.com/products/processors/overview.html
+
+Please refer to the link for Linux port and toolchains:
+http://rocketboards.org/foswiki/view/Documentation/NiosIILinuxUserManual
+
+The Nios II port of u-boot is controlled by device tree. Please check
+out doc/README.fdt-control.
+
+To add a new board/configuration (eg, mysystem) to u-boot, you will need
+three files.
+
+1. The device tree source which describes the hardware, dts file:
+ arch/nios2/dts/mysystem.dts
+
+2. Default configuration of Kconfig, defconfig file:
+ configs/mysystem_defconfig
+
+3. The legacy board header file:
+ include/configs/mysystem.h
+
+The device tree source must be generated from your qsys/sopc design
+using the sopc2dts tool. Then modified to fit your configuration.
+
+Please find the sopc2dts download and usage at the wiki:
+http://www.alterawiki.com/wiki/Sopc2dts
+
+.. code-block:: none
+
+ $ java -jar sopc2dts.jar --force-altr -i mysystem.sopcinfo -o mysystem.dts
+
+You will need to add additional properties to the dts. Please find an
+example at, arch/nios2/dts/10m50_devboard.dts.
+
+1. Add "stdout-path=..." property with your serial path to the chosen
+ node, like this::
+
+ chosen {
+ stdout-path = &uart_0;
+ };
+
+2. If you use SPI/EPCS or I2C, you will need to add aliases to number
+ the sequence of these devices, like this::
+
+ aliases {
+ spi0 = &epcs_controller;
+ };
+
+Next, you will need a default config file. You may start with
+10m50_defconfig, modify the options and save it.
+
+.. code-block:: none
+
+ $ make 10m50_defconfig
+ $ make menuconfig
+ $ make savedefconfig
+ $ cp defconfig configs/mysystem_defconfig
+
+You will need to change the names of board header file and device tree,
+and select the drivers with menuconfig.
+
+.. code-block:: none
+
+ Nios II architecture --->
+ (mysystem) Board header file
+ Device Tree Control --->
+ (mysystem) Default Device Tree for DT control
+
+There is a selection of "Provider of DTB for DT control" in the Device
+Tree Control menu.
+
+ * Separate DTB for DT control, will cat the dtb to end of u-boot
+ binary, output u-boot-dtb.bin. This should be used for production.
+ If you use boot copier, like EPCS boot copier, make sure the copier
+ copies all the u-boot-dtb.bin, not just u-boot.bin.
+
+ * Embedded DTB for DT control, will include the dtb inside the u-boot
+ binary. This is handy for development, eg, using gdb or nios2-download.
+
+The last thing, legacy board header file describes those config options
+not covered in Kconfig yet. You may copy it from 10m50_devboard.h::
+
+ $ cp include/configs/10m50_devboard.h include/configs/mysystem.h
+
+Please change the SDRAM base and size to match your board. The base
+should be cached virtual address, for Nios II with MMU it is 0xCxxx_xxxx
+to 0xDxxx_xxxx.
+
+.. code-block:: c
+
+ #define CONFIG_SYS_SDRAM_BASE 0xc8000000
+ #define CONFIG_SYS_SDRAM_SIZE 0x08000000
+
+You will need to change the environment variables location and setting,
+too. You may change other configs to fit your board.
+
+After all these changes, you may build and test::
+
+ $ export CROSS_COMPILE=nios2-elf- (or nios2-linux-gnu-)
+ $ make mysystem_defconfig
+ $ make
+
+Enjoy!
diff --git a/board/sandbox/README.sandbox b/doc/arch/sandbox.rst
similarity index 75%
rename from board/sandbox/README.sandbox
rename to doc/arch/sandbox.rst
index c10dd44..5c0caeb 100644
--- a/board/sandbox/README.sandbox
+++ b/doc/arch/sandbox.rst
@@ -1,10 +1,12 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 2014 The Chromium OS Authors.
- */
+.. SPDX-License-Identifier: GPL-2.0+ */
+.. Copyright (c) 2014 The Chromium OS Authors.
+.. sectionauthor:: Simon Glass <sjg@chromium.org>
+
+Sandbox
+=======
Native Execution of U-Boot
-==========================
+--------------------------
The 'sandbox' architecture is designed to allow U-Boot to run under Linux on
almost any hardware. To achieve this it builds U-Boot (so far as possible)
@@ -35,33 +37,31 @@
Basic Operation
---------------
-To run sandbox U-Boot use something like:
+To run sandbox U-Boot use something like::
make sandbox_defconfig all
./u-boot
-Note:
- If you get errors about 'sdl-config: Command not found' you may need to
- install libsdl1.2-dev or similar to get SDL support. Alternatively you can
- build sandbox without SDL (i.e. no display/keyboard support) by removing
- the CONFIG_SANDBOX_SDL line in include/configs/sandbox.h or using:
+Note: If you get errors about 'sdl-config: Command not found' you may need to
+install libsdl1.2-dev or similar to get SDL support. Alternatively you can
+build sandbox without SDL (i.e. no display/keyboard support) by removing
+the CONFIG_SANDBOX_SDL line in include/configs/sandbox.h or using::
- make sandbox_defconfig all NO_SDL=1
- ./u-boot
+ make sandbox_defconfig all NO_SDL=1
+ ./u-boot
U-Boot will start on your computer, showing a sandbox emulation of the serial
-console:
-
+console::
-U-Boot 2014.04 (Mar 20 2014 - 19:06:00)
+ U-Boot 2014.04 (Mar 20 2014 - 19:06:00)
-DRAM: 128 MiB
-Using default environment
+ DRAM: 128 MiB
+ Using default environment
-In: serial
-Out: lcd
-Err: lcd
-=>
+ In: serial
+ Out: lcd
+ Err: lcd
+ =>
You can issue commands as your would normally. If the command you want is
not supported you can add it to include/configs/sandbox.h.
@@ -73,7 +73,7 @@
---------------------
Assuming that CONFIG_SANDBOX_SDL is defined when building, you can run the
-sandbox with LCD and keyboard emulation, using something like:
+sandbox with LCD and keyboard emulation, using something like::
./u-boot -d u-boot.dtb -l
@@ -198,18 +198,23 @@
There are unfortunately quite a few variants at present:
-sandbox - should be used for most tests
-sandbox64 - special build that forces a 64-bit host
-sandbox_flattree - builds with dev_read_...() functions defined as inline.
- We need this build so that we can test those inline functions, and we
- cannot build with both the inline functions and the non-inline functions
- since they are named the same.
-sandbox_noblk - builds without CONFIG_BLK, which means the legacy block
- drivers are used. We cannot use both the legacy and driver-model block
- drivers since they implement the same functions
-sandbox_spl - builds sandbox with SPL support, so you can run spl/u-boot-spl
- and it will start up and then load ./u-boot. It is also possible to
- run ./u-boot directly.
+sandbox:
+ should be used for most tests
+sandbox64:
+ special build that forces a 64-bit host
+sandbox_flattree:
+ builds with dev_read\_...() functions defined as inline.
+ We need this build so that we can test those inline functions, and we
+ cannot build with both the inline functions and the non-inline functions
+ since they are named the same.
+sandbox_noblk:
+ builds without CONFIG_BLK, which means the legacy block
+ drivers are used. We cannot use both the legacy and driver-model block
+ drivers since they implement the same functions
+sandbox_spl:
+ builds sandbox with SPL support, so you can run spl/u-boot-spl
+ and it will start up and then load ./u-boot. It is also possible to
+ run ./u-boot directly.
Of these sandbox_noblk can be removed once CONFIG_BLK is used everwhere, and
sandbox_spl can probably be removed since it is a superset of sandbox.
@@ -234,42 +239,44 @@
for its configured (on Linux) MAC address.
The RAW sockets Ethernet API requires elevated privileges in Linux. You can
-either run as root, or you can add the capability needed like so:
+either run as root, or you can add the capability needed like so::
-sudo /sbin/setcap "CAP_NET_RAW+ep" /path/to/u-boot
+ sudo /sbin/setcap "CAP_NET_RAW+ep" /path/to/u-boot
The default device tree for sandbox includes an entry for eth0 on the sandbox
host machine whose alias is "eth1". The following are a few examples of network
operations being tested on the eth0 interface.
-sudo /path/to/u-boot -D
+.. code-block:: none
-DHCP
-....
+ sudo /path/to/u-boot -D
-setenv autoload no
-setenv ethrotate no
-setenv ethact eth1
-dhcp
+ DHCP
+ ....
-PING
-....
+ setenv autoload no
+ setenv ethrotate no
+ setenv ethact eth1
+ dhcp
-setenv autoload no
-setenv ethrotate no
-setenv ethact eth1
-dhcp
-ping $gatewayip
+ PING
+ ....
-TFTP
-....
+ setenv autoload no
+ setenv ethrotate no
+ setenv ethact eth1
+ dhcp
+ ping $gatewayip
-setenv autoload no
-setenv ethrotate no
-setenv ethact eth1
-dhcp
-setenv serverip WWW.XXX.YYY.ZZZ
-tftpboot u-boot.bin
+ TFTP
+ ....
+
+ setenv autoload no
+ setenv ethrotate no
+ setenv ethact eth1
+ dhcp
+ setenv serverip WWW.XXX.YYY.ZZZ
+ tftpboot u-boot.bin
The bridge also supports (to a lesser extent) the localhost interface, 'lo'.
@@ -287,20 +294,22 @@
host machine whose alias is "eth5". The following is an example of a network
operation being tested on the lo interface.
-TFTP
-....
+.. code-block:: none
-setenv ethrotate no
-setenv ethact eth5
-tftpboot u-boot.bin
+ TFTP
+ ....
+ setenv ethrotate no
+ setenv ethact eth5
+ tftpboot u-boot.bin
+
SPI Emulation
-------------
Sandbox supports SPI and SPI flash emulation.
-This is controlled by the spi_sf argument, the format of which is:
+This is controlled by the spi_sf argument, the format of which is::
bus:cs:device:file
@@ -309,24 +318,23 @@
device - SPI device emulation name
file - File on disk containing the data
-For example:
+For example::
- dd if=/dev/zero of=spi.bin bs=1M count=4
- ./u-boot --spi_sf 0:0:M25P16:spi.bin
+ dd if=/dev/zero of=spi.bin bs=1M count=4
+ ./u-boot --spi_sf 0:0:M25P16:spi.bin
-With this setup you can issue SPI flash commands as normal:
+With this setup you can issue SPI flash commands as normal::
-=>sf probe
-SF: Detected M25P16 with page size 64 KiB, total 2 MiB
-=>sf read 0 0 10000
-SF: 65536 bytes @ 0x0 Read: OK
-=>
+ =>sf probe
+ SF: Detected M25P16 with page size 64 KiB, total 2 MiB
+ =>sf read 0 0 10000
+ SF: 65536 bytes @ 0x0 Read: OK
Since this is a full SPI emulation (rather than just flash), you can
-also use low-level SPI commands:
+also use low-level SPI commands::
-=>sspi 0:0 32 9f
-FF202015
+ =>sspi 0:0 32 9f
+ FF202015
This is issuing a READ_ID command and getting back 20 (ST Micro) part
0x2015 (the M25P16).
@@ -338,15 +346,14 @@
Configuration settings for the curious are:
-CONFIG_SANDBOX_SPI_MAX_BUS
- The maximum number of SPI buses supported by the driver (default 1).
+CONFIG_SANDBOX_SPI_MAX_BUS:
+ The maximum number of SPI buses supported by the driver (default 1).
-CONFIG_SANDBOX_SPI_MAX_CS
- The maximum number of chip selects supported by the driver
- (default 10).
+CONFIG_SANDBOX_SPI_MAX_CS:
+ The maximum number of chip selects supported by the driver (default 10).
-CONFIG_SPI_IDLE_VAL
- The idle value on the SPI bus
+CONFIG_SPI_IDLE_VAL:
+ The idle value on the SPI bus
Block Device Emulation
@@ -354,20 +361,20 @@
U-Boot can use raw disk images for block device emulation. To e.g. list
the contents of the root directory on the second partion of the image
-"disk.raw", you can use the following commands:
+"disk.raw", you can use the following commands::
-=>host bind 0 ./disk.raw
-=>ls host 0:2
+ =>host bind 0 ./disk.raw
+ =>ls host 0:2
-A disk image can be created using the following commands:
+A disk image can be created using the following commands::
-$> truncate -s 1200M ./disk.raw
-$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk ./disk.raw
-$> lodev=`sudo losetup -P -f --show ./disk.raw`
-$> sudo mkfs.vfat -n EFI -v ${lodev}p1
-$> sudo mkfs.ext4 -L ROOT -v ${lodev}p2
+ $> truncate -s 1200M ./disk.raw
+ $> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk ./disk.raw
+ $> lodev=`sudo losetup -P -f --show ./disk.raw`
+ $> sudo mkfs.vfat -n EFI -v ${lodev}p1
+ $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2
-or utilize the device described in test/py/make_test_disk.py:
+or utilize the device described in test/py/make_test_disk.py::
#!/usr/bin/python
import make_test_disk
@@ -395,16 +402,16 @@
Debugging the init sequence
---------------------------
-If you get a failure in the initcall sequence, like this:
+If you get a failure in the initcall sequence, like this::
initcall sequence 0000560775957c80 failed at call 0000000000048134 (err=-96)
-Then you use can use grep to see which init call failed, e.g.:
+Then you use can use grep to see which init call failed, e.g.::
$ grep 0000000000048134 u-boot.map
stdio_add_devices
-Of course another option is to run it with a debugger such as gdb:
+Of course another option is to run it with a debugger such as gdb::
$ gdb u-boot
...
@@ -414,6 +421,8 @@
Note that two locations are reported, since this function is used in both
board_init_f() and board_init_r().
+.. code-block:: none
+
(gdb) r
Starting program: /tmp/b/sandbox/u-boot
[Thread debugging using libthread_db enabled]
@@ -445,13 +454,13 @@
Using valgrind / memcheck
-------------------------
-It is possible to run U-Boot under valgrind to check memory allocations:
+It is possible to run U-Boot under valgrind to check memory allocations::
valgrind u-boot
If you are running sandbox SPL or TPL, then valgrind will not by default
notice when U-Boot jumps from TPL to SPL, or from SPL to U-Boot proper. To
-fix this, use:
+fix this, use::
valgrind --trace-children=yes u-boot
@@ -462,22 +471,24 @@
U-Boot sandbox can be used to run various tests, mostly in the test/
directory. These include:
+command_ut:
+ Unit tests for command parsing and handling
+compression:
+ Unit tests for U-Boot's compression algorithms, useful for
+ security checking. It supports gzip, bzip2, lzma and lzo.
+driver model:
+ Run this pytest::
+
- command_ut
- - Unit tests for command parsing and handling
- compression
- - Unit tests for U-Boot's compression algorithms, useful for
- security checking. It supports gzip, bzip2, lzma and lzo.
- driver model
- - Run this pytest
- ./test/py/test.py --bd sandbox --build -k ut_dm -v
- image
- - Unit tests for images:
- test/image/test-imagetools.sh - multi-file images
- test/image/test-fit.py - FIT images
- tracing
- - test/trace/test-trace.sh tests the tracing system (see README.trace)
- verified boot
- - See test/vboot/vboot_test.sh for this
+ ./test/py/test.py --bd sandbox --build -k ut_dm -v
+
+image:
+ Unit tests for images:
+ test/image/test-imagetools.sh - multi-file images
+ test/image/test-fit.py - FIT images
+tracing:
+ test/trace/test-trace.sh tests the tracing system (see README.trace)
+verified boot:
+ See test/vboot/vboot_test.sh for this
If you change or enhance any of the above subsystems, you shold write or
expand a test and include it with your patch series submission. Test
@@ -495,14 +506,12 @@
Sandbox has its own emulated memory starting at 0. Here are some of the things
that are mapped into that memory:
+======= ======================== ===============================
+Addr Config Usage
+======= ======================== ===============================
0 CONFIG_SYS_FDT_LOAD_ADDR Device tree
e000 CONFIG_BLOBLIST_ADDR Blob list
10000 CONFIG_MALLOC_F_ADDR Early memory allocation
f0000 CONFIG_PRE_CON_BUF_ADDR Pre-console buffer
100000 CONFIG_TRACE_EARLY_ADDR Early trace buffer (if enabled)
-=
-
-
---
-Simon Glass <sjg@chromium.org>
-Updated 22-Mar-14
+======= ======================== ===============================
diff --git a/doc/arch/sh.rst b/doc/arch/sh.rst
new file mode 100644
index 0000000..3a3f92d
--- /dev/null
+++ b/doc/arch/sh.rst
@@ -0,0 +1,106 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (c) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigaur.org>
+
+SuperH
+======
+
+What's this?
+------------
+This file contains status information for the port of U-Boot to the
+Renesas SuperH series of CPUs.
+
+Overview
+--------
+SuperH has an original boot loader. However, source code is dirty, and
+maintenance is not done. To improve sharing and the maintenance of the code,
+Nobuhiro Iwamatsu started the porting to U-Boot in 2007.
+
+Supported CPUs
+--------------
+
+Renesas SH7750/SH7750R
+^^^^^^^^^^^^^^^^^^^^^^
+This CPU has the SH4 core.
+
+Renesas SH7722
+^^^^^^^^^^^^^^
+This CPU has the SH4AL-DSP core.
+
+Renesas SH7780
+^^^^^^^^^^^^^^
+This CPU has the SH4A core.
+
+Supported Boards
+----------------
+
+Hitachi UL MS7750SE01/MS7750RSE01
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Board specific code is in board/ms7750se
+To use this board, type "make ms7750se_config".
+Support devices are:
+
+ - SCIF
+ - SDRAM
+ - NOR Flash
+ - Marubun PCMCIA
+
+Hitachi UL MS7722SE01
+^^^^^^^^^^^^^^^^^^^^^
+Board specific code is in board/ms7722se
+To use this board, type "make ms7722se_config".
+Support devices are:
+
+ - SCIF
+ - SDRAM
+ - NOR Flash
+ - Marubun PCMCIA
+ - SMC91x ethernet
+
+Hitachi UL MS7720ERP01
+^^^^^^^^^^^^^^^^^^^^^^
+Board specific code is in board/ms7720se
+To use this board, type "make ms7720se_config".
+Support devices are:
+
+ - SCIF
+ - SDRAM
+ - NOR Flash
+ - Marubun PCMCIA
+
+Renesas R7780MP
+^^^^^^^^^^^^^^^
+Board specific code is in board/r7780mp
+To use this board, type "make r7780mp_config".
+Support devices are:
+
+ - SCIF
+ - DDR-SDRAM
+ - NOR Flash
+ - Compact Flash
+ - ASIX ethernet
+ - SH7780 PCI bridge
+ - RTL8110 ethernet
+
+In SuperH, S-record and binary of made u-boot work on the memory.
+When u-boot is written in the flash, it is necessary to change the
+address by using 'objcopy'::
+
+ ex) shX-linux-objcopy -Ibinary -Osrec u-boot.bin u-boot.flash.srec
+
+Compiler
+--------
+You can use the following of u-boot to compile.
+ - `SuperH Linux Open site <http://www.superh-linux.org/>`_
+ - `KPIT GNU tools <http://www.kpitgnutools.com/>`_
+
+Future
+------
+I plan to support the following CPUs and boards.
+
+CPUs
+^^^^
+- SH7751R(SH4)
+
+Boards
+^^^^^^
+Many boards ;-)
diff --git a/doc/arch/x86.rst b/doc/arch/x86.rst
new file mode 100644
index 0000000..2eb524c
--- /dev/null
+++ b/doc/arch/x86.rst
@@ -0,0 +1,728 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (C) 2014, Simon Glass <sjg@chromium.org>
+.. Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+
+x86
+===
+
+This document describes the information about U-Boot running on x86 targets,
+including supported boards, build instructions, todo list, etc.
+
+Status
+------
+U-Boot supports running as a `coreboot`_ payload on x86. So far only Link
+(Chromebook Pixel) and `QEMU`_ x86 targets have been tested, but it should
+work with minimal adjustments on other x86 boards since coreboot deals with
+most of the low-level details.
+
+U-Boot is a main bootloader on Intel Edison board.
+
+U-Boot also supports booting directly from x86 reset vector, without coreboot.
+In this case, known as bare mode, from the fact that it runs on the
+'bare metal', U-Boot acts like a BIOS replacement. The following platforms
+are supported:
+
+ - Bayley Bay CRB
+ - Cherry Hill CRB
+ - Congatec QEVAL 2.0 & conga-QA3/E3845
+ - Cougar Canyon 2 CRB
+ - Crown Bay CRB
+ - Galileo
+ - Link (Chromebook Pixel)
+ - Minnowboard MAX
+ - Samus (Chromebook Pixel 2015)
+ - QEMU x86 (32-bit & 64-bit)
+
+As for loading an OS, U-Boot supports directly booting a 32-bit or 64-bit
+Linux kernel as part of a FIT image. It also supports a compressed zImage.
+U-Boot supports loading an x86 VxWorks kernel. Please check README.vxworks
+for more details.
+
+Build Instructions for U-Boot as BIOS replacement (bare mode)
+-------------------------------------------------------------
+Building a ROM version of U-Boot (hereafter referred to as u-boot.rom) is a
+little bit tricky, as generally it requires several binary blobs which are not
+shipped in the U-Boot source tree. Due to this reason, the u-boot.rom build is
+not turned on by default in the U-Boot source tree. Firstly, you need turn it
+on by enabling the ROM build either via an environment variable::
+
+ $ export BUILD_ROM=y
+
+or via configuration::
+
+ CONFIG_BUILD_ROM=y
+
+Both tell the Makefile to build u-boot.rom as a target.
+
+CPU Microcode
+-------------
+Modern CPUs usually require a special bit stream called `microcode`_ to be
+loaded on the processor after power up in order to function properly. U-Boot
+has already integrated these as hex dumps in the source tree.
+
+SMP Support
+-----------
+On a multicore system, U-Boot is executed on the bootstrap processor (BSP).
+Additional application processors (AP) can be brought up by U-Boot. In order to
+have an SMP kernel to discover all of the available processors, U-Boot needs to
+prepare configuration tables which contain the multi-CPUs information before
+loading the OS kernel. Currently U-Boot supports generating two types of tables
+for SMP, called Simple Firmware Interface (`SFI`_) and Multi-Processor (`MP`_)
+tables. The writing of these two tables are controlled by two Kconfig
+options GENERATE_SFI_TABLE and GENERATE_MP_TABLE.
+
+Driver Model
+------------
+x86 has been converted to use driver model for serial, GPIO, SPI, SPI flash,
+keyboard, real-time clock, USB. Video is in progress.
+
+Device Tree
+-----------
+x86 uses device tree to configure the board thus requires CONFIG_OF_CONTROL to
+be turned on. Not every device on the board is configured via device tree, but
+more and more devices will be added as time goes by. Check out the directory
+arch/x86/dts/ for these device tree source files.
+
+Useful Commands
+---------------
+In keeping with the U-Boot philosophy of providing functions to check and
+adjust internal settings, there are several x86-specific commands that may be
+useful:
+
+fsp
+ Display information about Intel Firmware Support Package (FSP).
+ This is only available on platforms which use FSP, mostly Atom.
+iod
+ Display I/O memory
+iow
+ Write I/O memory
+mtrr
+ List and set the Memory Type Range Registers (MTRR). These are used to
+ tell the CPU whether memory is cacheable and if so the cache write
+ mode to use. U-Boot sets up some reasonable values but you can
+ adjust then with this command.
+
+Booting Ubuntu
+--------------
+As an example of how to set up your boot flow with U-Boot, here are
+instructions for starting Ubuntu from U-Boot. These instructions have been
+tested on Minnowboard MAX with a SATA drive but are equally applicable on
+other platforms and other media. There are really only four steps and it's a
+very simple script, but a more detailed explanation is provided here for
+completeness.
+
+Note: It is possible to set up U-Boot to boot automatically using syslinux.
+It could also use the grub.cfg file (/efi/ubuntu/grub.cfg) to obtain the
+GUID. If you figure these out, please post patches to this README.
+
+Firstly, you will need Ubuntu installed on an available disk. It should be
+possible to make U-Boot start a USB start-up disk but for now let's assume
+that you used another boot loader to install Ubuntu.
+
+Use the U-Boot command line to find the UUID of the partition you want to
+boot. For example our disk is SCSI device 0::
+
+ => part list scsi 0
+
+ Partition Map for SCSI device 0 -- Partition Type: EFI
+
+ Part Start LBA End LBA Name
+ Attributes
+ Type GUID
+ Partition GUID
+ 1 0x00000800 0x001007ff ""
+ attrs: 0x0000000000000000
+ type: c12a7328-f81f-11d2-ba4b-00a0c93ec93b
+ guid: 9d02e8e4-4d59-408f-a9b0-fd497bc9291c
+ 2 0x00100800 0x037d8fff ""
+ attrs: 0x0000000000000000
+ type: 0fc63daf-8483-4772-8e79-3d69d8477de4
+ guid: 965c59ee-1822-4326-90d2-b02446050059
+ 3 0x037d9000 0x03ba27ff ""
+ attrs: 0x0000000000000000
+ type: 0657fd6d-a4ab-43c4-84e5-0933c84b4f4f
+ guid: 2c4282bd-1e82-4bcf-a5ff-51dedbf39f17
+ =>
+
+This shows that your SCSI disk has three partitions. The really long hex
+strings are called Globally Unique Identifiers (GUIDs). You can look up the
+'type' ones `here`_. On this disk the first partition is for EFI and is in
+VFAT format (DOS/Windows)::
+
+ => fatls scsi 0:1
+ efi/
+
+ 0 file(s), 1 dir(s)
+
+
+Partition 2 is 'Linux filesystem data' so that will be our root disk. It is
+in ext2 format::
+
+ => ext2ls scsi 0:2
+ <DIR> 4096 .
+ <DIR> 4096 ..
+ <DIR> 16384 lost+found
+ <DIR> 4096 boot
+ <DIR> 12288 etc
+ <DIR> 4096 media
+ <DIR> 4096 bin
+ <DIR> 4096 dev
+ <DIR> 4096 home
+ <DIR> 4096 lib
+ <DIR> 4096 lib64
+ <DIR> 4096 mnt
+ <DIR> 4096 opt
+ <DIR> 4096 proc
+ <DIR> 4096 root
+ <DIR> 4096 run
+ <DIR> 12288 sbin
+ <DIR> 4096 srv
+ <DIR> 4096 sys
+ <DIR> 4096 tmp
+ <DIR> 4096 usr
+ <DIR> 4096 var
+ <SYM> 33 initrd.img
+ <SYM> 30 vmlinuz
+ <DIR> 4096 cdrom
+ <SYM> 33 initrd.img.old
+ =>
+
+and if you look in the /boot directory you will see the kernel::
+
+ => ext2ls scsi 0:2 /boot
+ <DIR> 4096 .
+ <DIR> 4096 ..
+ <DIR> 4096 efi
+ <DIR> 4096 grub
+ 3381262 System.map-3.13.0-32-generic
+ 1162712 abi-3.13.0-32-generic
+ 165611 config-3.13.0-32-generic
+ 176500 memtest86+.bin
+ 178176 memtest86+.elf
+ 178680 memtest86+_multiboot.bin
+ 5798112 vmlinuz-3.13.0-32-generic
+ 165762 config-3.13.0-58-generic
+ 1165129 abi-3.13.0-58-generic
+ 5823136 vmlinuz-3.13.0-58-generic
+ 19215259 initrd.img-3.13.0-58-generic
+ 3391763 System.map-3.13.0-58-generic
+ 5825048 vmlinuz-3.13.0-58-generic.efi.signed
+ 28304443 initrd.img-3.13.0-32-generic
+ =>
+
+The 'vmlinuz' files contain a packaged Linux kernel. The format is a kind of
+self-extracting compressed file mixed with some 'setup' configuration data.
+Despite its size (uncompressed it is >10MB) this only includes a basic set of
+device drivers, enough to boot on most hardware types.
+
+The 'initrd' files contain a RAM disk. This is something that can be loaded
+into RAM and will appear to Linux like a disk. Ubuntu uses this to hold lots
+of drivers for whatever hardware you might have. It is loaded before the
+real root disk is accessed.
+
+The numbers after the end of each file are the version. Here it is Linux
+version 3.13. You can find the source code for this in the Linux tree with
+the tag v3.13. The '.0' allows for additional Linux releases to fix problems,
+but normally this is not needed. The '-58' is used by Ubuntu. Each time they
+release a new kernel they increment this number. New Ubuntu versions might
+include kernel patches to fix reported bugs. Stable kernels can exist for
+some years so this number can get quite high.
+
+The '.efi.signed' kernel is signed for EFI's secure boot. U-Boot has its own
+secure boot mechanism - see `this`_ & `that`_. It cannot read .efi files
+at present.
+
+To boot Ubuntu from U-Boot the steps are as follows:
+
+1. Set up the boot arguments. Use the GUID for the partition you want to boot::
+
+ => setenv bootargs root=/dev/disk/by-partuuid/965c59ee-1822-4326-90d2-b02446050059 ro
+
+Here root= tells Linux the location of its root disk. The disk is specified
+by its GUID, using '/dev/disk/by-partuuid/', a Linux path to a 'directory'
+containing all the GUIDs Linux has found. When it starts up, there will be a
+file in that directory with this name in it. It is also possible to use a
+device name here, see later.
+
+2. Load the kernel. Since it is an ext2/4 filesystem we can do::
+
+ => ext2load scsi 0:2 03000000 /boot/vmlinuz-3.13.0-58-generic
+
+The address 30000000 is arbitrary, but there seem to be problems with using
+small addresses (sometimes Linux cannot find the ramdisk). This is 48MB into
+the start of RAM (which is at 0 on x86).
+
+3. Load the ramdisk (to 64MB)::
+
+ => ext2load scsi 0:2 04000000 /boot/initrd.img-3.13.0-58-generic
+
+4. Start up the kernel. We need to know the size of the ramdisk, but can use
+ a variable for that. U-Boot sets 'filesize' to the size of the last file it
+ loaded::
+
+ => zboot 03000000 0 04000000 ${filesize}
+
+Type 'help zboot' if you want to see what the arguments are. U-Boot on x86 is
+quite verbose when it boots a kernel. You should see these messages from
+U-Boot::
+
+ Valid Boot Flag
+ Setup Size = 0x00004400
+ Magic signature found
+ Using boot protocol version 2.0c
+ Linux kernel version 3.13.0-58-generic (buildd@allspice) #97-Ubuntu SMP Wed Jul 8 02:56:15 UTC 2015
+ Building boot_params at 0x00090000
+ Loading bzImage at address 100000 (5805728 bytes)
+ Magic signature found
+ Initial RAM disk at linear address 0x04000000, size 19215259 bytes
+ Kernel command line: "root=/dev/disk/by-partuuid/965c59ee-1822-4326-90d2-b02446050059 ro"
+
+ Starting kernel ...
+
+U-Boot prints out some bootstage timing. This is more useful if you put the
+above commands into a script since then it will be faster::
+
+ Timer summary in microseconds:
+ Mark Elapsed Stage
+ 0 0 reset
+ 241,535 241,535 board_init_r
+ 2,421,611 2,180,076 id=64
+ 2,421,790 179 id=65
+ 2,428,215 6,425 main_loop
+ 48,860,584 46,432,369 start_kernel
+
+ Accumulated time:
+ 240,329 ahci
+ 1,422,704 vesa display
+
+Now the kernel actually starts (if you want to examine kernel boot up message on
+the serial console, append "console=ttyS0,115200" to the kernel command line)::
+
+ [ 0.000000] Initializing cgroup subsys cpuset
+ [ 0.000000] Initializing cgroup subsys cpu
+ [ 0.000000] Initializing cgroup subsys cpuacct
+ [ 0.000000] Linux version 3.13.0-58-generic (buildd@allspice) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #97-Ubuntu SMP Wed Jul 8 02:56:15 UTC 2015 (Ubuntu 3.13.0-58.97-generic 3.13.11-ckt22)
+ [ 0.000000] Command line: root=/dev/disk/by-partuuid/965c59ee-1822-4326-90d2-b02446050059 ro console=ttyS0,115200
+
+It continues for a long time. Along the way you will see it pick up your
+ramdisk::
+
+ [ 0.000000] RAMDISK: [mem 0x04000000-0x05253fff]
+ ...
+ [ 0.788540] Trying to unpack rootfs image as initramfs...
+ [ 1.540111] Freeing initrd memory: 18768K (ffff880004000000 - ffff880005254000)
+ ...
+
+Later it actually starts using it::
+
+ Begin: Running /scripts/local-premount ... done.
+
+You should also see your boot disk turn up::
+
+ [ 4.357243] scsi 1:0:0:0: Direct-Access ATA ADATA SP310 5.2 PQ: 0 ANSI: 5
+ [ 4.366860] sd 1:0:0:0: [sda] 62533296 512-byte logical blocks: (32.0 GB/29.8 GiB)
+ [ 4.375677] sd 1:0:0:0: Attached scsi generic sg0 type 0
+ [ 4.381859] sd 1:0:0:0: [sda] Write Protect is off
+ [ 4.387452] sd 1:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
+ [ 4.399535] sda: sda1 sda2 sda3
+
+Linux has found the three partitions (sda1-3). Mercifully it doesn't print out
+the GUIDs. In step 1 above we could have used::
+
+ setenv bootargs root=/dev/sda2 ro
+
+instead of the GUID. However if you add another drive to your board the
+numbering may change whereas the GUIDs will not. So if your boot partition
+becomes sdb2, it will still boot. For embedded systems where you just want to
+boot the first disk, you have that option.
+
+The last thing you will see on the console is mention of plymouth (which
+displays the Ubuntu start-up screen) and a lot of 'Starting' messages::
+
+ * Starting Mount filesystems on boot [ OK ]
+
+After a pause you should see a login screen on your display and you are done.
+
+If you want to put this in a script you can use something like this::
+
+ setenv bootargs root=UUID=b2aaf743-0418-4d90-94cc-3e6108d7d968 ro
+ setenv boot zboot 03000000 0 04000000 \${filesize}
+ setenv bootcmd "ext2load scsi 0:2 03000000 /boot/vmlinuz-3.13.0-58-generic; ext2load scsi 0:2 04000000 /boot/initrd.img-3.13.0-58-generic; run boot"
+ saveenv
+
+The \ is to tell the shell not to evaluate ${filesize} as part of the setenv
+command.
+
+You can also bake this behaviour into your build by hard-coding the
+environment variables if you add this to minnowmax.h:
+
+.. code-block:: c
+
+ #undef CONFIG_BOOTCOMMAND
+ #define CONFIG_BOOTCOMMAND \
+ "ext2load scsi 0:2 03000000 /boot/vmlinuz-3.13.0-58-generic; " \
+ "ext2load scsi 0:2 04000000 /boot/initrd.img-3.13.0-58-generic; " \
+ "run boot"
+
+ #undef CONFIG_EXTRA_ENV_SETTINGS
+ #define CONFIG_EXTRA_ENV_SETTINGS "boot=zboot 03000000 0 04000000 ${filesize}"
+
+and change CONFIG_BOOTARGS value in configs/minnowmax_defconfig to::
+
+ CONFIG_BOOTARGS="root=/dev/sda2 ro"
+
+Test with SeaBIOS
+-----------------
+`SeaBIOS`_ is an open source implementation of a 16-bit x86 BIOS. It can run
+in an emulator or natively on x86 hardware with the use of U-Boot. With its
+help, we can boot some OSes that require 16-bit BIOS services like Windows/DOS.
+
+As U-Boot, we have to manually create a table where SeaBIOS gets various system
+information (eg: E820) from. The table unfortunately has to follow the coreboot
+table format as SeaBIOS currently supports booting as a coreboot payload.
+
+To support loading SeaBIOS, U-Boot should be built with CONFIG_SEABIOS on.
+Booting SeaBIOS is done via U-Boot's bootelf command, like below::
+
+ => tftp bios.bin.elf;bootelf
+ Using e1000#0 device
+ TFTP from server 10.10.0.100; our IP address is 10.10.0.108
+ ...
+ Bytes transferred = 122124 (1dd0c hex)
+ ## Starting application at 0x000ff06e ...
+ SeaBIOS (version rel-1.9.0)
+ ...
+
+bios.bin.elf is the SeaBIOS image built from SeaBIOS source tree.
+Make sure it is built as follows::
+
+ $ make menuconfig
+
+Inside the "General Features" menu, select "Build for coreboot" as the
+"Build Target". Inside the "Debugging" menu, turn on "Serial port debugging"
+so that we can see something as soon as SeaBIOS boots. Leave other options
+as in their default state. Then::
+
+ $ make
+ ...
+ Total size: 121888 Fixed: 66496 Free: 9184 (used 93.0% of 128KiB rom)
+ Creating out/bios.bin.elf
+
+Currently this is tested on QEMU x86 target with U-Boot chain-loading SeaBIOS
+to install/boot a Windows XP OS (below for example command to install Windows).
+
+.. code-block:: none
+
+ # Create a 10G disk.img as the virtual hard disk
+ $ qemu-img create -f qcow2 disk.img 10G
+
+ # Install a Windows XP OS from an ISO image 'winxp.iso'
+ $ qemu-system-i386 -serial stdio -bios u-boot.rom -hda disk.img -cdrom winxp.iso -smp 2 -m 512
+
+ # Boot a Windows XP OS installed on the virutal hard disk
+ $ qemu-system-i386 -serial stdio -bios u-boot.rom -hda disk.img -smp 2 -m 512
+
+This is also tested on Intel Crown Bay board with a PCIe graphics card, booting
+SeaBIOS then chain-loading a GRUB on a USB drive, then Linux kernel finally.
+
+If you are using Intel Integrated Graphics Device (IGD) as the primary display
+device on your board, SeaBIOS needs to be patched manually to get its VGA ROM
+loaded and run by SeaBIOS. SeaBIOS locates VGA ROM via the PCI expansion ROM
+register, but IGD device does not have its VGA ROM mapped by this register.
+Its VGA ROM is packaged as part of u-boot.rom at a configurable flash address
+which is unknown to SeaBIOS. An example patch is needed for SeaBIOS below:
+
+.. code-block:: none
+
+ diff --git a/src/optionroms.c b/src/optionroms.c
+ index 65f7fe0..c7b6f5e 100644
+ --- a/src/optionroms.c
+ +++ b/src/optionroms.c
+ @@ -324,6 +324,8 @@ init_pcirom(struct pci_device *pci, int isvga, u64 *sources)
+ rom = deploy_romfile(file);
+ else if (RunPCIroms > 1 || (RunPCIroms == 1 && isvga))
+ rom = map_pcirom(pci);
+ + if (pci->bdf == pci_to_bdf(0, 2, 0))
+ + rom = (struct rom_header *)0xfff90000;
+ if (! rom)
+ // No ROM present.
+ return;
+
+Note: the patch above expects IGD device is at PCI b.d.f 0.2.0 and its VGA ROM
+is at 0xfff90000 which corresponds to CONFIG_VGA_BIOS_ADDR on Minnowboard MAX.
+Change these two accordingly if this is not the case on your board.
+
+Development Flow
+----------------
+These notes are for those who want to port U-Boot to a new x86 platform.
+
+Since x86 CPUs boot from SPI flash, a SPI flash emulator is a good investment.
+The Dediprog em100 can be used on Linux.
+
+The em100 tool is available here: http://review.coreboot.org/p/em100.git
+
+On Minnowboard Max the following command line can be used::
+
+ sudo em100 -s -p LOW -d u-boot.rom -c W25Q64DW -r
+
+A suitable clip for connecting over the SPI flash chip is here:
+http://www.dediprog.com/pd/programmer-accessories/EM-TC-8.
+
+This allows you to override the SPI flash contents for development purposes.
+Typically you can write to the em100 in around 1200ms, considerably faster
+than programming the real flash device each time. The only important
+limitation of the em100 is that it only supports SPI bus speeds up to 20MHz.
+This means that images must be set to boot with that speed. This is an
+Intel-specific feature - e.g. tools/ifttool has an option to set the SPI
+speed in the SPI descriptor region.
+
+If your chip/board uses an Intel Firmware Support Package (FSP) it is fairly
+easy to fit it in. You can follow the Minnowboard Max implementation, for
+example. Hopefully you will just need to create new files similar to those
+in arch/x86/cpu/baytrail which provide Bay Trail support.
+
+If you are not using an FSP you have more freedom and more responsibility.
+The ivybridge support works this way, although it still uses a ROM for
+graphics and still has binary blobs containing Intel code. You should aim to
+support all important peripherals on your platform including video and storage.
+Use the device tree for configuration where possible.
+
+For the microcode you can create a suitable device tree file using the
+microcode tool::
+
+ ./tools/microcode-tool -d microcode.dat -m <model> create
+
+or if you only have header files and not the full Intel microcode.dat database::
+
+ ./tools/microcode-tool -H BAY_TRAIL_FSP_KIT/Microcode/M0130673322.h \
+ -H BAY_TRAIL_FSP_KIT/Microcode/M0130679901.h -m all create
+
+These are written to arch/x86/dts/microcode/ by default.
+
+Note that it is possible to just add the micrcode for your CPU if you know its
+model. U-Boot prints this information when it starts::
+
+ CPU: x86_64, vendor Intel, device 30673h
+
+so here we can use the M0130673322 file.
+
+If you platform can display POST codes on two little 7-segment displays on
+the board, then you can use post_code() calls from C or assembler to monitor
+boot progress. This can be good for debugging.
+
+If not, you can try to get serial working as early as possible. The early
+debug serial port may be useful here. See setup_internal_uart() for an example.
+
+During the U-Boot porting, one of the important steps is to write correct PIRQ
+routing information in the board device tree. Without it, device drivers in the
+Linux kernel won't function correctly due to interrupt is not working. Please
+refer to U-Boot `doc <doc/device-tree-bindings/misc/intel,irq-router.txt>`_ for
+the device tree bindings of Intel interrupt router. Here we have more details
+on the intel,pirq-routing property below.
+
+.. code-block:: none
+
+ intel,pirq-routing = <
+ PCI_BDF(0, 2, 0) INTA PIRQA
+ ...
+ >;
+
+As you see each entry has 3 cells. For the first one, we need describe all pci
+devices mounted on the board. For SoC devices, normally there is a chapter on
+the chipset datasheet which lists all the available PCI devices. For example on
+Bay Trail, this is chapter 4.3 (PCI configuration space). For the second one, we
+can get the interrupt pin either from datasheet or hardware via U-Boot shell.
+The reliable source is the hardware as sometimes chipset datasheet is not 100%
+up-to-date. Type 'pci header' plus the device's pci bus/device/function number
+from U-Boot shell below::
+
+ => pci header 0.1e.1
+ vendor ID = 0x8086
+ device ID = 0x0f08
+ ...
+ interrupt line = 0x09
+ interrupt pin = 0x04
+ ...
+
+It shows this PCI device is using INTD pin as it reports 4 in the interrupt pin
+register. Repeat this until you get interrupt pins for all the devices. The last
+cell is the PIRQ line which a particular interrupt pin is mapped to. On Intel
+chipset, the power-up default mapping is INTA/B/C/D maps to PIRQA/B/C/D. This
+can be changed by registers in LPC bridge. So far Intel FSP does not touch those
+registers so we can write down the PIRQ according to the default mapping rule.
+
+Once we get the PIRQ routing information in the device tree, the interrupt
+allocation and assignment will be done by U-Boot automatically. Now you can
+enable CONFIG_GENERATE_PIRQ_TABLE for testing Linux kernel using i8259 PIC and
+CONFIG_GENERATE_MP_TABLE for testing Linux kernel using local APIC and I/O APIC.
+
+This script might be useful. If you feed it the output of 'pci long' from
+U-Boot then it will generate a device tree fragment with the interrupt
+configuration for each device (note it needs gawk 4.0.0)::
+
+ $ cat console_output |awk '/PCI/ {device=$4} /interrupt line/ {line=$4} \
+ /interrupt pin/ {pin = $4; if (pin != "0x00" && pin != "0xff") \
+ {patsplit(device, bdf, "[0-9a-f]+"); \
+ printf "PCI_BDF(%d, %d, %d) INT%c PIRQ%c\n", strtonum("0x" bdf[1]), \
+ strtonum("0x" bdf[2]), bdf[3], strtonum(pin) + 64, 64 + strtonum(pin)}}'
+
+Example output::
+
+ PCI_BDF(0, 2, 0) INTA PIRQA
+ PCI_BDF(0, 3, 0) INTA PIRQA
+ ...
+
+Porting Hints
+-------------
+
+Quark-specific considerations
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To port U-Boot to other boards based on the Intel Quark SoC, a few things need
+to be taken care of. The first important part is the Memory Reference Code (MRC)
+parameters. Quark MRC supports memory-down configuration only. All these MRC
+parameters are supplied via the board device tree. To get started, first copy
+the MRC section of arch/x86/dts/galileo.dts to your board's device tree, then
+change these values by consulting board manuals or your hardware vendor.
+Available MRC parameter values are listed in include/dt-bindings/mrc/quark.h.
+The other tricky part is with PCIe. Quark SoC integrates two PCIe root ports,
+but by default they are held in reset after power on. In U-Boot, PCIe
+initialization is properly handled as per Quark's firmware writer guide.
+In your board support codes, you need provide two routines to aid PCIe
+initialization, which are board_assert_perst() and board_deassert_perst().
+The two routines need implement a board-specific mechanism to assert/deassert
+PCIe PERST# pin. Care must be taken that in those routines that any APIs that
+may trigger PCI enumeration process are strictly forbidden, as any access to
+PCIe root port's configuration registers will cause system hang while it is
+held in reset. For more details, check how they are implemented by the Intel
+Galileo board support codes in board/intel/galileo/galileo.c.
+
+coreboot
+^^^^^^^^
+
+See scripts/coreboot.sed which can assist with porting coreboot code into
+U-Boot drivers. It will not resolve all build errors, but will perform common
+transformations. Remember to add attribution to coreboot for new files added
+to U-Boot. This should go at the top of each file and list the coreboot
+filename where the code originated.
+
+Debugging ACPI issues with Windows
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Windows might cache system information and only detect ACPI changes if you
+modify the ACPI table versions. So tweak them liberally when debugging ACPI
+issues with Windows.
+
+ACPI Support Status
+-------------------
+Advanced Configuration and Power Interface (`ACPI`_) aims to establish
+industry-standard interfaces enabling OS-directed configuration, power
+management, and thermal management of mobile, desktop, and server platforms.
+
+Linux can boot without ACPI with "acpi=off" command line parameter, but
+with ACPI the kernel gains the capabilities to handle power management.
+For Windows, ACPI is a must-have firmware feature since Windows Vista.
+CONFIG_GENERATE_ACPI_TABLE is the config option to turn on ACPI support in
+U-Boot. This requires Intel ACPI compiler to be installed on your host to
+compile ACPI DSDT table written in ASL format to AML format. You can get
+the compiler via "apt-get install iasl" if you are on Ubuntu or download
+the source from https://www.acpica.org/downloads to compile one by yourself.
+
+Current ACPI support in U-Boot is basically complete. More optional features
+can be added in the future. The status as of today is:
+
+ * Support generating RSDT, XSDT, FACS, FADT, MADT, MCFG tables.
+ * Support one static DSDT table only, compiled by Intel ACPI compiler.
+ * Support S0/S3/S4/S5, reboot and shutdown from OS.
+ * Support booting a pre-installed Ubuntu distribution via 'zboot' command.
+ * Support installing and booting Ubuntu 14.04 (or above) from U-Boot with
+ the help of SeaBIOS using legacy interface (non-UEFI mode).
+ * Support installing and booting Windows 8.1/10 from U-Boot with the help
+ of SeaBIOS using legacy interface (non-UEFI mode).
+ * Support ACPI interrupts with SCI only.
+
+Features that are optional:
+
+ * Dynamic AML bytecodes insertion at run-time. We may need this to support
+ SSDT table generation and DSDT fix up.
+ * SMI support. Since U-Boot is a modern bootloader, we don't want to bring
+ those legacy stuff into U-Boot. ACPI spec allows a system that does not
+ support SMI (a legacy-free system).
+
+ACPI was initially enabled on BayTrail based boards. Testing was done by booting
+a pre-installed Ubuntu 14.04 from a SATA drive. Installing Ubuntu 14.04 and
+Windows 8.1/10 to a SATA drive and booting from there is also tested. Most
+devices seem to work correctly and the board can respond a reboot/shutdown
+command from the OS.
+
+For other platform boards, ACPI support status can be checked by examining their
+board defconfig files to see if CONFIG_GENERATE_ACPI_TABLE is set to y.
+
+The S3 sleeping state is a low wake latency sleeping state defined by ACPI
+spec where all system context is lost except system memory. To test S3 resume
+with a Linux kernel, simply run "echo mem > /sys/power/state" and kernel will
+put the board to S3 state where the power is off. So when the power button is
+pressed again, U-Boot runs as it does in cold boot and detects the sleeping
+state via ACPI register to see if it is S3, if yes it means we are waking up.
+U-Boot is responsible for restoring the machine state as it is before sleep.
+When everything is done, U-Boot finds out the wakeup vector provided by OSes
+and jump there. To determine whether ACPI S3 resume is supported, check to
+see if CONFIG_HAVE_ACPI_RESUME is set for that specific board.
+
+Note for testing S3 resume with Windows, correct graphics driver must be
+installed for your platform, otherwise you won't find "Sleep" option in
+the "Power" submenu from the Windows start menu.
+
+EFI Support
+-----------
+U-Boot supports booting as a 32-bit or 64-bit EFI payload, e.g. with UEFI.
+This is enabled with CONFIG_EFI_STUB to boot from both 32-bit and 64-bit
+UEFI BIOS. U-Boot can also run as an EFI application, with CONFIG_EFI_APP.
+The CONFIG_EFI_LOADER option, where U-Boot provides an EFI environment to
+the kernel (i.e. replaces UEFI completely but provides the same EFI run-time
+services) is supported too. For example, we can even use 'bootefi' command
+to load a 'u-boot-payload.efi', see below test logs on QEMU.
+
+.. code-block:: none
+
+ => load ide 0 3000000 u-boot-payload.efi
+ 489787 bytes read in 138 ms (3.4 MiB/s)
+ => bootefi 3000000
+ Scanning disk ide.blk#0...
+ Found 2 disks
+ WARNING: booting without device tree
+ ## Starting EFI application at 03000000 ...
+ U-Boot EFI Payload
+
+
+ U-Boot 2018.07-rc2 (Jun 23 2018 - 17:12:58 +0800)
+
+ CPU: x86_64, vendor AMD, device 663h
+ DRAM: 2 GiB
+ MMC:
+ Video: 1024x768x32
+ Model: EFI x86 Payload
+ Net: e1000: 52:54:00:12:34:56
+
+ Warning: e1000#0 using MAC address from ROM
+ eth0: e1000#0
+ No controllers found
+ Hit any key to stop autoboot: 0
+
+See README.u-boot_on_efi and README.uefi for details of EFI support in U-Boot.
+
+TODO List
+---------
+- Audio
+- Chrome OS verified boot
+
+.. _coreboot: http://www.coreboot.org
+.. _QEMU: http://www.qemu.org
+.. _microcode: http://en.wikipedia.org/wiki/Microcode
+.. _SFI: http://simplefirmware.org
+.. _MP: http://www.intel.com/design/archives/processors/pro/docs/242016.htm
+.. _here: https://en.wikipedia.org/wiki/GUID_Partition_Table
+.. _this: http://events.linuxfoundation.org/sites/events/files/slides/chromeos_and_diy_vboot_0.pdf
+.. _that: http://events.linuxfoundation.org/sites/events/files/slides/elce-2014.pdf
+.. _SeaBIOS: http://www.seabios.org/SeaBIOS
+.. _ACPI: http://www.acpi.info
diff --git a/doc/README.xtensa b/doc/arch/xtensa.rst
similarity index 89%
rename from doc/README.xtensa
rename to doc/arch/xtensa.rst
index 4068582..176410d 100644
--- a/doc/README.xtensa
+++ b/doc/arch/xtensa.rst
@@ -1,5 +1,7 @@
-U-Boot for the Xtensa Architecture
-==================================
+.. SPDX-License-Identifier: GPL-2.0+
+
+Xtensa
+======
Xtensa Architecture and Diamond Cores
-------------------------------------
@@ -35,15 +37,16 @@
the name for the processor configuration, for example, arch-dc233c for
the Diamond DC233 processor.
- core.h Definitions for the core itself.
+core.h:
+ Definitions for the core itself.
The following files are part of the overlay but not used by U-Boot.
- tie.h Co-processors and custom extensions defined
- in the Tensilica Instruction Extension (TIE)
- language.
- tie-asm.h Assembly macros to access custom-defined registers
- and states.
+tie.h:
+ Co-processors and custom extensions defined in the Tensilica Instruction
+ Extension (TIE) language.
+tie-asm.h:
+ Assembly macros to access custom-defined registers and states.
Global Data Pointer, Exported Function Stubs, and the ABI
@@ -92,6 +95,5 @@
reports such access attempts and resets the board.
-------------------------------------------------------------------------------
-Chris Zankel
-Ross Morley
+.. Chris Zankel
+.. Ross Morley
diff --git a/doc/README.ag101p b/doc/board/AndesTech/adp-ag101p.rst
similarity index 82%
rename from doc/README.ag101p
rename to doc/board/AndesTech/adp-ag101p.rst
index 8fc0ac5..879eba0 100644
--- a/doc/README.ag101p
+++ b/doc/board/AndesTech/adp-ag101p.rst
@@ -1,18 +1,21 @@
-Andes Technology SoC AG101P
-===========================
+.. SPDX-License-Identifier: GPL-2.0+
+
+ADP-AG101P
+==========
+
+ADP-AG101P is the SoC with AG101 hardcore CPU.
+
+AG101P SoC
+----------
AG101P is the mainline SoC produced by Andes Technology using N1213 CPU core
with FPU and DDR contoller support.
AG101P has integrated both AHB and APB bus and many periphals for application
and product development.
-ADP-AG101P
-=========
-
-ADP-AG101P is the SoC with AG101 hardcore CPU.
Configurations
-==============
+--------------
CONFIG_MEM_REMAP:
Doing memory remap is essential for preparing some non-OS or RTOS
@@ -24,13 +27,14 @@
in "include/configs/adp-ag101p.h".
Build and boot steps
-====================
+--------------------
-build:
+Build:
+
1. Prepare the toolchains and make sure the $PATH to toolchains is correct.
2. Use `make adp-ag101p_defconfig` in u-boot root to build the image.
-Burn u-boot to SPI ROM:
-====================
+Burn U-Boot to SPI ROM
+----------------------
This section will be added later.
diff --git a/doc/board/AndesTech/ax25-ae350.rst b/doc/board/AndesTech/ax25-ae350.rst
new file mode 100644
index 0000000..7a01893
--- /dev/null
+++ b/doc/board/AndesTech/ax25-ae350.rst
@@ -0,0 +1,329 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+AX25-AE350
+==========
+
+AE350 is the mainline SoC produced by Andes Technology using AX25 CPU core
+base on RISC-V architecture.
+
+AE350 has integrated both AHB and APB bus and many periphals for application
+and product development.
+
+AX25-AE350 is the SoC with AE350 hardcore CPU.
+
+AX25 is Andes CPU IP to adopt RISC-V architecture.
+
+AX25 Features
+-------------
+
+CPU Core
+ - 5-stage in-order execution pipeline
+ - Hardware Multiplier
+ - radix-2/radix-4/radix-16/radix-256/fast
+ - Hardware Divider
+ - Optional branch prediction
+ - Machine mode and optional user mode
+ - Optional performance monitoring
+
+ISA
+ - RV64I base integer instructions
+ - RVC for 16-bit compressed instructions
+ - RVM for multiplication and division instructions
+
+Memory subsystem
+ - I & D local memory
+ - Size: 4KB to 16MB
+ - Memory subsyetem soft-error protection
+ - Protection scheme: parity-checking or error-checking-and-correction (ECC)
+ - Automatic hardware error correction
+
+Bus
+ - Interface Protocol
+ - Synchronous AHB (32-bit/64-bit data-width), or
+ - Synchronous AXI4 (64-bit data-width)
+
+Power management
+ - Wait for interrupt (WFI) mode
+
+Debug
+ - Configurable number of breakpoints: 2/4/8
+ - External Debug Module
+ - AHB slave port
+ - External JTAG debug transport module
+
+Platform Level Interrupt Controller (PLIC)
+ - AHB slave port
+ - Configurable number of interrupts: 1-1023
+ - Configurable number of interrupt priorities: 3/7/15/63/127/255
+ - Configurable number of targets: 1-16
+ - Preempted interrupt priority stack
+
+Configurations
+--------------
+
+CONFIG_SKIP_LOWLEVEL_INIT:
+ If you want to boot this system from SPI ROM and bypass e-bios (the
+ other boot loader on ROM). You should undefine CONFIG_SKIP_LOWLEVEL_INIT
+ in "include/configs/ax25-ae350.h".
+
+Build and boot steps
+--------------------
+
+Build:
+
+1. Prepare the toolchains and make sure the $PATH to toolchains is correct.
+2. Use `make ae350_rv[32|64]_defconfig` in u-boot root to build the image for
+ 32 or 64 bit.
+
+Verification:
+
+1. startup
+2. relocation
+3. timer driver
+4. uart driver
+5. mac driver
+6. mmc driver
+7. spi driver
+
+Steps
+-----
+
+1. Define CONFIG_SKIP_LOWLEVEL_INIT to build u-boot which is loaded via gdb from ram.
+2. Undefine CONFIG_SKIP_LOWLEVEL_INIT to build u-boot which is booted from spi rom.
+3. Ping a server by mac driver
+4. Scan sd card and copy u-boot image which is booted from flash to ram by sd driver.
+5. Burn this u-boot image to spi rom by spi driver
+6. Re-boot u-boot from spi flash with power off and power on.
+
+Messages of U-Boot boot on AE350 board
+--------------------------------------
+
+.. code-block:: none
+
+ U-Boot 2018.01-rc2-00033-g824f89a (Dec 21 2017 - 16:51:26 +0800)
+
+ DRAM: 1 GiB
+ MMC: mmc@f0e00000: 0
+ SF: Detected mx25u1635e with page size 256 Bytes, erase size 4 KiB, total 2 MiB
+ In: serial@f0300000
+ Out: serial@f0300000
+ Err: serial@f0300000
+ Net:
+ Warning: mac@e0100000 (eth0) using random MAC address - be:dd:d7:e4:e8:10
+ eth0: mac@e0100000
+
+ RISC-V # version
+ U-Boot 2018.01-rc2-00033-gb265b91-dirty (Dec 22 2017 - 13:54:21 +0800)
+
+ riscv32-unknown-linux-gnu-gcc (GCC) 7.2.0
+ GNU ld (GNU Binutils) 2.29
+
+ RISC-V # setenv ipaddr 10.0.4.200 ;
+ RISC-V # setenv serverip 10.0.4.97 ;
+ RISC-V # ping 10.0.4.97 ;
+ Using mac@e0100000 device
+ host 10.0.4.97 is alive
+
+ RISC-V # mmc rescan
+ RISC-V # fatls mmc 0:1
+ 318907 u-boot-ae350-64.bin
+ 1252 hello_world_ae350_32.bin
+ 328787 u-boot-ae350-32.bin
+
+ 3 file(s), 0 dir(s)
+
+ RISC-V # sf probe 0:0 50000000 0
+ SF: Detected mx25u1635e with page size 256 Bytes, erase size 4 KiB, total 2 MiB
+
+ RISC-V # sf test 0x100000 0x1000
+ SPI flash test:
+ 0 erase: 36 ticks, 111 KiB/s 0.888 Mbps
+ 1 check: 29 ticks, 137 KiB/s 1.096 Mbps
+ 2 write: 40 ticks, 100 KiB/s 0.800 Mbps
+ 3 read: 20 ticks, 200 KiB/s 1.600 Mbps
+ Test passed
+ 0 erase: 36 ticks, 111 KiB/s 0.888 Mbps
+ 1 check: 29 ticks, 137 KiB/s 1.096 Mbps
+ 2 write: 40 ticks, 100 KiB/s 0.800 Mbps
+ 3 read: 20 ticks, 200 KiB/s 1.600 Mbps
+
+ RISC-V # fatload mmc 0:1 0x600000 u-boot-ae350-32.bin
+ reading u-boot-ae350-32.bin
+ 328787 bytes read in 324 ms (990.2 KiB/s)
+
+ RISC-V # sf erase 0x0 0x51000
+ SF: 331776 bytes @ 0x0 Erased: OK
+
+ RISC-V # sf write 0x600000 0x0 0x50453
+ device 0 offset 0x0, size 0x50453
+ SF: 328787 bytes @ 0x0 Written: OK
+
+ RISC-V # crc32 0x600000 0x50453
+ crc32 for 00600000 ... 00650452 ==> 692dc44a
+
+ RISC-V # crc32 0x80000000 0x50453
+ crc32 for 80000000 ... 80050452 ==> 692dc44a
+ RISC-V #
+
+ *** power-off and power-on, this U-Boot is booted from spi flash ***
+
+ U-Boot 2018.01-rc2-00032-gf67dd47-dirty (Dec 21 2017 - 13:56:03 +0800)
+
+ DRAM: 1 GiB
+ MMC: mmc@f0e00000: 0
+ SF: Detected mx25u1635e with page size 256 Bytes, erase size 4 KiB, total 2 MiB
+ In: serial@f0300000
+ Out: serial@f0300000
+ Err: serial@f0300000
+ Net:
+ Warning: mac@e0100000 (eth0) using random MAC address - ee:4c:58:29:32:f5
+ eth0: mac@e0100000
+ RISC-V #
+
+
+Boot bbl and riscv-linux via U-Boot on QEMU
+-------------------------------------------
+
+1. Build riscv-linux
+2. Build bbl and riscv-linux with --with-payload
+3. Prepare ae350.dtb
+4. Creating OS-kernel images
+
+.. code-block:: none
+
+ ./mkimage -A riscv -O linux -T kernel -C none -a 0x0000 -e 0x0000 -d bbl.bin bootmImage-bbl.bin
+ Image Name:
+ Created: Tue Mar 13 10:06:42 2018
+ Image Type: RISC-V Linux Kernel Image (uncompressed)
+ Data Size: 17901204 Bytes = 17481.64 KiB = 17.07 MiB
+ Load Address: 00000000
+ Entry Point: 00000000
+
+5. Copy bootmImage-bbl.bin and ae350.dtb to qemu sd card image
+6. Message of booting riscv-linux from bbl via u-boot on qemu
+
+.. code-block:: none
+
+ U-Boot 2018.03-rc4-00031-g2631273 (Mar 13 2018 - 15:02:55 +0800)
+
+ DRAM: 1 GiB
+ main-loop: WARNING: I/O thread spun for 1000 iterations
+ MMC: mmc@f0e00000: 0
+ Loading Environment from SPI Flash... *** Warning - spi_flash_probe_bus_cs() failed, using default environment
+
+ Failed (-22)
+ In: serial@f0300000
+ Out: serial@f0300000
+ Err: serial@f0300000
+ Net:
+ Warning: mac@e0100000 (eth0) using random MAC address - 02:00:00:00:00:00
+ eth0: mac@e0100000
+ RISC-V # mmc rescan
+ RISC-V # mmc part
+
+ Partition Map for MMC device 0 -- Partition Type: DOS
+
+ Part Start Sector Num Sectors UUID Type
+ RISC-V # fatls mmc 0:0
+ 17901268 bootmImage-bbl.bin
+ 1954 ae2xx.dtb
+
+ 2 file(s), 0 dir(s)
+
+ RISC-V # fatload mmc 0:0 0x00600000 bootmImage-bbl.bin
+ 17901268 bytes read in 4642 ms (3.7 MiB/s)
+ RISC-V # fatload mmc 0:0 0x2000000 ae350.dtb
+ 1954 bytes read in 1 ms (1.9 MiB/s)
+ RISC-V # setenv bootm_size 0x2000000
+ RISC-V # setenv fdt_high 0x1f00000
+ RISC-V # bootm 0x00600000 - 0x2000000
+ ## Booting kernel from Legacy Image at 00600000 ...
+ Image Name:
+ Image Type: RISC-V Linux Kernel Image (uncompressed)
+ Data Size: 17901204 Bytes = 17.1 MiB
+ Load Address: 00000000
+ Entry Point: 00000000
+ Verifying Checksum ... OK
+ ## Flattened Device Tree blob at 02000000
+ Booting using the fdt blob at 0x2000000
+ Loading Kernel Image ... OK
+ Loading Device Tree to 0000000001efc000, end 0000000001eff7a1 ... OK
+ [ 0.000000] OF: fdt: Ignoring memory range 0x0 - 0x200000
+ [ 0.000000] Linux version 4.14.0-00046-gf3e439f-dirty (rick@atcsqa06) (gcc version 7.1.1 20170509 (GCC)) #1 Tue Jan 9 16:34:25 CST 2018
+ [ 0.000000] bootconsole [early0] enabled
+ [ 0.000000] Initial ramdisk at: 0xffffffe000016a98 (12267008 bytes)
+ [ 0.000000] Zone ranges:
+ [ 0.000000] DMA [mem 0x0000000000200000-0x000000007fffffff]
+ [ 0.000000] Normal empty
+ [ 0.000000] Movable zone start for each node
+ [ 0.000000] Early memory node ranges
+ [ 0.000000] node 0: [mem 0x0000000000200000-0x000000007fffffff]
+ [ 0.000000] Initmem setup node 0 [mem 0x0000000000200000-0x000000007fffffff]
+ [ 0.000000] elf_hwcap is 0x112d
+ [ 0.000000] random: fast init done
+ [ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 516615
+ [ 0.000000] Kernel command line: console=ttyS0,38400n8 earlyprintk=uart8250-32bit,0xf0300000 debug loglevel=7
+ [ 0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
+ [ 0.000000] Dentry cache hash table entries: 262144 (order: 9, 2097152 bytes)
+ [ 0.000000] Inode-cache hash table entries: 131072 (order: 8, 1048576 bytes)
+ [ 0.000000] Sorting __ex_table...
+ [ 0.000000] Memory: 2047832K/2095104K available (1856K kernel code, 204K rwdata, 532K rodata, 12076K init, 756K bss, 47272K reserved, 0K cma-reserved)
+ [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
+ [ 0.000000] NR_IRQS: 0, nr_irqs: 0, preallocated irqs: 0
+ [ 0.000000] riscv,cpu_intc,0: 64 local interrupts mapped
+ [ 0.000000] riscv,plic0,e4000000: mapped 31 interrupts to 1/2 handlers
+ [ 0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x24e6a1710, max_idle_ns: 440795202120 ns
+ [ 0.000000] Calibrating delay loop (skipped), value calculated using timer frequency.. 20.00 BogoMIPS (lpj=40000)
+ [ 0.000000] pid_max: default: 32768 minimum: 301
+ [ 0.004000] Mount-cache hash table entries: 4096 (order: 3, 32768 bytes)
+ [ 0.004000] Mountpoint-cache hash table entries: 4096 (order: 3, 32768 bytes)
+ [ 0.056000] devtmpfs: initialized
+ [ 0.060000] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
+ [ 0.064000] futex hash table entries: 256 (order: 0, 6144 bytes)
+ [ 0.068000] NET: Registered protocol family 16
+ [ 0.080000] vgaarb: loaded
+ [ 0.084000] clocksource: Switched to clocksource riscv_clocksource
+ [ 0.088000] NET: Registered protocol family 2
+ [ 0.092000] TCP established hash table entries: 16384 (order: 5, 131072 bytes)
+ [ 0.096000] TCP bind hash table entries: 16384 (order: 5, 131072 bytes)
+ [ 0.096000] TCP: Hash tables configured (established 16384 bind 16384)
+ [ 0.100000] UDP hash table entries: 1024 (order: 3, 32768 bytes)
+ [ 0.100000] UDP-Lite hash table entries: 1024 (order: 3, 32768 bytes)
+ [ 0.104000] NET: Registered protocol family 1
+ [ 0.616000] Unpacking initramfs...
+ [ 1.220000] workingset: timestamp_bits=62 max_order=19 bucket_order=0
+ [ 1.244000] io scheduler noop registered
+ [ 1.244000] io scheduler cfq registered (default)
+ [ 1.244000] io scheduler mq-deadline registered
+ [ 1.248000] io scheduler kyber registered
+ [ 1.360000] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
+ [ 1.368000] console [ttyS0] disabled
+ [ 1.372000] f0300000.serial: ttyS0 at MMIO 0xf0300020 (irq = 10, base_baud = 1228800) is a 16550A
+ [ 1.392000] console [ttyS0] enabled
+ [ 1.392000] ftmac100: Loading version 0.2 ...
+ [ 1.396000] ftmac100 e0100000.mac eth0: irq 8, mapped at ffffffd002005000
+ [ 1.400000] ftmac100 e0100000.mac eth0: generated random MAC address 6e:ac:c3:92:36:c0
+ [ 1.404000] IR NEC protocol handler initialized
+ [ 1.404000] IR RC5(x/sz) protocol handler initialized
+ [ 1.404000] IR RC6 protocol handler initialized
+ [ 1.404000] IR JVC protocol handler initialized
+ [ 1.408000] IR Sony protocol handler initialized
+ [ 1.408000] IR SANYO protocol handler initialized
+ [ 1.408000] IR Sharp protocol handler initialized
+ [ 1.408000] IR MCE Keyboard/mouse protocol handler initialized
+ [ 1.412000] IR XMP protocol handler initialized
+ [ 1.456000] ftsdc010 f0e00000.mmc: mmc0 - using hw SDIO IRQ
+ [ 1.464000] bootconsole [early0] uses init memory and must be disabled even before the real one is ready
+ [ 1.464000] bootconsole [early0] disabled
+ [ 1.508000] Freeing unused kernel memory: 12076K
+ [ 1.512000] This architecture does not have kernel memory protection.
+ [ 1.520000] mmc0: new SD card at address 4567
+ [ 1.524000] mmcblk0: mmc0:4567 QEMU! 20.0 MiB
+ [ 1.844000] mmcblk0:
+ Wed Dec 1 10:00:00 CST 2010
+ / #
+
+
+TODO
+----
+Boot bbl and riscv-linux via U-Boot on AE350 board
diff --git a/doc/board/atmel/at91ek.rst b/doc/board/atmel/at91ek.rst
new file mode 100644
index 0000000..6185b1d
--- /dev/null
+++ b/doc/board/atmel/at91ek.rst
@@ -0,0 +1,192 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+AT91 Evaluation kits
+====================
+
+Board mapping & boot media
+--------------------------
+
+AT91SAM9260EK, AT91SAM9G20EK & AT91SAM9XEEK
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Memory map::
+
+ 0x20000000 - 23FFFFFF SDRAM (64 MB)
+ 0xC0000000 - Cxxxxxxx Atmel Dataflash card (J13)
+ 0xD0000000 - D07FFFFF Soldered Atmel Dataflash (AT45DB642)
+
+Environment variables
+
+U-Boot environment variables can be stored at different places:
+
+ - Dataflash on SPI chip select 1 (default)
+ - Dataflash on SPI chip select 0 (dataflash card)
+ - Nand flash
+
+You can choose your storage location at config step (here for at91sam9260ek)::
+
+ make at91sam9260ek_nandflash_config - use nand flash
+ make at91sam9260ek_dataflash_cs0_config - use data flash (spi cs0)
+ make at91sam9260ek_dataflash_cs1_config - use data flash (spi cs1)
+
+
+AT91SAM9261EK, AT91SAM9G10EK
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Memory map::
+
+ 0x20000000 - 23FFFFFF SDRAM (64 MB)
+ 0xC0000000 - C07FFFFF Soldered Atmel Dataflash (AT45DB642)
+ 0xD0000000 - Dxxxxxxx Atmel Dataflash card (J22)
+
+Environment variables
+
+U-Boot environment variables can be stored at different places:
+
+ - Dataflash on SPI chip select 0 (default)
+ - Dataflash on SPI chip select 3 (dataflash card)
+ - Nand flash
+
+You can choose your storage location at config step (here for at91sam9260ek)::
+
+ make at91sam9261ek_nandflash_config - use nand flash
+ make at91sam9261ek_dataflash_cs0_config - use data flash (spi cs0)
+ make at91sam9261ek_dataflash_cs3_config - use data flash (spi cs3)
+
+
+AT91SAM9263EK
+^^^^^^^^^^^^^
+
+Memory map::
+
+ 0x20000000 - 23FFFFFF SDRAM (64 MB)
+ 0xC0000000 - Cxxxxxxx Atmel Dataflash card (J9)
+
+Environment variables
+
+U-Boot environment variables can be stored at different places:
+
+ - Dataflash on SPI chip select 0 (dataflash card)
+ - Nand flash
+ - Nor flash (not populate by default)
+
+You can choose your storage location at config step (here for at91sam9260ek)::
+
+ make at91sam9263ek_nandflash_config - use nand flash
+ make at91sam9263ek_dataflash_cs0_config - use data flash (spi cs0)
+ make at91sam9263ek_norflash_config - use nor flash
+
+You can choose to boot directly from U-Boot at config step::
+
+ make at91sam9263ek_norflash_boot_config - boot from nor flash
+
+
+AT91SAM9M10G45EK
+^^^^^^^^^^^^^^^^
+
+Memory map::
+
+ 0x70000000 - 77FFFFFF SDRAM (128 MB)
+
+Environment variables
+
+U-Boot environment variables can be stored at different places:
+
+ - Nand flash
+
+You can choose your storage location at config step (here for at91sam9m10g45ek)::
+
+ make at91sam9m10g45ek_nandflash_config - use nand flash
+
+
+AT91SAM9RLEK
+^^^^^^^^^^^^
+
+Memory map::
+
+ 0x20000000 - 23FFFFFF SDRAM (64 MB)
+ 0xC0000000 - C07FFFFF Soldered Atmel Dataflash (AT45DB642)
+
+Environment variables
+
+U-Boot environment variables can be stored at different places:
+
+ - Dataflash on SPI chip select 0
+ - Nand flash.
+
+You can choose your storage location at config step (here for at91sam9rlek)::
+
+ make at91sam9rlek_nandflash_config - use nand flash
+
+
+AT91SAM9N12EK, AT91SAM9X5EK
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Memory map::
+
+ 0x20000000 - 27FFFFFF SDRAM (128 MB)
+
+Environment variables
+
+U-Boot environment variables can be stored at different places:
+
+ - Nand flash
+ - SD/MMC card
+ - Serialflash/Dataflash on SPI chip select 0
+
+You can choose your storage location at config step (here for at91sam9x5ek)::
+
+ make at91sam9x5ek_dataflash_config - use data flash
+ make at91sam9x5ek_mmc_config - use sd/mmc card
+ make at91sam9x5ek_nandflash_config - use nand flash
+ make at91sam9x5ek_spiflash_config - use serial flash
+
+
+SAMA5D3XEK
+^^^^^^^^^^
+
+Memory map::
+
+ 0x20000000 - 3FFFFFFF SDRAM (512 MB)
+
+Environment variables
+
+U-Boot environment variables can be stored at different places:
+
+ - Nand flash
+ - SD/MMC card
+ - Serialflash on SPI chip select 0
+
+You can choose your storage location at config step (here for sama5d3xek)::
+
+ make sama5d3xek_mmc_config - use SD/MMC card
+ make sama5d3xek_nandflash_config - use nand flash
+ make sama5d3xek_serialflash_config - use serial flash
+
+
+NAND partition table
+--------------------
+
+All the board support boot from NAND flash will use the following NAND
+partition table::
+
+ 0x00000000 - 0x0003FFFF bootstrap (256 KiB)
+ 0x00040000 - 0x000BFFFF u-boot (512 KiB)
+ 0x000C0000 - 0x000FFFFF env (256 KiB)
+ 0x00100000 - 0x0013FFFF env_redundant (256 KiB)
+ 0x00140000 - 0x0017FFFF spare (256 KiB)
+ 0x00180000 - 0x001FFFFF dtb (512 KiB)
+ 0x00200000 - 0x007FFFFF kernel (6 MiB)
+ 0x00800000 - 0xxxxxxxxx rootfs (All left)
+
+
+Watchdog support
+----------------
+
+For security reasons, the at91 watchdog is running at boot time and,
+if deactivated, cannot be used anymore.
+If you want to use the watchdog, you will need to keep it running in
+your code (make sure not to disable it in AT91Bootstrap for instance).
+
+In the U-Boot configuration, the AT91 watchdog support is enabled using
+the CONFIG_WDT and CONFIG_WDT_AT91 options.
diff --git a/doc/board/coreboot/coreboot.rst b/doc/board/coreboot/coreboot.rst
new file mode 100644
index 0000000..fd97422
--- /dev/null
+++ b/doc/board/coreboot/coreboot.rst
@@ -0,0 +1,42 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Bin Meng <bmeng.cn@gmail.com>
+
+Coreboot
+========
+
+Build Instructions for U-Boot as coreboot payload
+-------------------------------------------------
+Building U-Boot as a coreboot payload is just like building U-Boot for targets
+on other architectures, like below::
+
+ $ make coreboot_defconfig
+ $ make all
+
+Test with coreboot
+------------------
+For testing U-Boot as the coreboot payload, there are things that need be paid
+attention to. coreboot supports loading an ELF executable and a 32-bit plain
+binary, as well as other supported payloads. With the default configuration,
+U-Boot is set up to use a separate Device Tree Blob (dtb). As of today, the
+generated u-boot-dtb.bin needs to be packaged by the cbfstool utility (a tool
+provided by coreboot) manually as coreboot's 'make menuconfig' does not provide
+this capability yet. The command is as follows::
+
+ # in the coreboot root directory
+ $ ./build/util/cbfstool/cbfstool build/coreboot.rom add-flat-binary \
+ -f u-boot-dtb.bin -n fallback/payload -c lzma -l 0x1110000 -e 0x1110000
+
+Make sure 0x1110000 matches CONFIG_SYS_TEXT_BASE, which is the symbol address
+of _x86boot_start (in arch/x86/cpu/start.S).
+
+If you want to use ELF as the coreboot payload, change U-Boot configuration to
+use CONFIG_OF_EMBED instead of CONFIG_OF_SEPARATE.
+
+To enable video you must enable these options in coreboot:
+
+ - Set framebuffer graphics resolution (1280x1024 32k-color (1:5:5))
+ - Keep VESA framebuffer
+
+At present it seems that for Minnowboard Max, coreboot does not pass through
+the video information correctly (it always says the resolution is 0x0). This
+works correctly for link though.
diff --git a/doc/board/coreboot/index.rst b/doc/board/coreboot/index.rst
new file mode 100644
index 0000000..d148db9
--- /dev/null
+++ b/doc/board/coreboot/index.rst
@@ -0,0 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Coreboot
+========
+
+.. toctree::
+ :maxdepth: 2
+
+ coreboot
diff --git a/doc/board/emulation/index.rst b/doc/board/emulation/index.rst
new file mode 100644
index 0000000..1adefee
--- /dev/null
+++ b/doc/board/emulation/index.rst
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Emulation
+=========
+
+.. toctree::
+ :maxdepth: 2
+
+ qemu-arm
+ qemu-mips
+ qemu-riscv
+ qemu-x86
diff --git a/doc/README.qemu-arm b/doc/board/emulation/qemu-arm.rst
similarity index 79%
rename from doc/README.qemu-arm
rename to doc/board/emulation/qemu-arm.rst
index e67bc13..ca751d4 100644
--- a/doc/README.qemu-arm
+++ b/doc/board/emulation/qemu-arm.rst
@@ -1,9 +1,8 @@
-# SPDX-License-Identifier: GPL-2.0+
-#
-# Copyright (C) 2017, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (C) 2017, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
-U-Boot on QEMU's 'virt' machine on ARM & AArch64
-================================================
+QEMU ARM
+========
QEMU for ARM supports a special 'virt' machine designed for emulation and
virtualization purposes. This document describes how to run U-Boot under it.
@@ -26,11 +25,13 @@
---------------
Set the CROSS_COMPILE environment variable as usual, and run:
-- For ARM:
+- For ARM::
+
make qemu_arm_defconfig
make
+- For AArch64::
+
-- For AArch64:
make qemu_arm64_defconfig
make
@@ -38,31 +39,44 @@
--------------
The minimal QEMU command line to get U-Boot up and running is:
-- For ARM:
+- For ARM::
+
qemu-system-arm -machine virt -bios u-boot.bin
+- For AArch64::
+
-- For AArch64:
qemu-system-aarch64 -machine virt -cpu cortex-a57 -bios u-boot.bin
Note that for some odd reason qemu-system-aarch64 needs to be explicitly
told to use a 64-bit CPU or it will boot in 32-bit mode.
Additional persistent U-boot environment support can be added as follows:
-- Create envstore.img using qemu-img:
+
+- Create envstore.img using qemu-img::
+
qemu-img create -f raw envstore.img 64M
-- Add a pflash drive parameter to the command line:
+
+- Add a pflash drive parameter to the command line::
+
-drive if=pflash,format=raw,index=1,file=envstore.img
Additional peripherals that have been tested to work in both U-Boot and Linux
can be enabled with the following command line parameters:
-- To add a Serial ATA disk via an Intel ICH9 AHCI controller, pass e.g.:
+- To add a Serial ATA disk via an Intel ICH9 AHCI controller, pass e.g.::
+
-drive if=none,file=disk.img,id=mydisk -device ich9-ahci,id=ahci -device ide-drive,drive=mydisk,bus=ahci.0
-- To add an Intel E1000 network adapter, pass e.g.:
+
+- To add an Intel E1000 network adapter, pass e.g.::
+
-netdev user,id=net0 -device e1000,netdev=net0
-- To add an EHCI-compliant USB host controller, pass e.g.:
+
+- To add an EHCI-compliant USB host controller, pass e.g.::
+
-device usb-ehci,id=ehci
-- To add a NVMe disk, pass e.g.:
+
+- To add a NVMe disk, pass e.g.::
+
-drive if=none,file=disk.img,id=mydisk -device nvme,drive=mydisk,serial=foo
These have been tested in QEMU 2.9.0 but should work in at least 2.5.0 as well.
diff --git a/doc/board/emulation/qemu-mips.rst b/doc/board/emulation/qemu-mips.rst
new file mode 100644
index 0000000..529a908
--- /dev/null
+++ b/doc/board/emulation/qemu-mips.rst
@@ -0,0 +1,234 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Vlad Lungu <vlad.lungu@windriver.com>
+
+QEMU MIPS
+=========
+
+Qemu is a full system emulator. See http://www.nongnu.org/qemu/
+
+Limitations & comments
+----------------------
+Supports the "-M mips" configuration of qemu: serial,NE2000,IDE.
+Supports little and big endian as well as 32 bit and 64 bit.
+Derived from au1x00 with a lot of things cut out.
+
+Supports emulated flash (patch Jean-Christophe PLAGNIOL-VILLARD) with
+recent qemu versions. When using emulated flash, launch with
+-pflash <filename> and erase mips_bios.bin.
+
+
+Notes for the Qemu MIPS port
+----------------------------
+
+Example usage
+^^^^^^^^^^^^^
+
+Using u-boot.bin as ROM (replaces Qemu monitor):
+
+32 bit, big endian::
+
+ # make qemu_mips
+ # qemu-system-mips -M mips -bios u-boot.bin -nographic
+
+32 bit, little endian::
+
+ # make qemu_mipsel
+ # qemu-system-mipsel -M mips -bios u-boot.bin -nographic
+
+64 bit, big endian::
+
+ # make qemu_mips64
+ # qemu-system-mips64 -cpu MIPS64R2-generic -M mips -bios u-boot.bin -nographic
+
+64 bit, little endian::
+
+ # make qemu_mips64el
+ # qemu-system-mips64el -cpu MIPS64R2-generic -M mips -bios u-boot.bin -nographic
+
+or using u-boot.bin from emulated flash:
+
+if you use a qemu version after commit 4224
+
+.. code-block:: none
+
+ create image:
+ # dd of=flash bs=1k count=4k if=/dev/zero
+ # dd of=flash bs=1k conv=notrunc if=u-boot.bin
+ start it (see above):
+ # qemu-system-mips[64][el] [-cpu MIPS64R2-generic] -M mips -pflash flash -nographic
+
+Download kernel + initrd
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+On ftp://ftp.denx.de/pub/contrib/Jean-Christophe_Plagniol-Villard/qemu_mips/
+you can downland::
+
+ #config to build the kernel
+ qemu_mips_defconfig
+ #patch to fix mips interrupt init on 2.6.24.y kernel
+ qemu_mips_kernel.patch
+ initrd.gz
+ vmlinux
+ vmlinux.bin
+ System.map
+
+Generate uImage
+^^^^^^^^^^^^^^^
+
+.. code-block:: none
+
+ # tools/mkimage -A mips -O linux -T kernel -C gzip -a 0x80010000 -e 0x80245650 -n "Linux 2.6.24.y" -d vmlinux.bin.gz uImage
+
+Copy uImage to Flash
+^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: none
+
+ # dd if=uImage bs=1k conv=notrunc seek=224 of=flash
+
+Generate Ide Disk
+^^^^^^^^^^^^^^^^^
+
+.. code-block:: none
+
+ # dd of=ide bs=1k cout=100k if=/dev/zero
+
+ # sfdisk -C 261 -d ide
+ # partition table of ide
+ unit: sectors
+
+ ide1 : start= 63, size= 32067, Id=83
+ ide2 : start= 32130, size= 32130, Id=83
+ ide3 : start= 64260, size= 4128705, Id=83
+ ide4 : start= 0, size= 0, Id= 0
+
+Copy to ide
+^^^^^^^^^^^
+
+.. code-block:: none
+
+ # dd if=uImage bs=512 conv=notrunc seek=63 of=ide
+
+Generate ext2 on part 2 on Copy uImage and initrd.gz
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: none
+
+ # Attached as loop device ide offset = 32130 * 512
+ # losetup -o 16450560 -f ide
+ # Format as ext2 ( arg2 : nb blocks)
+ # mke2fs /dev/loop0 16065
+ # losetup -d /dev/loop0
+ # Mount and copy uImage and initrd.gz to it
+ # mount -o loop,offset=16450560 -t ext2 ide /mnt
+ # mkdir /mnt/boot
+ # cp {initrd.gz,uImage} /mnt/boot/
+ # Umount it
+ # umount /mnt
+
+Set Environment
+^^^^^^^^^^^^^^^
+
+.. code-block:: none
+
+ setenv rd_start 0x80800000
+ setenv rd_size 2663940
+ setenv kernel BFC38000
+ setenv oad_addr 80500000
+ setenv load_addr2 80F00000
+ setenv kernel_flash BFC38000
+ setenv load_addr_hello 80200000
+ setenv bootargs 'root=/dev/ram0 init=/bin/sh'
+ setenv load_rd_ext2 'ide res; ext2load ide 0:2 ${rd_start} /boot/initrd.gz'
+ setenv load_rd_tftp 'tftp ${rd_start} /initrd.gz'
+ setenv load_kernel_hda 'ide res; diskboot ${load_addr} 0:2'
+ setenv load_kernel_ext2 'ide res; ext2load ide 0:2 ${load_addr} /boot/uImage'
+ setenv load_kernel_tftp 'tftp ${load_addr} /qemu_mips/uImage'
+ setenv boot_ext2_ext2 'run load_rd_ext2; run load_kernel_ext2; run addmisc; bootm ${load_addr}'
+ setenv boot_ext2_flash 'run load_rd_ext2; run addmisc; bootm ${kernel_flash}'
+ setenv boot_ext2_hda 'run load_rd_ext2; run load_kernel_hda; run addmisc; bootm ${load_addr}'
+ setenv boot_ext2_tftp 'run load_rd_ext2; run load_kernel_tftp; run addmisc; bootm ${load_addr}'
+ setenv boot_tftp_hda 'run load_rd_tftp; run load_kernel_hda; run addmisc; bootm ${load_addr}'
+ setenv boot_tftp_ext2 'run load_rd_tftp; run load_kernel_ext2; run addmisc; bootm ${load_addr}'
+ setenv boot_tftp_flash 'run load_rd_tftp; run addmisc; bootm ${kernel_flash}'
+ setenv boot_tftp_tftp 'run load_rd_tftp; run load_kernel_tftp; run addmisc; bootm ${load_addr}'
+ setenv load_hello_tftp 'tftp ${load_addr_hello} /examples/hello_world.bin'
+ setenv go_tftp 'run load_hello_tftp; go ${load_addr_hello}'
+ setenv addmisc 'setenv bootargs ${bootargs} console=ttyS0,${baudrate} rd_start=${rd_start} rd_size=${rd_size} ethaddr=${ethaddr}'
+ setenv bootcmd 'run boot_tftp_flash'
+
+Now you can boot from flash, ide, ide+ext2 and tfp::
+
+ # qemu-system-mips -M mips -pflash flash -monitor null -nographic -net nic -net user -tftp `pwd` -hda ide
+
+
+How to debug U-Boot
+-------------------
+
+In order to debug U-Boot you need to start qemu with gdb server support (-s)
+and waiting the connection to start the CPU (-S)
+
+.. code-block:: none
+
+ # qemu-system-mips -S -s -M mips -pflash flash -monitor null -nographic -net nic -net user -tftp `pwd` -hda ide
+
+in an other console you start gdb
+
+Debugging of U-Boot Before Relocation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Before relocation, the addresses in the ELF file can be used without any problems
+by connecting to the gdb server localhost:1234
+
+.. code-block:: none
+
+ # mipsel-unknown-linux-gnu-gdb u-boot
+ GNU gdb 6.6
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ GDB is free software, covered by the GNU General Public License, and you are
+ welcome to change it and/or distribute copies of it under certain conditions.
+ Type "show copying" to see the conditions.
+ There is absolutely no warranty for GDB. Type "show warranty" for details.
+ This GDB was configured as "--host=i486-linux-gnu --target=mipsel-unknown-linux-gnu"...
+ (gdb) target remote localhost:1234
+ Remote debugging using localhost:1234
+ _start () at start.S:64
+ 64 RVECENT(reset,0) /* U-Boot entry point */
+ Current language: auto; currently asm
+ (gdb) b board.c:289
+ Breakpoint 1 at 0xbfc00cc8: file board.c, line 289.
+ (gdb) c
+ Continuing.
+
+ Breakpoint 1, board_init_f (bootflag=<value optimized out>) at board.c:290
+ 290 relocate_code (addr_sp, id, addr);
+ Current language: auto; currently c
+ (gdb) p/x addr
+ $1 = 0x87fa0000
+
+Debugging of U-Boot After Relocation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For debugging U-Boot after relocation we need to know the address to which
+U-Boot relocates itself to 0x87fa0000 by default.
+And replace the symbol table to this offset.
+
+.. code-block:: none
+
+ (gdb) symbol-file
+ Discard symbol table from `/private/u-boot-arm/u-boot'? (y or n) y
+ Error in re-setting breakpoint 1:
+ No symbol table is loaded. Use the "file" command.
+ No symbol file now.
+ (gdb) add-symbol-file u-boot 0x87fa0000
+ add symbol table from file "u-boot" at
+ .text_addr = 0x87fa0000
+ (y or n) y
+ Reading symbols from /private/u-boot-arm/u-boot...done.
+ Breakpoint 1 at 0x87fa0cc8: file board.c, line 289.
+ (gdb) c
+ Continuing.
+
+ Program received signal SIGINT, Interrupt.
+ 0xffffffff87fa0de4 in udelay (usec=<value optimized out>) at time.c:78
+ 78 while ((tmo - read_c0_count()) < 0x7fffffff)
diff --git a/doc/README.qemu-riscv b/doc/board/emulation/qemu-riscv.rst
similarity index 82%
rename from doc/README.qemu-riscv
rename to doc/board/emulation/qemu-riscv.rst
index e2e4804..2148334 100644
--- a/doc/README.qemu-riscv
+++ b/doc/board/emulation/qemu-riscv.rst
@@ -1,9 +1,8 @@
-# SPDX-License-Identifier: GPL-2.0+
-#
-# Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
-U-Boot on QEMU's 'virt' machine on RISC-V
-=========================================
+QEMU RISC-V
+===========
QEMU for RISC-V supports a special 'virt' machine designed for emulation and
virtualization purposes. This document describes how to run U-Boot under it.
@@ -19,11 +18,13 @@
---------------
Set the CROSS_COMPILE environment variable as usual, and run:
-- For 32-bit RISC-V:
+- For 32-bit RISC-V::
+
make qemu-riscv32_defconfig
make
+- For 64-bit RISC-V::
+
-- For 64-bit RISC-V:
make qemu-riscv64_defconfig
make
@@ -31,10 +32,12 @@
--------------
The minimal QEMU command line to get U-Boot up and running is:
-- For 32-bit RISC-V:
+- For 32-bit RISC-V::
+
qemu-system-riscv32 -nographic -machine virt -kernel u-boot
-- For 64-bit RISC-V:
+- For 64-bit RISC-V::
+
qemu-system-riscv64 -nographic -machine virt -kernel u-boot
The commands above create targets with 128MiB memory by default.
diff --git a/doc/board/emulation/qemu-x86.rst b/doc/board/emulation/qemu-x86.rst
new file mode 100644
index 0000000..c2e704a
--- /dev/null
+++ b/doc/board/emulation/qemu-x86.rst
@@ -0,0 +1,101 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Bin Meng <bmeng.cn@gmail.com>
+
+QEMU x86
+========
+
+Build instructions for bare mode
+--------------------------------
+
+To build u-boot.rom for QEMU x86 targets, just simply run::
+
+ $ make qemu-x86_defconfig (for 32-bit)
+ $ make qemu-x86_64_defconfig (for 64-bit)
+ $ make all
+
+Note this default configuration will build a U-Boot for the QEMU x86 i440FX
+board. To build a U-Boot against QEMU x86 Q35 board, you can change the build
+configuration during the 'make menuconfig' process like below::
+
+ Device Tree Control --->
+ ...
+ (qemu-x86_q35) Default Device Tree for DT control
+
+Test with QEMU for bare mode
+----------------------------
+
+QEMU is a fancy emulator that can enable us to test U-Boot without access to
+a real x86 board. Please make sure your QEMU version is 2.3.0 or above test
+U-Boot. To launch QEMU with u-boot.rom, call QEMU as follows::
+
+ $ qemu-system-i386 -nographic -bios path/to/u-boot.rom
+
+This will instantiate an emulated x86 board with i440FX and PIIX chipset. QEMU
+also supports emulating an x86 board with Q35 and ICH9 based chipset, which is
+also supported by U-Boot. To instantiate such a machine, call QEMU with::
+
+ $ qemu-system-i386 -nographic -bios path/to/u-boot.rom -M q35
+
+Note by default QEMU instantiated boards only have 128 MiB system memory. But
+it is enough to have U-Boot boot and function correctly. You can increase the
+system memory by pass '-m' parameter to QEMU if you want more memory::
+
+ $ qemu-system-i386 -nographic -bios path/to/u-boot.rom -m 1024
+
+This creates a board with 1 GiB system memory. Currently U-Boot for QEMU only
+supports 3 GiB maximum system memory and reserves the last 1 GiB address space
+for PCI device memory-mapped I/O and other stuff, so the maximum value of '-m'
+would be 3072.
+
+QEMU emulates a graphic card which U-Boot supports. Removing '-nographic' will
+show QEMU's VGA console window. Note this will disable QEMU's serial output.
+If you want to check both consoles, use '-serial stdio'.
+
+Multicore is also supported by QEMU via '-smp n' where n is the number of cores
+to instantiate. Note, the maximum supported CPU number in QEMU is 255.
+
+The fw_cfg interface in QEMU also provides information about kernel data,
+initrd, command-line arguments and more. U-Boot supports directly accessing
+these informtion from fw_cfg interface, which saves the time of loading them
+from hard disk or network again, through emulated devices. To use it , simply
+providing them in QEMU command line::
+
+ $ qemu-system-i386 -nographic -bios path/to/u-boot.rom -m 1024 \
+ -kernel /path/to/bzImage -append 'root=/dev/ram console=ttyS0' \
+ -initrd /path/to/initrd -smp 8
+
+Note: -initrd and -smp are both optional
+
+Then start QEMU, in U-Boot command line use the following U-Boot command to
+setup kernel::
+
+ => qfw
+ qfw - QEMU firmware interface
+
+ Usage:
+ qfw <command>
+ - list : print firmware(s) currently loaded
+ - cpus : print online cpu number
+ - load <kernel addr> <initrd addr> : load kernel and initrd (if any) and setup for zboot
+
+ => qfw load
+ loading kernel to address 01000000 size 5d9d30 initrd 04000000 size 1b1ab50
+
+Here the kernel (bzImage) is loaded to 01000000 and initrd is to 04000000. Then,
+'zboot' can be used to boot the kernel::
+
+ => zboot 01000000 - 04000000 1b1ab50
+
+To run 64-bit U-Boot, qemu-system-x86_64 should be used instead, e.g.::
+
+ $ qemu-system-x86_64 -nographic -bios path/to/u-boot.rom
+
+A specific CPU can be specified via the '-cpu' parameter but please make
+sure the specified CPU supports 64-bit like '-cpu core2duo'. Conversely
+'-cpu pentium' won't work for obvious reasons that the processor only
+supports 32-bit.
+
+Note 64-bit support is very preliminary at this point. Lots of features
+are missing in the 64-bit world. One notable feature is the VGA console
+support which is currently missing, so that you must specify '-nographic'
+to get 64-bit U-Boot up and running.
diff --git a/doc/board/freescale/b4860qds.rst b/doc/board/freescale/b4860qds.rst
new file mode 100644
index 0000000..37d7d08
--- /dev/null
+++ b/doc/board/freescale/b4860qds.rst
@@ -0,0 +1,453 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+B4860QDS
+========
+
+The B4860QDS is a Freescale reference board that hosts the B4860 SoC
+(and variants).
+
+B4860 Overview
+--------------
+The B4860 QorIQ Qonverge device is a Freescale high-end, multicore SoC based on
+StarCore and Power Architecture® cores. It targets the broadband wireless
+infrastructure and builds upon the proven success of the existing multicore
+DSPs and Power CPUs. It is designed to bolster the rapidly changing and
+expanding wireless markets, such as 3GLTE (FDD and TDD), LTE-Advanced, and UMTS.
+
+The B4860 is a highly-integrated StarCore and Power Architecture processor that
+contains:
+
+* Six fully-programmable StarCore SC3900 FVP subsystems, divided into three
+ clusters-each core runs up to 1.2 GHz, with an architecture highly optimized
+ for wireless base station applications
+* Four dual-thread e6500 Power Architecture processors organized in one
+ cluster-each core runs up to 1.8 GHz
+* Two DDR3/3L controllers for high-speed, industry-standard memory interface
+ each runs at up to 1866.67 MHz
+* MAPLE-B3 hardware acceleration-for forward error correction schemes including
+ Turbo or Viterbi decoding, Turbo encoding and rate matching, MIMO MMSE
+ equalization scheme, matrix operations, CRC insertion and check, DFT/iDFT and
+ FFT/iFFT calculations, PUSCH/PDSCH acceleration, and UMTS chip rate
+ acceleration
+* CoreNet fabric that fully supports coherency using MESI protocol between the
+ e6500 cores, SC3900 FVP cores, memories and external interfaces.
+ CoreNet fabric interconnect runs at 667 MHz and supports coherent and
+ non-coherent out of order transactions with prioritization and bandwidth
+ allocation amongst CoreNet endpoints.
+* Data Path Acceleration Architecture, which includes the following:
+
+ * Frame Manager (FMan), which supports in-line packet parsing and general
+ classification to enable policing and QoS-based packet distribution
+ * Queue Manager (QMan) and Buffer Manager (BMan), which allow offloading
+ of queue management, task management, load distribution, flow ordering,
+ buffer management, and allocation tasks from the cores
+ * Security engine (SEC 5.3)-crypto-acceleration for protocols such as
+ IPsec, SSL, and 802.16
+ * RapidIO manager (RMAN) - Support SRIO types 8, 9, 10, and 11 (inbound
+ and outbound). Supports types 5, 6 (outbound only)
+
+* Large internal cache memory with snooping and stashing capabilities for
+ bandwidth saving and high utilization of processor elements. The 9856-Kbyte
+ internal memory space includes the following:
+
+ * 32 Kbyte L1 ICache per e6500/SC3900 core
+ * 32 Kbyte L1 DCache per e6500/SC3900 core
+ * 2048 Kbyte unified L2 cache for each SC3900 FVP cluster
+ * 2048 Kbyte unified L2 cache for the e6500 cluster
+ * Two 512 Kbyte shared L3 CoreNet platform caches (CPC)
+
+* Sixteen 10-GHz SerDes lanes serving:
+
+ * Two Serial RapidIO interfaces
+ * Each supports up to 4 lanes and a total of up to 8 lanes
+
+* Up to 8-lanes Common Public Radio Interface (CPRI) controller for
+ glue-less antenna connection
+* Two 10-Gbit Ethernet controllers (10GEC)
+* Six 1G/2.5-Gbit Ethernet controllers for network communications
+* PCI Express controller
+* Debug (Aurora)
+* Two OCeaN DMAs
+* Various system peripherals
+* 182 32-bit timers
+
+B4860QDS Overview
+-----------------
+- DDRC1: Ten separate DDR3 parts of 16-bit to support 72-bit (ECC) at 1866MT/s,
+ ECC, 4 GB of memory in two ranks of 2 GB.
+- DDRC2: Five separate DDR3 parts of 16-bit to support 72-bit (ECC) at 1866MT/s,
+ ECC, 2 GB of memory. Single rank.
+- SerDes 1 multiplexing: Two Vitesse (transmit and receive path) cross-point
+ 16x16 switch VSC3316
+- SerDes 2 multiplexing: Two Vitesse (transmit and receive path) cross-point
+ 8x8 switch VSC3308
+- USB 2.0 ULPI PHY USB3315 by SMSC supports USB port in host mode.
+ B4860 UART port is available over USB-to-UART translator USB2SER or over
+ RS232 flat cable.
+- A Vitesse dual SGMII phy VSC8662 links the B4860 SGMII lines to 2xRJ-45
+ copper connectors for Stand-alone mode and to the 1000Base-X over AMC
+ MicroTCA connector ports 0 and 2 for AMC mode.
+- The B4860 configuration may be loaded from nine bits coded reset configuration
+ reset source. The RCW source is set by appropriate DIP-switches.
+- 16-bit NOR Flash / PROMJet
+- QIXIS 8-bit NOR Flash Emulator
+- 8-bit NAND Flash
+- 24-bit SPI Flash
+- Long address I2C EEPROM
+- Available debug interfaces are:
+
+ - On-board eCWTAP controller with ETH and USB I/F
+ - JTAG/COP 16-pin header for any external TAP controller
+ - External JTAG source over AMC to support B2B configuration
+ - 70-pin Aurora debug connector
+
+- QIXIS (FPGA) logic:
+ - 2 KB internal memory space including
+
+- IDT840NT4 clock synthesizer provides B4860 essential clocks : SYSCLK,
+ DDRCLK1,2 and RTCCLK.
+- Two 8T49N222A SerDes ref clock devices support two SerDes port clock
+ frequency - total four refclk, including CPRI clock scheme.
+
+
+B4420 Personality
+-----------------
+
+B4420 is a reduced personality of B4860 with less core/clusters(both SC3900
+and e6500), less DDR controllers, less serdes lanes, less SGMII interfaces
+and reduced target frequencies.
+
+Key differences between B4860 and B4420
+---------------------------------------
+
+B4420 has:
+
+1. Less e6500 cores: 1 cluster with 2 e6500 cores
+2. Less SC3900 cores/clusters: 1 cluster with 2 SC3900 cores per cluster
+3. Single DDRC
+4. 2X 4 lane serdes
+5. 3 SGMII interfaces
+6. no sRIO
+7. no 10G
+
+B4860QDS Default Settings
+-------------------------
+
+Switch Settings
+---------------
+
+.. code-block:: none
+
+ SW1 OFF [0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0]
+ SW2 ON ON ON ON ON ON OFF OFF
+ SW3 OFF OFF OFF ON OFF OFF ON OFF
+ SW5 OFF OFF OFF OFF OFF OFF ON ON
+
+Note:
+
+- PCIe slots modes: All the PCIe devices work as Root Complex.
+- Boot location: NOR flash.
+
+SysClk/Core(e6500)/CCB/DDR/FMan/DDRCLK/StarCore/CPRI-Maple/eTVPE-Maple/ULB-Maple
+66MHz/1.6GHz/667MHz/1.6GHz data rate/667MHz/133MHz/1200MHz/500MHz/800MHz/667MHz
+
+NAND boot::
+
+ SW1 [1.1] = 0
+ SW2 [1.1] = 1
+ SW3 [1:4] = 0001
+
+NOR boot::
+
+ SW1 [1.1] = 1
+ SW2 [1.1] = 0
+ SW3 [1:4] = 1000
+
+B4420QDS Default Settings
+-------------------------
+
+Switch Settings
+---------------
+
+.. code-block:: none
+
+ SW1 OFF[0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0] OFF [0]
+ SW2 ON OFF ON OFF ON ON OFF OFF
+ SW3 OFF OFF OFF ON OFF OFF ON OFF
+ SW5 OFF OFF OFF OFF OFF OFF ON ON
+
+Note:
+
+- PCIe slots modes: All the PCIe devices work as Root Complex.
+- Boot location: NOR flash.
+
+SysClk/Core(e6500)/CCB/DDR/FMan/DDRCLK/StarCore/CPRI-Maple/eTVPE-Maple/ULB-Maple
+66MHz/1.6GHz/667MHz/1.6GHz data rate/667MHz/133MHz/1200MHz/500MHz/800MHz/667MHz
+
+NAND boot::
+
+ SW1 [1.1] = 0
+ SW2 [1.1] = 1
+ SW3 [1:4] = 0001
+
+NOR boot::
+
+ SW1 [1.1] = 1
+ SW2 [1.1] = 0
+ SW3 [1:4] = 1000
+
+Memory map on B4860QDS
+----------------------
+The addresses in brackets are physical addresses.
+
+============= ============= =============== =======
+Start Address End Address Description Size
+============= ============= =============== =======
+0xF_FFDF_1000 0xF_FFFF_FFFF Free 2 MB
+0xF_FFDF_0000 0xF_FFDF_0FFF IFC - FPGA 4 KB
+0xF_FF81_0000 0xF_FFDE_FFFF Free 5 MB
+0xF_FF80_0000 0xF_FF80_FFFF IFC NAND Flash 64 KB
+0xF_FF00_0000 0xF_FF7F_FFFF Free 8 MB
+0xF_FE00_0000 0xF_FEFF_FFFF CCSRBAR 16 MB
+0xF_F801_0000 0xF_FDFF_FFFF Free 95 MB
+0xF_F800_0000 0xF_F800_FFFF PCIe I/O Space 64 KB
+0xF_F600_0000 0xF_F7FF_FFFF QMAN s/w portal 32 MB
+0xF_F400_0000 0xF_F5FF_FFFF BMAN s/w portal 32 MB
+0xF_F000_0000 0xF_F3FF_FFFF Free 64 MB
+0xF_E800_0000 0xF_EFFF_FFFF IFC NOR Flash 128 MB
+0xF_E000_0000 0xF_E7FF_FFFF Promjet 128 MB
+0xF_A0C0_0000 0xF_DFFF_FFFF Free 1012 MB
+0xF_A000_0000 0xF_A0BF_FFFF MAPLE0/1/2 12 MB
+0xF_0040_0000 0xF_9FFF_FFFF Free 12 GB
+0xF_0000_0000 0xF_01FF_FFFF DCSR 32 MB
+0xC_4000_0000 0xE_FFFF_FFFF Free 11 GB
+0xC_3000_0000 0xC_3FFF_FFFF sRIO-2 I/O 256 MB
+0xC_2000_0000 0xC_2FFF_FFFF sRIO-1 I/O 256 MB
+0xC_0000_0000 0xC_1FFF_FFFF PCIe Mem Space 512 MB
+0x1_0000_0000 0xB_FFFF_FFFF Free 44 GB
+0x0_8000_0000 0x0_FFFF_FFFF DDRC1 2 GB
+0x0_0000_0000 0x0_7FFF_FFFF DDRC2 2 GB
+============= ============= =============== =======
+
+Memory map on B4420QDS
+----------------------
+The addresses in brackets are physical addresses.
+
+============= ============= =============== =======
+Start Address End Address Description Size
+============= ============= =============== =======
+0xF_FFDF_1000 0xF_FFFF_FFFF Free 2 MB
+0xF_FFDF_0000 0xF_FFDF_0FFF IFC - FPGA 4 KB
+0xF_FF81_0000 0xF_FFDE_FFFF Free 5 MB
+0xF_FF80_0000 0xF_FF80_FFFF IFC NAND Flash 64 KB
+0xF_FF00_0000 0xF_FF7F_FFFF Free 8 MB
+0xF_FE00_0000 0xF_FEFF_FFFF CCSRBAR 16 MB
+0xF_F801_0000 0xF_FDFF_FFFF Free 95 MB
+0xF_F800_0000 0xF_F800_FFFF PCIe I/O Space 64 KB
+0xF_F600_0000 0xF_F7FF_FFFF QMAN s/w portal 32 MB
+0xF_F400_0000 0xF_F5FF_FFFF BMAN s/w portal 32 MB
+0xF_F000_0000 0xF_F3FF_FFFF Free 64 MB
+0xF_E800_0000 0xF_EFFF_FFFF IFC NOR Flash 128 MB
+0xF_E000_0000 0xF_E7FF_FFFF Promjet 128 MB
+0xF_A0C0_0000 0xF_DFFF_FFFF Free 1012 MB
+0xF_A000_0000 0xF_A0BF_FFFF MAPLE0/1/2 12 MB
+0xF_0040_0000 0xF_9FFF_FFFF Free 12 GB
+0xF_0000_0000 0xF_01FF_FFFF DCSR 32 MB
+0xC_4000_0000 0xE_FFFF_FFFF Free 11 GB
+0xC_3000_0000 0xC_3FFF_FFFF sRIO-2 I/O 256 MB
+0xC_2000_0000 0xC_2FFF_FFFF sRIO-1 I/O 256 MB
+0xC_0000_0000 0xC_1FFF_FFFF PCIe Mem Space 512 MB
+0x1_0000_0000 0xB_FFFF_FFFF Free 44 GB
+0x0_0000_0000 0x0_FFFF_FFFF DDRC1 4 GB
+============= ============= =============== =======
+
+NOR Flash memory Map on B4860 and B4420QDS
+------------------------------------------
+
+============= ============= ============================== =========
+ Start End Definition Size
+============= ============= ============================== =========
+0xEFF40000 0xEFFFFFFF U-Boot (current bank) 768KB
+0xEFF20000 0xEFF3FFFF U-Boot env (current bank) 128KB
+0xEFF00000 0xEFF1FFFF FMAN Ucode (current bank) 128KB
+0xEF300000 0xEFEFFFFF rootfs (alternate bank) 12MB
+0xEE800000 0xEE8FFFFF device tree (alternate bank) 1MB
+0xEE020000 0xEE6FFFFF Linux.uImage (alternate bank) 6MB+896KB
+0xEE000000 0xEE01FFFF RCW (alternate bank) 128KB
+0xEDF40000 0xEDFFFFFF U-Boot (alternate bank) 768KB
+0xEDF20000 0xEDF3FFFF U-Boot env (alternate bank) 128KB
+0xEDF00000 0xEDF1FFFF FMAN ucode (alternate bank) 128KB
+0xED300000 0xEDEFFFFF rootfs (current bank) 12MB
+0xEC800000 0xEC8FFFFF device tree (current bank) 1MB
+0xEC020000 0xEC6FFFFF Linux.uImage (current bank) 6MB+896KB
+0xEC000000 0xEC01FFFF RCW (current bank) 128KB
+============= ============= ============================== =========
+
+Various Software configurations/environment variables/commands
+--------------------------------------------------------------
+The below commands apply to both B4860QDS and B4420QDS.
+
+U-Boot environment variable hwconfig
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The default hwconfig is:
+
+.. code-block:: none
+
+ hwconfig=fsl_ddr:ctlr_intlv=null,bank_intlv=cs0_cs1;usb1:dr_mode=host,phy_type=ulpi
+
+Note: For USB gadget set "dr_mode=peripheral"
+
+FMAN Ucode versions
+^^^^^^^^^^^^^^^^^^^
+
+fsl_fman_ucode_B4860_106_3_6.bin
+
+Switching to alternate bank
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Commands for switching to alternate bank.
+
+1. To change from vbank0 to vbank2
+
+.. code-block:: none
+
+ => qixis_reset altbank (it will boot using vbank2)
+
+2. To change from vbank2 to vbank0
+
+.. code-block:: none
+
+ => qixis reset (it will boot using vbank0)
+
+To change personality of board
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For changing personality from B4860 to B4420
+
+1. Boot from vbank0
+2. Flash vbank2 with b4420 rcw and U-Boot
+3. Give following commands to uboot prompt
+
+.. code-block:: none
+
+ => mw.b ffdf0040 0x30;
+ => mw.b ffdf0010 0x00;
+ => mw.b ffdf0062 0x02;
+ => mw.b ffdf0050 0x02;
+ => mw.b ffdf0010 0x30;
+ => reset
+
+Note:
+
+- Power off cycle will lead to default switch settings.
+- 0xffdf0000 is the address of the QIXIS FPGA.
+
+Switching between NOR and NAND boot(RCW src changed from NOR <-> NAND)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To change from NOR to NAND boot give following command on uboot prompt
+
+.. code-block:: none
+
+ => mw.b ffdf0040 0x30
+ => mw.b ffdf0010 0x00
+ => mw.b 0xffdf0050 0x08
+ => mw.b 0xffdf0060 0x82
+ => mw.b ffdf0061 0x00
+ => mw.b ffdf0010 0x30
+ => reset
+
+To change from NAND to NOR boot give following command on uboot prompt:
+
+.. code-block:: none
+
+ => mw.b ffdf0040 0x30
+ => mw.b ffdf0010 0x00
+ => mw.b 0xffdf0050 0x00(for vbank0) or (mw.b 0xffdf0050 0x02 for vbank2)
+ => mw.b 0xffdf0060 0x12
+ => mw.b ffdf0061 0x01
+ => mw.b ffdf0010 0x30
+ => reset
+
+Note:
+
+- Power off cycle will lead to default switch settings.
+- 0xffdf0000 is the address of the QIXIS FPGA.
+
+Ethernet interfaces for B4860QDS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Serdes protocosl tested:
+* 0x2a, 0x8d (serdes1, serdes2) [DEFAULT]
+* 0x2a, 0xb2 (serdes1, serdes2)
+
+When using [DEFAULT] RCW, which including 2 * 1G SGMII on board and 2 * 1G
+SGMII on SGMII riser card.
+
+Under U-Boot these network interfaces are recognized as::
+
+ FM1@DTSEC3, FM1@DTSEC4, FM1@DTSEC5 and FM1@DTSEC6.
+
+On Linux the interfaces are renamed as::
+
+ eth2 -> fm1-gb2
+ eth3 -> fm1-gb3
+ eth4 -> fm1-gb4
+ eth5 -> fm1-gb5
+
+RCW and Ethernet interfaces for B4420QDS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Serdes protocosl tested:
+* 0x18, 0x9e (serdes1, serdes2)
+
+Under U-Boot these network interfaces are recognized as::
+
+ FM1@DTSEC3, FM1@DTSEC4 and e1000#0.
+
+On Linux the interfaces are renamed as::
+
+ eth2 -> fm1-gb2
+ eth3 -> fm1-gb3
+
+NAND boot with 2 Stage boot loader
+----------------------------------
+PBL initialise the internal SRAM and copy SPL(160KB) in SRAM.
+SPL further initialise DDR using SPD and environment variables and copy
+U-Boot(768 KB) from flash to DDR.
+Finally SPL transer control to U-Boot for futher booting.
+
+SPL has following features:
+ - Executes within 256K
+ - No relocation required
+
+Run time view of SPL framework during boot:
+
++----------------------------------------------+
+|Area | Address |
++----------------------------------------------+
+|Secure boot | 0xFFFC0000 (32KB) |
+|headers | |
++----------------------------------------------+
+|GD, BD | 0xFFFC8000 (4KB) |
++----------------------------------------------+
+|ENV | 0xFFFC9000 (8KB) |
++----------------------------------------------+
+|HEAP | 0xFFFCB000 (30KB) |
++----------------------------------------------+
+|STACK | 0xFFFD8000 (22KB) |
++----------------------------------------------+
+|U-Boot SPL | 0xFFFD8000 (160KB) |
++----------------------------------------------+
+
+NAND Flash memory Map on B4860 and B4420QDS
+-------------------------------------------
+
+============= ============= ============================= =====
+Start End Definition Size
+============= ============= ============================= =====
+0x000000 0x0FFFFF U-Boot 1MB
+0x140000 0x15FFFF U-Boot env 128KB
+0x1A0000 0x1BFFFF FMAN Ucode 128KB
+============= ============= ============================= =====
diff --git a/doc/board/google/chromebook_link.rst b/doc/board/google/chromebook_link.rst
new file mode 100644
index 0000000..1608030
--- /dev/null
+++ b/doc/board/google/chromebook_link.rst
@@ -0,0 +1,34 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Simon Glass <sjg@chromium.org>
+
+Chromebook Link
+===============
+
+First, you need the following binary blobs:
+
+ * descriptor.bin - Intel flash descriptor
+ * me.bin - Intel Management Engine
+ * mrc.bin - Memory Reference Code, which sets up SDRAM
+ * video ROM - sets up the display
+
+You can get these binary blobs by::
+
+ $ git clone http://review.coreboot.org/p/blobs.git
+ $ cd blobs
+
+Find the following files:
+
+ * ./mainboard/google/link/descriptor.bin
+ * ./mainboard/google/link/me.bin
+ * ./northbridge/intel/sandybridge/systemagent-r6.bin
+
+The 3rd one should be renamed to mrc.bin.
+As for the video ROM, you can get it `here`_ and rename it to vga.bin.
+Make sure all these binary blobs are put in the board directory.
+
+Now you can build U-Boot and obtain u-boot.rom::
+
+ $ make chromebook_link_defconfig
+ $ make all
+
+.. _here: http://www.coreboot.org/~stepan/pci8086,0166.rom
diff --git a/doc/board/google/chromebook_samus.rst b/doc/board/google/chromebook_samus.rst
new file mode 100644
index 0000000..eab1128
--- /dev/null
+++ b/doc/board/google/chromebook_samus.rst
@@ -0,0 +1,101 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Simon Glass <sjg@chromium.org>
+
+Chromebook Samus
+================
+
+First, you need the following binary blobs:
+
+ * descriptor.bin - Intel flash descriptor
+ * me.bin - Intel Management Engine
+ * mrc.bin - Memory Reference Code, which sets up SDRAM
+ * refcode.elf - Additional Reference code
+ * vga.bin - video ROM, which sets up the display
+
+If you have a samus you can obtain them from your flash, for example, in
+developer mode on the Chromebook (use Ctrl-Alt-F2 to obtain a terminal and
+log in as 'root')::
+
+ cd /tmp
+ flashrom -w samus.bin
+ scp samus.bin username@ip_address:/path/to/somewhere
+
+If not see the coreboot tree where you can use::
+
+ bash crosfirmware.sh samus
+
+to get the image. There is also an 'extract_blobs.sh' scripts that you can use
+on the 'coreboot-Google_Samus.*' file to short-circuit some of the below.
+
+Then 'ifdtool -x samus.bin' on your development machine will produce::
+
+ flashregion_0_flashdescriptor.bin
+ flashregion_1_bios.bin
+ flashregion_2_intel_me.bin
+
+Rename flashregion_0_flashdescriptor.bin to descriptor.bin
+Rename flashregion_2_intel_me.bin to me.bin
+You can ignore flashregion_1_bios.bin - it is not used.
+
+To get the rest, use 'cbfstool samus.bin print'::
+
+ samus.bin: 8192 kB, bootblocksize 2864, romsize 8388608, offset 0x700000
+ alignment: 64 bytes, architecture: x86
+
+============================ ======== =========== ======
+Name Offset Type Size
+============================ ======== =========== ======
+cmos_layout.bin 0x700000 cmos_layout 1164
+pci8086,0406.rom 0x7004c0 optionrom 65536
+spd.bin 0x710500 (unknown) 4096
+cpu_microcode_blob.bin 0x711540 microcode 70720
+fallback/romstage 0x722a00 stage 54210
+fallback/ramstage 0x72fe00 stage 96382
+config 0x7476c0 raw 6075
+fallback/vboot 0x748ec0 stage 15980
+fallback/refcode 0x74cd80 stage 75578
+fallback/payload 0x75f500 payload 62878
+u-boot.dtb 0x76eb00 (unknown) 5318
+(empty) 0x770000 null 196504
+mrc.bin 0x79ffc0 (unknown) 222876
+(empty) 0x7d66c0 null 167320
+============================ ======== =========== ======
+
+You can extract what you need::
+
+ cbfstool samus.bin extract -n pci8086,0406.rom -f vga.bin
+ cbfstool samus.bin extract -n fallback/refcode -f refcode.rmod
+ cbfstool samus.bin extract -n mrc.bin -f mrc.bin
+ cbfstool samus.bin extract -n fallback/refcode -f refcode.bin -U
+
+Note that the -U flag is only supported by the latest cbfstool. It unpacks
+and decompresses the stage to produce a coreboot rmodule. This is a simple
+representation of an ELF file. You need the patch "Support decoding a stage
+with compression".
+
+Put all 5 files into board/google/chromebook_samus.
+
+Now you can build U-Boot and obtain u-boot.rom::
+
+ $ make chromebook_samus_defconfig
+ $ make all
+
+If you are using em100, then this command will flash write -Boot::
+
+ em100 -s -d filename.rom -c W25Q64CV -r
+
+Flash map for samus / broadwell:
+
+ :fffff800: SYS_X86_START16
+ :ffff0000: RESET_SEG_START
+ :fffd8000: TPL_TEXT_BASE
+ :fffa0000: X86_MRC_ADDR
+ :fff90000: VGA_BIOS_ADDR
+ :ffed0000: SYS_TEXT_BASE
+ :ffea0000: X86_REFCODE_ADDR
+ :ffe70000: SPL_TEXT_BASE
+ :ffbf8000: CONFIG_ENV_OFFSET (environemnt offset)
+ :ffbe0000: rw-mrc-cache (Memory-reference-code cache)
+ :ffa00000: <spare>
+ :ff801000: intel-me (address set by descriptor.bin)
+ :ff800000: intel-descriptor
diff --git a/doc/board/google/index.rst b/doc/board/google/index.rst
new file mode 100644
index 0000000..7f557fe
--- /dev/null
+++ b/doc/board/google/index.rst
@@ -0,0 +1,10 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Google
+======
+
+.. toctree::
+ :maxdepth: 2
+
+ chromebook_link
+ chromebook_samus
diff --git a/doc/board/index.rst b/doc/board/index.rst
new file mode 100644
index 0000000..00e72f5
--- /dev/null
+++ b/doc/board/index.rst
@@ -0,0 +1,18 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Board-specific doc
+==================
+
+.. toctree::
+ :maxdepth: 2
+
+ AndesTech/index
+ atmel/index
+ coreboot/index
+ emulation/index
+ freescale/index
+ google/index
+ intel/index
+ renesas/index
+ sifive/index
+ xilinx/index
diff --git a/doc/board/intel/bayleybay.rst b/doc/board/intel/bayleybay.rst
new file mode 100644
index 0000000..db97f64
--- /dev/null
+++ b/doc/board/intel/bayleybay.rst
@@ -0,0 +1,29 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Bin Meng <bmeng.cn@gmail.com>
+
+Bayley Bay CRB
+==============
+
+This uses as FSP as with Crown Bay, except it is for the Atom E3800 series.
+Download this and get the .fd file (BAYTRAIL_FSP_GOLD_003_16-SEP-2014.fd at
+the time of writing). Put it in the corresponding board directory and rename
+it to fsp.bin.
+
+Obtain the VGA RAM (Vga.dat at the time of writing) and put it into the same
+board directory as vga.bin.
+
+You still need two more binary blobs. For Bayley Bay, they can be extracted
+from the sample SPI image provided in the FSP (SPI.bin at the time of writing)::
+
+ $ ./tools/ifdtool -x BayleyBay/SPI.bin
+ $ cp flashregion_0_flashdescriptor.bin board/intel/bayleybay/descriptor.bin
+ $ cp flashregion_2_intel_me.bin board/intel/bayleybay/me.bin
+
+Now you can build U-Boot and obtain u-boot.rom::
+
+ $ make bayleybay_defconfig
+ $ make all
+
+Note that the debug version of the FSP is bigger in size. If this version
+is used, CONFIG_FSP_ADDR needs to be configured to 0xfffb0000 instead of
+the default value 0xfffc0000.
diff --git a/doc/board/intel/cherryhill.rst b/doc/board/intel/cherryhill.rst
new file mode 100644
index 0000000..151f061
--- /dev/null
+++ b/doc/board/intel/cherryhill.rst
@@ -0,0 +1,30 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Bin Meng <bmeng.cn@gmail.com>
+
+Cherry Hill CRB
+===============
+
+This uses Intel FSP for Braswell platform. Download it from Intel FSP website,
+put the .fd file to the board directory and rename it to fsp.bin.
+
+Extract descriptor.bin and me.bin from the original BIOS on the board using
+ifdtool and put them to the board directory as well.
+
+Note the FSP package for Braswell does not ship a traditional legacy VGA BIOS
+image for the integrated graphics device. Instead a new binary called Video
+BIOS Table (VBT) is shipped. Put it to the board directory and rename it to
+vbt.bin if you want graphics support in U-Boot.
+
+Now you can build U-Boot and obtain u-boot.rom::
+
+ $ make cherryhill_defconfig
+ $ make all
+
+An important note for programming u-boot.rom to the on-board SPI flash is that
+you need make sure the SPI flash's 'quad enable' bit in its status register
+matches the settings in the descriptor.bin, otherwise the board won't boot.
+
+For the on-board SPI flash MX25U6435F, this can be done by writing 0x40 to the
+status register by DediProg in: Config > Modify Status Register > Write Status
+Register(s) > Register1 Value(Hex). This is is a one-time change. Once set, it
+persists in SPI flash part regardless of the u-boot.rom image burned.
diff --git a/doc/board/intel/cougarcanyon2.rst b/doc/board/intel/cougarcanyon2.rst
new file mode 100644
index 0000000..5e3e7a1
--- /dev/null
+++ b/doc/board/intel/cougarcanyon2.rst
@@ -0,0 +1,24 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Bin Meng <bmeng.cn@gmail.com>
+
+Cougar Canyon 2 CRB
+===================
+
+This uses Intel FSP for 3rd generation Intel Core and Intel Celeron processors
+with mobile Intel HM76 and QM77 chipsets platform. Download it from Intel FSP
+website and put the .fd file (CHIEFRIVER_FSP_GOLD_001_09-OCTOBER-2013.fd at the
+time of writing) in the board directory and rename it to fsp.bin.
+
+Now build U-Boot and obtain u-boot.rom::
+
+ $ make cougarcanyon2_defconfig
+ $ make all
+
+The board has two 8MB SPI flashes mounted, which are called SPI-0 and SPI-1 in
+the board manual. The SPI-0 flash should have flash descriptor plus ME firmware
+and SPI-1 flash is used to store U-Boot. For convenience, the complete 8MB SPI-0
+flash image is included in the FSP package (named Rom00_8M_MB_PPT.bin). Program
+this image to the SPI-0 flash according to the board manual just once and we are
+all set. For programming U-Boot we just need to program SPI-1 flash. Since the
+default u-boot.rom image for this board is set to 2MB, it should be programmed
+to the last 2MB of the 8MB chip, address range [600000, 7FFFFF].
diff --git a/doc/board/intel/crownbay.rst b/doc/board/intel/crownbay.rst
new file mode 100644
index 0000000..4fcf981
--- /dev/null
+++ b/doc/board/intel/crownbay.rst
@@ -0,0 +1,43 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Bin Meng <bmeng.cn@gmail.com>
+
+Crown Bay CRB
+=============
+
+U-Boot support of Intel `Crown Bay`_ board relies on a binary blob called
+Firmware Support Package (`FSP`_) to perform all the necessary initialization
+steps as documented in the BIOS Writer Guide, including initialization of the
+CPU, memory controller, chipset and certain bus interfaces.
+
+Download the Intel FSP for Atom E6xx series and Platform Controller Hub EG20T,
+install it on your host and locate the FSP binary blob. Note this platform
+also requires a Chipset Micro Code (CMC) state machine binary to be present in
+the SPI flash where u-boot.rom resides, and this CMC binary blob can be found
+in this FSP package too.
+
+ * ./FSP/QUEENSBAY_FSP_GOLD_001_20-DECEMBER-2013.fd
+ * ./Microcode/C0_22211.BIN
+
+Rename the first one to fsp.bin and second one to cmc.bin and put them in the
+board directory.
+
+Note the FSP release version 001 has a bug which could cause random endless
+loop during the FspInit call. This bug was published by Intel although Intel
+did not describe any details. We need manually apply the patch to the FSP
+binary using any hex editor (eg: bvi). Go to the offset 0x1fcd8 of the FSP
+binary, change the following five bytes values from orginally E8 42 FF FF FF
+to B8 00 80 0B 00.
+
+As for the video ROM, you need manually extract it from the Intel provided
+BIOS for Crown Bay `here`_, using the AMI `MMTool`_. Check PCI option
+ROM ID 8086:4108, extract and save it as vga.bin in the board directory.
+
+Now you can build U-Boot and obtain u-boot.rom::
+
+ $ make crownbay_defconfig
+ $ make all
+
+.. _`Crown Bay`: http://www.intel.com/content/www/us/en/embedded/design-tools/evaluation-platforms/atom-e660-eg20t-development-kit.html
+.. _`FSP`: http://www.intel.com/fsp
+.. _`here`: http://www.intel.com/content/www/us/en/secure/intelligent-systems/privileged/e6xx-35-b1-cmc22211.html
+.. _`MMTool`: http://www.ami.com/products/bios-uefi-tools-and-utilities/bios-uefi-utilities/
diff --git a/doc/board/intel/edison.rst b/doc/board/intel/edison.rst
new file mode 100644
index 0000000..1aee2a1
--- /dev/null
+++ b/doc/board/intel/edison.rst
@@ -0,0 +1,41 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+Edison
+======
+
+Build Instructions for U-Boot as main bootloader
+------------------------------------------------
+
+Simple you can build U-Boot and obtain u-boot.bin::
+
+ $ make edison_defconfig
+ $ make all
+
+Updating U-Boot on Edison
+-------------------------
+
+By default Intel Edison boards are shipped with preinstalled heavily
+patched U-Boot v2014.04. Though it supports DFU which we may be able to
+use.
+
+1. Prepare u-boot.bin as described in chapter above. You still need one
+ more step (if and only if you have original U-Boot), i.e. run the
+ following command::
+
+ $ truncate -s %4096 u-boot.bin
+
+2. Run your board and interrupt booting to U-Boot console. In the console
+ call::
+
+ => run do_force_flash_os
+
+3. Wait for few seconds, it will prepare environment variable and runs
+ DFU. Run DFU command from the host system::
+
+ $ dfu-util -v -d 8087:0a99 --alt u-boot0 -D u-boot.bin
+
+4. Return to U-Boot console and following hint. i.e. push Ctrl+C, and
+ reset the board::
+
+ => reset
diff --git a/doc/board/intel/galileo.rst b/doc/board/intel/galileo.rst
new file mode 100644
index 0000000..f51a06b
--- /dev/null
+++ b/doc/board/intel/galileo.rst
@@ -0,0 +1,22 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Bin Meng <bmeng.cn@gmail.com>
+
+Galileo
+=======
+
+Only one binary blob is needed for Remote Management Unit (RMU) within Intel
+Quark SoC. Not like FSP, U-Boot does not call into the binary. The binary is
+needed by the Quark SoC itself.
+
+You can get the binary blob from Quark Board Support Package from Intel website:
+
+ * ./QuarkSocPkg/QuarkNorthCluster/Binary/QuarkMicrocode/RMU.bin
+
+Rename the file and put it to the board directory by::
+
+ $ cp RMU.bin board/intel/galileo/rmu.bin
+
+Now you can build U-Boot and obtain u-boot.rom::
+
+ $ make galileo_defconfig
+ $ make all
diff --git a/doc/board/intel/index.rst b/doc/board/intel/index.rst
new file mode 100644
index 0000000..f416801
--- /dev/null
+++ b/doc/board/intel/index.rst
@@ -0,0 +1,15 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Intel
+=====
+
+.. toctree::
+ :maxdepth: 2
+
+ bayleybay
+ cherryhill
+ cougarcanyon2
+ crownbay
+ edison
+ galileo
+ minnowmax
diff --git a/doc/board/intel/minnowmax.rst b/doc/board/intel/minnowmax.rst
new file mode 100644
index 0000000..0281217
--- /dev/null
+++ b/doc/board/intel/minnowmax.rst
@@ -0,0 +1,70 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Simon Glass <sjg@chromium.org>
+
+Minnowboard MAX
+===============
+
+This uses as FSP as with Crown Bay, except it is for the Atom E3800 series.
+Download this and get the .fd file (BAYTRAIL_FSP_GOLD_003_16-SEP-2014.fd at
+the time of writing). Put it in the corresponding board directory and rename
+it to fsp.bin.
+
+Obtain the VGA RAM (Vga.dat at the time of writing) and put it into the same
+board directory as vga.bin.
+
+You still need two more binary blobs. For Minnowboard MAX, we can reuse the
+same ME firmware above, but for flash descriptor, we need get that somewhere
+else, as the one above does not seem to work, probably because it is not
+designed for the Minnowboard MAX. Now download the original firmware image
+for this board from:
+
+ * http://firmware.intel.com/sites/default/files/2014-WW42.4-MinnowBoardMax.73-64-bit.bin_Release.zip
+
+Unzip it::
+
+ $ unzip 2014-WW42.4-MinnowBoardMax.73-64-bit.bin_Release.zip
+
+Use ifdtool in the U-Boot tools directory to extract the images from that
+file, for example::
+
+ $ ./tools/ifdtool -x MNW2MAX1.X64.0073.R02.1409160934.bin
+
+This will provide the descriptor file - copy this into the correct place::
+
+ $ cp flashregion_0_flashdescriptor.bin board/intel/minnowmax/descriptor.bin
+
+Now you can build U-Boot and obtain u-boot.rom::
+
+ $ make minnowmax_defconfig
+ $ make all
+
+Checksums are as follows (but note that newer versions will invalidate this)::
+
+ $ md5sum -b board/intel/minnowmax/*.bin
+ ffda9a3b94df5b74323afb328d51e6b4 board/intel/minnowmax/descriptor.bin
+ 69f65b9a580246291d20d08cbef9d7c5 board/intel/minnowmax/fsp.bin
+ 894a97d371544ec21de9c3e8e1716c4b board/intel/minnowmax/me.bin
+ a2588537da387da592a27219d56e9962 board/intel/minnowmax/vga.bin
+
+The ROM image is broken up into these parts:
+
+====== ================== ============================
+Offset Description Controlling config
+====== ================== ============================
+000000 descriptor.bin Hard-coded to 0 in ifdtool
+001000 me.bin Set by the descriptor
+500000 <spare>
+6ef000 Environment CONFIG_ENV_OFFSET
+6f0000 MRC cache CONFIG_ENABLE_MRC_CACHE
+700000 u-boot-dtb.bin CONFIG_SYS_TEXT_BASE
+7b0000 vga.bin CONFIG_VGA_BIOS_ADDR
+7c0000 fsp.bin CONFIG_FSP_ADDR
+7f8000 <spare> (depends on size of fsp.bin)
+7ff800 U-Boot 16-bit boot CONFIG_SYS_X86_START16
+====== ================== ============================
+
+Overall ROM image size is controlled by CONFIG_ROM_SIZE.
+
+Note that the debug version of the FSP is bigger in size. If this version
+is used, CONFIG_FSP_ADDR needs to be configured to 0xfffb0000 instead of
+the default value 0xfffc0000.
diff --git a/doc/board/renesas/sh7752evb.rst b/doc/board/renesas/sh7752evb.rst
new file mode 100644
index 0000000..272d6dd
--- /dev/null
+++ b/doc/board/renesas/sh7752evb.rst
@@ -0,0 +1,79 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+R0P7752C00000RZ board
+=====================
+
+This board specification
+------------------------
+
+The R0P7752C00000RZ(board config name:sh7752evb) has the following device:
+
+ - SH7752 (SH-4A)
+ - DDR3-SDRAM 512MB
+ - SPI ROM 8MB
+ - Gigabit Ethernet controllers
+ - eMMC 4GB
+
+
+Configuration for This board
+----------------------------
+
+You can select the configuration as follows:
+
+ - make sh7752evb_config
+
+
+This board specific command
+---------------------------
+
+This board has the following its specific command:
+
+write_mac:
+ You can write MAC address to SPI ROM.
+
+Usage 1: Write MAC address
+
+.. code-block:: none
+
+ write_mac [GETHERC ch0] [GETHERC ch1]
+
+ For example:
+ => write_mac 74:90:50:00:33:9e 74:90:50:00:33:9f
+
+* We have to input the command as a single line (without carriage return)
+* We have to reset after input the command.
+
+Usage 2: Show current data
+
+.. code-block:: none
+
+ write_mac
+
+ For example:
+ => write_mac
+ GETHERC ch0 = 74:90:50:00:33:9e
+ GETHERC ch1 = 74:90:50:00:33:9f
+
+
+Update SPI ROM
+--------------
+
+1. Copy u-boot image to RAM area.
+2. Probe SPI device.
+
+.. code-block:: none
+
+ => sf probe 0
+ SF: Detected MX25L6405D with page size 64KiB, total 8 MiB
+
+3. Erase SPI ROM.
+
+.. code-block:: none
+
+ => sf erase 0 80000
+
+4. Write u-boot image to SPI ROM.
+
+.. code-block:: none
+
+ => sf write 0x48000000 0 80000
diff --git a/doc/board/renesas/sh7753evb.rst b/doc/board/renesas/sh7753evb.rst
new file mode 100644
index 0000000..c62a824
--- /dev/null
+++ b/doc/board/renesas/sh7753evb.rst
@@ -0,0 +1,79 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+SH7753 EVB board
+================
+
+This board specification
+------------------------
+
+The SH7753 EVB (board config name:sh7753evb) has the following device:
+
+ - SH7753 (SH-4A)
+ - DDR3-SDRAM 512MB
+ - SPI ROM 8MB
+ - Gigabit Ethernet controllers
+ - eMMC 4GB
+
+
+Configuration for This board
+----------------------------
+
+You can select the configuration as follows:
+
+ - make sh7753evb_config
+
+
+This board specific command
+---------------------------
+
+This board has the following its specific command:
+
+write_mac:
+ You can write MAC address to SPI ROM.
+
+Usage 1: Write MAC address
+
+.. code-block:: none
+
+ write_mac [GETHERC ch0] [GETHERC ch1]
+
+ For example:
+ => write_mac 74:90:50:00:33:9e 74:90:50:00:33:9f
+
+* We have to input the command as a single line (without carriage return)
+* We have to reset after input the command.
+
+Usage 2: Show current data
+
+.. code-block:: none
+
+ write_mac
+
+ For example:
+ => write_mac
+ GETHERC ch0 = 74:90:50:00:33:9e
+ GETHERC ch1 = 74:90:50:00:33:9f
+
+
+Update SPI ROM
+--------------
+
+1. Copy u-boot image to RAM area.
+2. Probe SPI device.
+
+.. code-block:: none
+
+ => sf probe 0
+ SF: Detected MX25L6405D with page size 64KiB, total 8 MiB
+
+3. Erase SPI ROM.
+
+.. code-block:: none
+
+ => sf erase 0 80000
+
+4. Write u-boot image to SPI ROM.
+
+.. code-block:: none
+
+ => sf write 0x48000000 0 80000
diff --git a/doc/board/sifive/fu540.rst b/doc/board/sifive/fu540.rst
new file mode 100644
index 0000000..594f1fe
--- /dev/null
+++ b/doc/board/sifive/fu540.rst
@@ -0,0 +1,320 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+HiFive Unleashed
+================
+
+FU540-C000 RISC-V SoC
+---------------------
+The FU540-C000 is the world’s first 4+1 64-bit RISC-V SoC from SiFive.
+
+The HiFive Unleashed development platform is based on FU540-C000 and capable
+of running Linux.
+
+Mainline support
+----------------
+The support for following drivers are already enabled:
+
+1. SiFive UART Driver.
+2. SiFive PRCI Driver for clock.
+3. Cadence MACB ethernet driver for networking support.
+
+TODO:
+
+1. U-Boot expects the serial console device entry to be present under /chosen
+ DT node. Without a serial console U-Boot will panic. Example:
+
+.. code-block:: none
+
+ chosen {
+ stdout-path = "/soc/serial@10010000:115200";
+ };
+
+Building
+--------
+
+1. Add the RISC-V toolchain to your PATH.
+2. Setup ARCH & cross compilation enviornment variable:
+
+.. code-block:: none
+
+ export ARCH=riscv
+ export CROSS_COMPILE=<riscv64 toolchain prefix>
+
+3. make sifive_fu540_defconfig
+4. make
+
+Flashing
+--------
+
+The current U-Boot port is supported in S-mode only and loaded from DRAM.
+
+A prior stage (M-mode) firmware/bootloader (e.g OpenSBI or BBL) is required to
+load the u-boot.bin into memory and provide runtime services. The u-boot.bin
+can be given as a payload to the prior stage (M-mode) firmware/bootloader.
+
+The description of steps required to build the firmware is beyond the scope of
+this document. Please refer OpenSBI or BBL documenation.
+(Note: OpenSBI git repo is at https://github.com/riscv/opensbi.git)
+(Note: BBL git repo is at https://github.com/riscv/riscv-pk.git)
+
+Once the prior stage firmware/bootloader binary is generated, it should be
+copied to the first partition of the sdcard.
+
+.. code-block:: none
+
+ sudo dd if=<prior_stage_firmware_binary> of=/dev/disk2s1 bs=1024
+
+Booting
+-------
+Once you plugin the sdcard and power up, you should see the U-Boot prompt.
+
+Sample boot log from HiFive Unleashed board
+-------------------------------------------
+
+.. code-block:: none
+
+ U-Boot 2019.01-00019-gc7953536-dirty (Jan 22 2019 - 11:05:40 -0800)
+
+ CPU: rv64imafdc
+ Model: sifive,hifive-unleashed-a00
+ DRAM: 8 GiB
+ In: serial@10010000
+ Out: serial@10010000
+ Err: serial@10010000
+ Net:
+ Warning: ethernet@10090000 (eth0) using random MAC address - b6:75:4d:48:50:94
+ eth0: ethernet@10090000
+ Hit any key to stop autoboot: 0
+ => version
+ U-Boot 2019.01-00019-gc7953536-dirty (Jan 22 2019 - 11:05:40 -0800)
+
+ riscv64-linux-gcc.br_real (Buildroot 2018.11-rc2-00003-ga0787e9) 8.2.0
+ GNU ld (GNU Binutils) 2.31.1
+
+Now you can configure your networking, tftp server and use tftp boot method to
+load uImage.
+
+.. code-block:: none
+
+ => setenv ethaddr 70:B3:D5:92:F0:C2
+ => setenv ipaddr 10.196.157.189
+ => setenv serverip 10.11.143.218
+ => setenv gatewayip 10.196.156.1
+ => setenv netmask 255.255.252.0
+ => bdinfo
+ boot_params = 0x0000000000000000
+ DRAM bank = 0x0000000000000000
+ -> start = 0x0000000080000000
+ -> size = 0x0000000200000000
+ relocaddr = 0x00000000fff90000
+ reloc off = 0x000000007fd90000
+ ethaddr = 70:B3:D5:92:F0:C2
+ IP addr = 10.196.157.189
+ baudrate = 115200 bps
+ => tftpboot uImage
+ ethernet@10090000: PHY present at 0
+ ethernet@10090000: Starting autonegotiation...
+ ethernet@10090000: Autonegotiation complete
+ ethernet@10090000: link up, 1000Mbps full-duplex (lpa: 0x3800)
+ Using ethernet@10090000 device
+ TFTP from server 10.11.143.218; our IP address is 10.196.157.189; sending through gateway 10.196.156.1
+ Filename 'uImage'.
+ Load address: 0x80200000
+ Loading: #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ #################################################################
+ ##########################################################
+ 2.5 MiB/s
+ done
+ Bytes transferred = 14939132 (e3f3fc hex)
+ => bootm 0x80200000 - 0x82200000
+ ## Booting kernel from Legacy Image at 80200000 ...
+ Image Name: Linux
+ Image Type: RISC-V Linux Kernel Image (uncompressed)
+ Data Size: 14939068 Bytes = 14.2 MiB
+ Load Address: 80200000
+ Entry Point: 80200000
+ Verifying Checksum ... OK
+ ## Flattened Device Tree blob at 82200000
+ Booting using the fdt blob at 0x82200000
+ Loading Kernel Image ... OK
+ Using Device Tree in place at 0000000082200000, end 0000000082205c69
+
+ Starting kernel ...
+
+ [ 0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
+ [ 0.000000] Linux version 5.0.0-rc1-00020-g4b51f736 (atish@jedi-01) (gcc version 7.2.0 (GCC)) #262 SMP Mon Jan 21 17:39:27 PST 2019
+ [ 0.000000] initrd not found or empty - disabling initrd
+ [ 0.000000] Zone ranges:
+ [ 0.000000] DMA32 [mem 0x0000000080200000-0x00000000ffffffff]
+ [ 0.000000] Normal [mem 0x0000000100000000-0x000027ffffffffff]
+ [ 0.000000] Movable zone start for each node
+ [ 0.000000] Early memory node ranges
+ [ 0.000000] node 0: [mem 0x0000000080200000-0x000000027fffffff]
+ [ 0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x000000027fffffff]
+ [ 0.000000] software IO TLB: mapped [mem 0xfbfff000-0xfffff000] (64MB)
+ [ 0.000000] CPU with hartid=0 has a non-okay status of "masked"
+ [ 0.000000] CPU with hartid=0 has a non-okay status of "masked"
+ [ 0.000000] elf_hwcap is 0x112d
+ [ 0.000000] percpu: Embedded 15 pages/cpu @(____ptrval____) s29720 r0 d31720 u61440
+ [ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 2067975
+ [ 0.000000] Kernel command line: earlyprintk
+ [ 0.000000] Dentry cache hash table entries: 1048576 (order: 11, 8388608 bytes)
+ [ 0.000000] Inode-cache hash table entries: 524288 (order: 10, 4194304 bytes)
+ [ 0.000000] Sorting __ex_table...
+ [ 0.000000] Memory: 8178760K/8386560K available (3309K kernel code, 248K rwdata, 872K rodata, 9381K init, 763K bss, 207800K reserved, 0K cma-reserved)
+ [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
+ [ 0.000000] rcu: Hierarchical RCU implementation.
+ [ 0.000000] rcu: RCU event tracing is enabled.
+ [ 0.000000] rcu: RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
+ [ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
+ [ 0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
+ [ 0.000000] NR_IRQS: 0, nr_irqs: 0, preallocated irqs: 0
+ [ 0.000000] plic: mapped 53 interrupts to 4 (out of 9) handlers.
+ [ 0.000000] riscv_timer_init_dt: Registering clocksource cpuid [0] hartid [1]
+ [ 0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x1d854df40, max_idle_ns: 3526361616960 ns
+ [ 0.000008] sched_clock: 64 bits at 1000kHz, resolution 1000ns, wraps every 2199023255500ns
+ [ 0.000221] Console: colour dummy device 80x25
+ [ 0.000902] printk: console [tty0] enabled
+ [ 0.000963] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.00 BogoMIPS (lpj=10000)
+ [ 0.001034] pid_max: default: 32768 minimum: 301
+ [ 0.001541] Mount-cache hash table entries: 16384 (order: 5, 131072 bytes)
+ [ 0.001912] Mountpoint-cache hash table entries: 16384 (order: 5, 131072 bytes)
+ [ 0.003542] rcu: Hierarchical SRCU implementation.
+ [ 0.004347] smp: Bringing up secondary CPUs ...
+ [ 1.040259] CPU1: failed to come online
+ [ 2.080483] CPU2: failed to come online
+ [ 3.120699] CPU3: failed to come online
+ [ 3.120765] smp: Brought up 1 node, 1 CPU
+ [ 3.121923] devtmpfs: initialized
+ [ 3.124649] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
+ [ 3.124727] futex hash table entries: 1024 (order: 4, 65536 bytes)
+ [ 3.125346] random: get_random_u32 called from bucket_table_alloc+0x72/0x172 with crng_init=0
+ [ 3.125578] NET: Registered protocol family 16
+ [ 3.126400] sifive-u54-prci 10000000.prci: Registered U54 core clocks
+ [ 3.126649] sifive-gemgxl-mgmt 100a0000.cadence-gemgxl-mgmt: Registered clock switch 'cadence-gemgxl-mgmt'
+ [ 3.135572] vgaarb: loaded
+ [ 3.135858] SCSI subsystem initialized
+ [ 3.136193] usbcore: registered new interface driver usbfs
+ [ 3.136266] usbcore: registered new interface driver hub
+ [ 3.136348] usbcore: registered new device driver usb
+ [ 3.136446] pps_core: LinuxPPS API ver. 1 registered
+ [ 3.136484] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
+ [ 3.136575] PTP clock support registered
+ [ 3.137256] clocksource: Switched to clocksource riscv_clocksource
+ [ 3.142711] NET: Registered protocol family 2
+ [ 3.143322] tcp_listen_portaddr_hash hash table entries: 4096 (order: 4, 65536 bytes)
+ [ 3.143634] TCP established hash table entries: 65536 (order: 7, 524288 bytes)
+ [ 3.145799] TCP bind hash table entries: 65536 (order: 8, 1048576 bytes)
+ [ 3.149121] TCP: Hash tables configured (established 65536 bind 65536)
+ [ 3.149591] UDP hash table entries: 4096 (order: 5, 131072 bytes)
+ [ 3.150094] UDP-Lite hash table entries: 4096 (order: 5, 131072 bytes)
+ [ 3.150781] NET: Registered protocol family 1
+ [ 3.230693] workingset: timestamp_bits=62 max_order=21 bucket_order=0
+ [ 3.241224] io scheduler mq-deadline registered
+ [ 3.241269] io scheduler kyber registered
+ [ 3.242143] sifive_gpio 10060000.gpio: SiFive GPIO chip registered 16 GPIOs
+ [ 3.242357] pwm-sifivem 10020000.pwm: Unable to find controller clock
+ [ 3.242439] pwm-sifivem 10021000.pwm: Unable to find controller clock
+ [ 3.243228] xilinx-pcie 2000000000.pci: PCIe Link is DOWN
+ [ 3.243289] xilinx-pcie 2000000000.pci: host bridge /soc/pci@2000000000 ranges:
+ [ 3.243360] xilinx-pcie 2000000000.pci: No bus range found for /soc/pci@2000000000, using [bus 00-ff]
+ [ 3.243447] xilinx-pcie 2000000000.pci: MEM 0x40000000..0x5fffffff -> 0x40000000
+ [ 3.243591] xilinx-pcie 2000000000.pci: PCI host bridge to bus 0000:00
+ [ 3.243636] pci_bus 0000:00: root bus resource [bus 00-ff]
+ [ 3.243676] pci_bus 0000:00: root bus resource [mem 0x40000000-0x5fffffff]
+ [ 3.276547] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
+ [ 3.277689] 10010000.serial: ttySIF0 at MMIO 0x10010000 (irq = 39, base_baud = 0) is a SiFive UART v0
+ [ 3.786963] printk: console [ttySIF0] enabled
+ [ 3.791504] 10011000.serial: ttySIF1 at MMIO 0x10011000 (irq = 40, base_baud = 0) is a SiFive UART v0
+ [ 3.801251] sifive_spi 10040000.spi: mapped; irq=41, cs=1
+ [ 3.806362] m25p80 spi0.0: unrecognized JEDEC id bytes: 9d, 70, 19
+ [ 3.812084] m25p80: probe of spi0.0 failed with error -2
+ [ 3.817453] sifive_spi 10041000.spi: mapped; irq=42, cs=4
+ [ 3.823027] sifive_spi 10050000.spi: mapped; irq=43, cs=1
+ [ 3.828604] libphy: Fixed MDIO Bus: probed
+ [ 3.832623] macb: GEM doesn't support hardware ptp.
+ [ 3.837196] libphy: MACB_mii_bus: probed
+ [ 4.041156] Microsemi VSC8541 SyncE 10090000.ethernet-ffffffff:00: attached PHY driver [Microsemi VSC8541 SyncE] (mii_bus:phy_addr=10090000.ethernet-ffffffff:00, irq=POLL)
+ [ 4.055779] macb 10090000.ethernet eth0: Cadence GEM rev 0x10070109 at 0x10090000 irq 12 (70:b3:d5:92:f0:c2)
+ [ 4.065780] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
+ [ 4.072033] ehci-pci: EHCI PCI platform driver
+ [ 4.076521] usbcore: registered new interface driver usb-storage
+ [ 4.082843] softdog: initialized. soft_noboot=0 soft_margin=60 sec soft_panic=0 (nowayout=0)
+ [ 4.127465] mmc_spi spi2.0: SD/MMC host mmc0, no DMA, no WP, no poweroff
+ [ 4.133645] usbcore: registered new interface driver usbhid
+ [ 4.138980] usbhid: USB HID core driver
+ [ 4.143017] NET: Registered protocol family 17
+ [ 4.147885] pwm-sifivem 10020000.pwm: SiFive PWM chip registered 4 PWMs
+ [ 4.153945] pwm-sifivem 10021000.pwm: SiFive PWM chip registered 4 PWMs
+ [ 4.186407] Freeing unused kernel memory: 9380K
+ [ 4.190224] This architecture does not have kernel memory protection.
+ [ 4.196609] Run /init as init process
+ Starting logging: OK
+ Starting mdev...
+ [ 4.303785] mmc0: host does not support reading read-only switch, assuming write-enable
+ [ 4.311109] mmc0: new SDHC card on SPI
+ [ 4.317103] mmcblk0: mmc0:0000 SS08G 7.40 GiB
+ [ 4.386471] mmcblk0: p1 p2
+ sort: /sys/devices/platform/Fixed: No such file or directory
+ modprobe: can't change directory to '/lib/modules': No such file or directory
+ Initializing random[ 4.759075] random: dd: uninitialized urandom read (512 bytes read)
+ number generator... done.
+ Starting network...
+ udhcpc (v1.24.2) started
+ Sending discover...
+ Sending discover...
+ [ 7.927510] macb 10090000.ethernet eth0: link up (1000/Full)
+ Sending discover...
+ Sending select for 10.196.157.190...
+ Lease of 10.196.157.190 obtained, lease time 499743
+ deleting routers
+ adding dns 10.86.1.1
+ adding dns 10.86.2.1
+ /etc/init.d/S50dropbear
+ Starting dropbear sshd: [ 12.772393] random: dropbear: uninitialized urandom read (32 bytes read)
+ OK
+
+ Welcome to Buildroot
+ buildroot login:
diff --git a/doc/board/xilinx/zynq.rst b/doc/board/xilinx/zynq.rst
new file mode 100644
index 0000000..3f0513e
--- /dev/null
+++ b/doc/board/xilinx/zynq.rst
@@ -0,0 +1,95 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. (C) Copyright 2013 Xilinx, Inc.
+
+ZYNQ
+====
+
+About this
+----------
+
+This document describes the information about Xilinx Zynq U-Boot -
+like supported boards, ML status and TODO list.
+
+Zynq boards
+-----------
+
+Xilinx Zynq-7000 All Programmable SoCs enable extensive system level
+differentiation, integration, and flexibility through hardware, software,
+and I/O programmability.
+
+* zc702 (single qspi, gem0, mmc) [1]
+* zc706 (dual parallel qspi, gem0, mmc) [2]
+* zed (single qspi, gem0, mmc) [3]
+* microzed (single qspi, gem0, mmc) [4]
+* zc770
+ - zc770-xm010 (single qspi, gem0, mmc)
+ - zc770-xm011 (8 or 16 bit nand)
+ - zc770-xm012 (nor)
+ - zc770-xm013 (dual parallel qspi, gem1)
+
+Building
+--------
+
+configure and build for zc702 board::
+
+ $ make zynq_zc702_config
+ $ make
+
+Bootmode
+--------
+
+Zynq has a facility to read the bootmode from the slcr bootmode register
+once user is setting through jumpers on the board - see page no:1546 on [5]
+
+All possible bootmode values are defined in Table 6-2:Boot_Mode MIO Pins
+on [5].
+
+board_late_init() will read the bootmode values using slcr bootmode register
+at runtime and assign the modeboot variable to specific bootmode string which
+is intern used in autoboot.
+
+SLCR bootmode register Bit[3:0] values
+
+.. code-block:: c
+
+ #define ZYNQ_BM_NOR 0x02
+ #define ZYNQ_BM_SD 0x05
+ #define ZYNQ_BM_JTAG 0x0
+
+"modeboot" variable can assign any of "norboot", "sdboot" or "jtagboot"
+bootmode strings at runtime.
+
+Mainline status
+---------------
+
+- Added basic board configurations support.
+- Added zynq u-boot bsp code - arch/arm/cpu/armv7/zynq
+- Added zynq boards named - zc70x, zed, microzed, zc770_xm010/xm011/xm012/xm013
+- Added zynq drivers:
+
+ :serial: drivers/serial/serial_zynq.c
+ :net: drivers/net/zynq_gem.c
+ :mmc: drivers/mmc/zynq_sdhci.c
+ :spi: drivers/spi/zynq_spi.c
+ :qspi: drivers/spi/zynq_qspi.c
+ :i2c: drivers/i2c/zynq_i2c.c
+ :nand: drivers/mtd/nand/raw/zynq_nand.c
+
+- Done proper cleanups on board configurations
+- Added basic FDT support for zynq boards
+- d-cache support for zynq_gem.c
+
+TODO
+----
+
+Add FDT support on individual drivers
+
+* [1] http://www.xilinx.com/products/boards-and-kits/EK-Z7-ZC702-G.htm
+* [2] http://www.xilinx.com/products/boards-and-kits/EK-Z7-ZC706-G.htm
+* [3] http://zedboard.org/product/zedboard
+* [4] http://zedboard.org/product/microzed
+* [5] http://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf
+
+
+.. Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
+.. Sun Dec 15 14:52:41 IST 2013
diff --git a/doc/conf.py b/doc/conf.py
index 168c313..0772fb6 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -170,7 +170,7 @@
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+html_logo = '../tools/logos/u-boot_logo.svg'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
diff --git a/doc/device-tree-bindings/net/fsl-tsec-phy.txt b/doc/device-tree-bindings/net/fsl-tsec-phy.txt
index c5bf48c..59989e3 100644
--- a/doc/device-tree-bindings/net/fsl-tsec-phy.txt
+++ b/doc/device-tree-bindings/net/fsl-tsec-phy.txt
@@ -28,13 +28,13 @@
Required properties:
- compatible : Should define the compatible device type for the
- mdio. Currently supported string/device is "fsl,tsec-mdio".
+ mdio. Currently supported string/device is "fsl,etsec2-mdio".
- reg : Offset and length of the register set for the device
Example:
mdio@24520 {
- compatible = "fsl,tsec-mdio";
+ compatible = "fsl,etsec2-mdio";
reg = <0x24520 0x20>;
ethernet-phy@0 {
diff --git a/doc/device-tree-bindings/net/mdio-mux-reg.txt b/doc/device-tree-bindings/net/mdio-mux-reg.txt
new file mode 100644
index 0000000..0ac34dc
--- /dev/null
+++ b/doc/device-tree-bindings/net/mdio-mux-reg.txt
@@ -0,0 +1,82 @@
+Device tree structures used by register based MDIO muxes is described here.
+This binding is based on reg-mux.txt binding in Linux and is currently used by
+mdio-mux-i2creg driver in U-Boot.
+
+Required properties:
+#mux-control-cells = <1> indicates how many registers are used for mux
+ selection. mux-reg-mask property described below must
+ include this number of pairs.
+mux-reg-masks = <reg mask> describes pairs of register offset and register mask.
+ Register bits enabled in mask are set to the selection
+ value defined in reg property of child MDIOs to control
+ selection.
+Properties described in mdio-mux.txt also apply.
+
+Example structure, used on Freescale LS1028A QDS board:
+
+&i2c0 {
+ status = "okay";
+ u-boot,dm-pre-reloc;
+
+ fpga@66 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "simple-mfd";
+ reg = <0x66>;
+
+ mux-mdio@54 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "mdio-mux-i2creg";
+ reg = <0x54>;
+ #mux-control-cells = <1>;
+ mux-reg-masks = <0x54 0xf0>;
+ mdio-parent-bus = <&mdio0>;
+
+ /* on-board MDIO with a single RGMII PHY */
+ mdio@00 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x00>;
+
+ /* on-board 1G RGMII PHY */
+ qds_phy0: phy@5 {
+ reg = <5>;
+ };
+ };
+ /* card slot 1 */
+ mdio@40 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x40>;
+ /* VSC8234 1G SGMII card */
+ sgmii_port0: phy@1c {
+ reg = <0x1c>;
+ };
+ };
+ /* card slot 2 */
+ mdio@50 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x50>;
+ };
+ /* card slot 3 */
+ mdio@60 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x60>;
+ };
+ /* card slot 4 */
+ mdio@70 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+ };
+ };
+ };
+};
+
+/* Parent MDIO, defined in SoC .dtsi file, just enabled here */
+&mdio0 {
+ status = "okay";
+};
diff --git a/doc/device-tree-bindings/net/mdio-mux.txt b/doc/device-tree-bindings/net/mdio-mux.txt
new file mode 100644
index 0000000..eaa31ef
--- /dev/null
+++ b/doc/device-tree-bindings/net/mdio-mux.txt
@@ -0,0 +1,138 @@
+The expected structure of an MDIO MUX device tree node is described here. This
+is heavily based on current Linux specification.
+One notable difference to Linux is that mdio-parent-bus is currently required
+by U-Boot, not optional as is in Linux. Current U-Boot MDIO MUX udevice class
+implementation does not have specific support for MDIOs with an integrated MUX,
+the property should be made optional if such support is added.
+
+The MDIO buses downstream of the MUX should be described in the device tree as
+child nodes as indicated below.
+
+Required properties:
+mdio-parent-bus = a phandle to the MDIO bus used to perform actual I/O. This is
+ typically a real MDIO device, unless there are cascaded MUXes.
+#address-cells = <1>, each MDIO group is identified by one 32b value.
+#size-cells = <0>
+
+Other properties:
+The properties described here are sufficient for MDIO MUX DM class code, but
+MUX drivers may define additional properties, either required or optional.
+
+Required properties in child nodes:
+reg = value to be configured on the MUX to select the respective downstream
+ MDIO.
+
+Child nodes should normally contain PHY nodes, referenced by phandle from
+ethernet nodes of the eth interfaces using these PHYs.
+
+Example structure, extracted from Linux bindings document:
+
+ /* The parent MDIO bus. */
+ smi1: mdio@1180000001900 {
+ compatible = "cavium,octeon-3860-mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x11800 0x00001900 0x0 0x40>;
+ };
+ /*
+ * An NXP sn74cbtlv3253 dual 1-of-4 switch controlled by a
+ * pair of GPIO lines. Child busses 2 and 3 populated with 4
+ * PHYs each.
+ */
+ mdio-mux {
+ compatible = "mdio-mux-gpio";
+ gpios = <&gpio1 3 0>, <&gpio1 4 0>;
+ mdio-parent-bus = <&smi1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mdio@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy11: ethernet-phy@1 {
+ reg = <1>;
+ compatible = "marvell,88e1149r";
+ marvell,reg-init = <3 0x10 0 0x5777>,
+ <3 0x11 0 0x00aa>,
+ <3 0x12 0 0x4105>,
+ <3 0x13 0 0x0a60>;
+ interrupt-parent = <&gpio>;
+ interrupts = <10 8>; /* Pin 10, active low */
+ };
+ phy12: ethernet-phy@2 {
+ reg = <2>;
+ compatible = "marvell,88e1149r";
+ marvell,reg-init = <3 0x10 0 0x5777>,
+ <3 0x11 0 0x00aa>,
+ <3 0x12 0 0x4105>,
+ <3 0x13 0 0x0a60>;
+ interrupt-parent = <&gpio>;
+ interrupts = <10 8>; /* Pin 10, active low */
+ };
+ phy13: ethernet-phy@3 {
+ reg = <3>;
+ compatible = "marvell,88e1149r";
+ marvell,reg-init = <3 0x10 0 0x5777>,
+ <3 0x11 0 0x00aa>,
+ <3 0x12 0 0x4105>,
+ <3 0x13 0 0x0a60>;
+ interrupt-parent = <&gpio>;
+ interrupts = <10 8>; /* Pin 10, active low */
+ };
+ phy14: ethernet-phy@4 {
+ reg = <4>;
+ compatible = "marvell,88e1149r";
+ marvell,reg-init = <3 0x10 0 0x5777>,
+ <3 0x11 0 0x00aa>,
+ <3 0x12 0 0x4105>,
+ <3 0x13 0 0x0a60>;
+ interrupt-parent = <&gpio>;
+ interrupts = <10 8>; /* Pin 10, active low */
+ };
+ };
+ mdio@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy21: ethernet-phy@1 {
+ reg = <1>;
+ compatible = "marvell,88e1149r";
+ marvell,reg-init = <3 0x10 0 0x5777>,
+ <3 0x11 0 0x00aa>,
+ <3 0x12 0 0x4105>,
+ <3 0x13 0 0x0a60>;
+ interrupt-parent = <&gpio>;
+ interrupts = <12 8>; /* Pin 12, active low */
+ };
+ phy22: ethernet-phy@2 {
+ reg = <2>;
+ compatible = "marvell,88e1149r";
+ marvell,reg-init = <3 0x10 0 0x5777>,
+ <3 0x11 0 0x00aa>,
+ <3 0x12 0 0x4105>,
+ <3 0x13 0 0x0a60>;
+ interrupt-parent = <&gpio>;
+ interrupts = <12 8>; /* Pin 12, active low */
+ };
+ phy23: ethernet-phy@3 {
+ reg = <3>;
+ compatible = "marvell,88e1149r";
+ marvell,reg-init = <3 0x10 0 0x5777>,
+ <3 0x11 0 0x00aa>,
+ <3 0x12 0 0x4105>,
+ <3 0x13 0 0x0a60>;
+ interrupt-parent = <&gpio>;
+ interrupts = <12 8>; /* Pin 12, active low */
+ };
+ phy24: ethernet-phy@4 {
+ reg = <4>;
+ compatible = "marvell,88e1149r";
+ marvell,reg-init = <3 0x10 0 0x5777>,
+ <3 0x11 0 0x00aa>,
+ <3 0x12 0 0x4105>,
+ <3 0x13 0 0x0a60>;
+ interrupt-parent = <&gpio>;
+ interrupts = <12 8>; /* Pin 12, active low */
+ };
+ };
+ };
diff --git a/doc/device-tree-bindings/spi/spi-stm32-qspi.txt b/doc/device-tree-bindings/spi/spi-stm32-qspi.txt
index cec3e12..adeeb63 100644
--- a/doc/device-tree-bindings/spi/spi-stm32-qspi.txt
+++ b/doc/device-tree-bindings/spi/spi-stm32-qspi.txt
@@ -1,39 +1,44 @@
-STM32 QSPI controller device tree bindings
---------------------------------------------
+* STMicroelectronics Quad Serial Peripheral Interface(QSPI)
Required properties:
-- compatible : should be "st,stm32-qspi".
-- reg : 1. Physical base address and size of SPI registers map.
- 2. Physical base address & size of mapped NOR Flash.
-- spi-max-frequency : Max supported spi frequency.
-- status : enable in requried dts.
+- compatible: should be "st,stm32f469-qspi"
+- reg: the first contains the register location and length.
+ the second contains the memory mapping address and length
+- reg-names: should contain the reg names "qspi" "qspi_mm"
+- interrupts: should contain the interrupt for the device
+- clocks: the phandle of the clock needed by the QSPI controller
+- A pinctrl must be defined to set pins in mode of operation for QSPI transfer
-Connected flash properties
---------------------------
-- spi-max-frequency : Max supported spi frequency.
-- spi-tx-bus-width : Bus width (number of lines) for writing (1-4)
-- spi-rx-bus-width : Bus width (number of lines) for reading (1-4)
-- memory-map : Address and size for memory-mapping the flash
+Optional properties:
+- resets: must contain the phandle to the reset controller.
+
+A spi flash (NOR/NAND) must be a child of spi node and could have some
+properties. Also see jedec,spi-nor.txt.
+
+Required properties:
+- reg: chip-Select number (QSPI controller may connect 2 flashes)
+- spi-max-frequency: max frequency of spi bus
+
+Optional property:
+- spi-rx-bus-width: see ./spi-bus.txt for the description
Example:
- qspi: quadspi@A0001000 {
- compatible = "st,stm32-qspi";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0xA0001000 0x1000>, <0x90000000 0x10000000>;
- reg-names = "QuadSPI", "QuadSPI-memory";
- interrupts = <92>;
- spi-max-frequency = <108000000>;
- status = "okay";
- qflash0: n25q128a {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "micron,n25q128a13", "jedec,spi-nor";
- spi-max-frequency = <108000000>;
- spi-tx-bus-width = <4>;
- spi-rx-bus-width = <4>;
- memory-map = <0x90000000 0x1000000>;
- reg = <0>;
- };
+qspi: spi@a0001000 {
+ compatible = "st,stm32f469-qspi";
+ reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>;
+ reg-names = "qspi", "qspi_mm";
+ interrupts = <91>;
+ resets = <&rcc STM32F4_AHB3_RESET(QSPI)>;
+ clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_qspi0>;
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-rx-bus-width = <4>;
+ spi-max-frequency = <108000000>;
+ ...
};
+};
diff --git a/doc/driver-model/README.txt b/doc/driver-model/design.rst
similarity index 64%
rename from doc/driver-model/README.txt
rename to doc/driver-model/design.rst
index 532a771..8fd28c0 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/design.rst
@@ -1,40 +1,46 @@
-Driver Model
-============
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Simon Glass <sjg@chromium.org>
+
+Design Details
+==============
This README contains high-level information about driver model, a unified
way of declaring and accessing drivers in U-Boot. The original work was done
by:
- Marek Vasut <marex@denx.de>
- Pavel Herrmann <morpheus.ibis@gmail.com>
- Viktor KÅ™ivák <viktor.krivak@gmail.com>
- Tomas Hlavacek <tmshlvck@gmail.com>
+ * Marek Vasut <marex@denx.de>
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ * Viktor KÅ™ivák <viktor.krivak@gmail.com>
+ * Tomas Hlavacek <tmshlvck@gmail.com>
This has been both simplified and extended into the current implementation
by:
- Simon Glass <sjg@chromium.org>
+ * Simon Glass <sjg@chromium.org>
Terminology
-----------
-Uclass - a group of devices which operate in the same way. A uclass provides
- a way of accessing individual devices within the group, but always
- using the same interface. For example a GPIO uclass provides
- operations for get/set value. An I2C uclass may have 10 I2C ports,
- 4 with one driver, and 6 with another.
+Uclass
+ a group of devices which operate in the same way. A uclass provides
+ a way of accessing individual devices within the group, but always
+ using the same interface. For example a GPIO uclass provides
+ operations for get/set value. An I2C uclass may have 10 I2C ports,
+ 4 with one driver, and 6 with another.
-Driver - some code which talks to a peripheral and presents a higher-level
- interface to it.
+Driver
+ some code which talks to a peripheral and presents a higher-level
+ interface to it.
-Device - an instance of a driver, tied to a particular port or peripheral.
+Device
+ an instance of a driver, tied to a particular port or peripheral.
How to try it
-------------
-Build U-Boot sandbox and run it:
+Build U-Boot sandbox and run it::
make sandbox_defconfig
make
@@ -56,31 +62,31 @@
handles parameter data and platdata (data which tells the driver how
to operate on a particular platform) and it uses private driver data.
-To try it, see the example session below:
+To try it, see the example session below::
-=>demo hello 1
-Hello '@' from 07981110: red 4
-=>demo status 2
-Status: 0
-=>demo hello 2
-g
-r@
-e@@
-e@@@
-n@@@@
-g@@@@@
-=>demo status 2
-Status: 21
-=>demo hello 4 ^
- y^^^
- e^^^^^
-l^^^^^^^
-l^^^^^^^
- o^^^^^
- w^^^
-=>demo status 4
-Status: 36
-=>
+ =>demo hello 1
+ Hello '@' from 07981110: red 4
+ =>demo status 2
+ Status: 0
+ =>demo hello 2
+ g
+ r@
+ e@@
+ e@@@
+ n@@@@
+ g@@@@@
+ =>demo status 2
+ Status: 21
+ =>demo hello 4 ^
+ y^^^
+ e^^^^^
+ l^^^^^^^
+ l^^^^^^^
+ o^^^^^
+ w^^^
+ =>demo status 4
+ Status: 36
+ =>
Running the tests
@@ -88,139 +94,139 @@
The intent with driver model is that the core portion has 100% test coverage
in sandbox, and every uclass has its own test. As a move towards this, tests
-are provided in test/dm. To run them, try:
+are provided in test/dm. To run them, try::
./test/py/test.py --bd sandbox --build -k ut_dm -v
-You should see something like this:
+You should see something like this::
-(venv)$ ./test/py/test.py --bd sandbox --build -k ut_dm -v
-+make O=/root/u-boot/build-sandbox -s sandbox_defconfig
-+make O=/root/u-boot/build-sandbox -s -j8
-============================= test session starts ==============================
-platform linux2 -- Python 2.7.5, pytest-2.9.0, py-1.4.31, pluggy-0.3.1 -- /root/u-boot/venv/bin/python
-cachedir: .cache
-rootdir: /root/u-boot, inifile:
-collected 199 items
+ (venv)$ ./test/py/test.py --bd sandbox --build -k ut_dm -v
+ +make O=/root/u-boot/build-sandbox -s sandbox_defconfig
+ +make O=/root/u-boot/build-sandbox -s -j8
+ ============================= test session starts ==============================
+ platform linux2 -- Python 2.7.5, pytest-2.9.0, py-1.4.31, pluggy-0.3.1 -- /root/u-boot/venv/bin/python
+ cachedir: .cache
+ rootdir: /root/u-boot, inifile:
+ collected 199 items
-test/py/tests/test_ut.py::test_ut_dm_init PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_adc_bind] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_adc_multi_channel_conversion] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_adc_multi_channel_shot] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_adc_single_channel_conversion] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_adc_single_channel_shot] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_adc_supply] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_adc_wrong_channel_selection] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_autobind] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_autobind_uclass_pdata_alloc] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_autobind_uclass_pdata_valid] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_autoprobe] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_child_post_bind] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_child_post_bind_uclass] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_child_pre_probe_uclass] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_children] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_children_funcs] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_children_iterators] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_parent_data] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_parent_data_uclass] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_parent_ops] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_parent_platdata] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_bus_parent_platdata_uclass] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_children] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_clk_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_clk_periph] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_device_get_uclass_id] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_eth] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_eth_act] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_eth_alias] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_eth_prime] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_eth_rotate] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_fdt] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_fdt_offset] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_fdt_pre_reloc] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_fdt_uclass_seq] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_gpio] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_gpio_anon] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_gpio_copy] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_gpio_leak] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_gpio_phandles] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_gpio_requestf] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_i2c_bytewise] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_i2c_find] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_i2c_offset] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_i2c_offset_len] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_i2c_probe_empty] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_i2c_read_write] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_i2c_speed] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_leak] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_led_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_led_gpio] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_led_label] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_lifecycle] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_mmc_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_net_retry] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_operations] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_ordering] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_pci_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_pci_busnum] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_pci_swapcase] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_platdata] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_power_pmic_get] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_power_pmic_io] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_autoset] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_autoset_list] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_get] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_set_get_current] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_set_get_enable] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_set_get_mode] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_set_get_voltage] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_pre_reloc] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_ram_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_regmap_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_regmap_syscon] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_remoteproc_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_remove] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_reset_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_reset_walk] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_rtc_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_rtc_dual] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_rtc_reset] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_rtc_set_get] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_spi_find] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_spi_flash] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_spi_xfer] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_syscon_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_syscon_by_driver_data] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_timer_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_uclass] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_uclass_before_ready] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_uclass_devices_find] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_uclass_devices_find_by_name] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_uclass_devices_get] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_uclass_devices_get_by_name] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_usb_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_usb_flash] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_usb_keyb] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_usb_multi] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_usb_remove] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_usb_tree] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_usb_tree_remove] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_usb_tree_reorder] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_base] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_bmp] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_bmp_comp] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_chars] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_context] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_rotation1] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_rotation2] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_rotation3] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_text] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_truetype] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_truetype_bs] PASSED
-test/py/tests/test_ut.py::test_ut[ut_dm_video_truetype_scroll] PASSED
+ test/py/tests/test_ut.py::test_ut_dm_init PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_adc_bind] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_adc_multi_channel_conversion] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_adc_multi_channel_shot] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_adc_single_channel_conversion] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_adc_single_channel_shot] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_adc_supply] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_adc_wrong_channel_selection] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_autobind] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_autobind_uclass_pdata_alloc] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_autobind_uclass_pdata_valid] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_autoprobe] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_child_post_bind] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_child_post_bind_uclass] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_child_pre_probe_uclass] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_children] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_children_funcs] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_children_iterators] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_parent_data] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_parent_data_uclass] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_parent_ops] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_parent_platdata] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_bus_parent_platdata_uclass] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_children] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_clk_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_clk_periph] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_device_get_uclass_id] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_eth] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_eth_act] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_eth_alias] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_eth_prime] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_eth_rotate] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_fdt] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_fdt_offset] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_fdt_pre_reloc] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_fdt_uclass_seq] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_gpio] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_gpio_anon] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_gpio_copy] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_gpio_leak] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_gpio_phandles] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_gpio_requestf] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_i2c_bytewise] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_i2c_find] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_i2c_offset] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_i2c_offset_len] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_i2c_probe_empty] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_i2c_read_write] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_i2c_speed] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_leak] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_led_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_led_gpio] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_led_label] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_lifecycle] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_mmc_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_net_retry] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_operations] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_ordering] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_pci_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_pci_busnum] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_pci_swapcase] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_platdata] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_power_pmic_get] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_power_pmic_io] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_autoset] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_autoset_list] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_get] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_set_get_current] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_set_get_enable] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_set_get_mode] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_power_regulator_set_get_voltage] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_pre_reloc] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_ram_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_regmap_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_regmap_syscon] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_remoteproc_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_remove] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_reset_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_reset_walk] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_rtc_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_rtc_dual] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_rtc_reset] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_rtc_set_get] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_spi_find] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_spi_flash] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_spi_xfer] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_syscon_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_syscon_by_driver_data] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_timer_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_uclass] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_uclass_before_ready] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_uclass_devices_find] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_uclass_devices_find_by_name] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_uclass_devices_get] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_uclass_devices_get_by_name] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_usb_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_usb_flash] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_usb_keyb] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_usb_multi] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_usb_remove] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_usb_tree] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_usb_tree_remove] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_usb_tree_reorder] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_base] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_bmp] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_bmp_comp] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_chars] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_context] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_rotation1] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_rotation2] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_rotation3] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_text] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_truetype] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_truetype_bs] PASSED
+ test/py/tests/test_ut.py::test_ut[ut_dm_video_truetype_scroll] PASSED
-======================= 84 tests deselected by '-kut_dm' =======================
-================== 115 passed, 84 deselected in 3.77 seconds ===================
+ ======================= 84 tests deselected by '-kut_dm' =======================
+ ================== 115 passed, 84 deselected in 3.77 seconds ===================
What is going on?
-----------------
@@ -228,6 +234,8 @@
Let's start at the top. The demo command is in common/cmd_demo.c. It does
the usual command processing and then:
+.. code-block:: c
+
struct udevice *demo_dev;
ret = uclass_get_device(UCLASS_DEMO, devnum, &demo_dev);
@@ -245,6 +253,8 @@
Now that we have the device we can do things like:
+.. code-block:: c
+
return demo_hello(demo_dev, ch);
This function is in the demo uclass. It takes care of calling the 'hello'
@@ -253,29 +263,33 @@
The code for demo_hello() is in drivers/demo/demo-uclass.c:
-int demo_hello(struct udevice *dev, int ch)
-{
- const struct demo_ops *ops = device_get_ops(dev);
+.. code-block:: c
- if (!ops->hello)
- return -ENOSYS;
+ int demo_hello(struct udevice *dev, int ch)
+ {
+ const struct demo_ops *ops = device_get_ops(dev);
- return ops->hello(dev, ch);
-}
+ if (!ops->hello)
+ return -ENOSYS;
+
+ return ops->hello(dev, ch);
+ }
As you can see it just calls the relevant driver method. One of these is
in drivers/demo/demo-simple.c:
-static int simple_hello(struct udevice *dev, int ch)
-{
- const struct dm_demo_pdata *pdata = dev_get_platdata(dev);
+.. code-block:: c
- printf("Hello from %08x: %s %d\n", map_to_sysmem(dev),
- pdata->colour, pdata->sides);
+ static int simple_hello(struct udevice *dev, int ch)
+ {
+ const struct dm_demo_pdata *pdata = dev_get_platdata(dev);
- return 0;
-}
+ printf("Hello from %08x: %s %d\n", map_to_sysmem(dev),
+ pdata->colour, pdata->sides);
+ return 0;
+ }
+
So that is a trip from top (command execution) to bottom (driver action)
but it leaves a lot of topics to address.
@@ -287,17 +301,19 @@
A driver declaration looks something like this (see
drivers/demo/demo-shape.c):
-static const struct demo_ops shape_ops = {
- .hello = shape_hello,
- .status = shape_status,
-};
+.. code-block:: c
-U_BOOT_DRIVER(demo_shape_drv) = {
- .name = "demo_shape_drv",
- .id = UCLASS_DEMO,
- .ops = &shape_ops,
- .priv_data_size = sizeof(struct shape_data),
-};
+ static const struct demo_ops shape_ops = {
+ .hello = shape_hello,
+ .status = shape_status,
+ };
+
+ U_BOOT_DRIVER(demo_shape_drv) = {
+ .name = "demo_shape_drv",
+ .id = UCLASS_DEMO,
+ .ops = &shape_ops,
+ .priv_data_size = sizeof(struct shape_data),
+ };
This driver has two methods (hello and status) and requires a bit of
@@ -315,11 +331,11 @@
The methods a device can provide are documented in the device.h header.
Briefly, they are:
- bind - make the driver model aware of a device (bind it to its driver)
- unbind - make the driver model forget the device
- ofdata_to_platdata - convert device tree data to platdata - see later
- probe - make a device ready for use
- remove - remove a device so it cannot be used until probed again
+ * bind - make the driver model aware of a device (bind it to its driver)
+ * unbind - make the driver model forget the device
+ * ofdata_to_platdata - convert device tree data to platdata - see later
+ * probe - make a device ready for use
+ * remove - remove a device so it cannot be used until probed again
The sequence to get a device to work is bind, ofdata_to_platdata (if using
device tree) and probe.
@@ -328,14 +344,14 @@
Platform Data
-------------
-*** Note: platform data is the old way of doing things. It is
-*** basically a C structure which is passed to drivers to tell them about
-*** platform-specific settings like the address of its registers, bus
-*** speed, etc. Device tree is now the preferred way of handling this.
-*** Unless you have a good reason not to use device tree (the main one
-*** being you need serial support in SPL and don't have enough SRAM for
-*** the cut-down device tree and libfdt libraries) you should stay away
-*** from platform data.
+Note: platform data is the old way of doing things. It is
+basically a C structure which is passed to drivers to tell them about
+platform-specific settings like the address of its registers, bus
+speed, etc. Device tree is now the preferred way of handling this.
+Unless you have a good reason not to use device tree (the main one
+being you need serial support in SPL and don't have enough SRAM for
+the cut-down device tree and libfdt libraries) you should stay away
+from platform data.
Platform data is like Linux platform data, if you are familiar with that.
It provides the board-specific information to start up a device.
@@ -366,9 +382,9 @@
- The base address of the IP block's register space
- Configuration options, like:
- - the SPI polarity and maximum speed for a SPI controller
- - the I2C speed to use for an I2C device
- - the number of GPIOs available in a GPIO device
+ - the SPI polarity and maximum speed for a SPI controller
+ - the I2C speed to use for an I2C device
+ - the number of GPIOs available in a GPIO device
Where does the platform data come from? It is either held in a structure
which is compiled into U-Boot, or it can be parsed from the Device Tree
@@ -384,10 +400,13 @@
the declaration for the platform data, which would normally appear
in the board file.
+.. code-block:: c
+
static const struct dm_demo_cdata red_square = {
.colour = "red",
.sides = 4.
};
+
static const struct driver_info info[] = {
{
.name = "demo_shape_drv",
@@ -409,6 +428,8 @@
With device tree we replace the above code with the following device tree
fragment:
+.. code-block:: c
+
red-square {
compatible = "demo-shape";
colour = "red";
@@ -425,6 +446,8 @@
The easiest way to make this work it to add a few members to the driver:
+.. code-block:: c
+
.platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
.ofdata_to_platdata = testfdt_ofdata_to_platdata,
@@ -464,9 +487,11 @@
The demo uclass is declared like this:
-U_BOOT_CLASS(demo) = {
- .id = UCLASS_DEMO,
-};
+.. code-block:: c
+
+ U_BOOT_CLASS(demo) = {
+ .id = UCLASS_DEMO,
+ };
It is also possible to specify special methods for probe, etc. The uclass
numbering comes from include/dm/uclass.h. To add a new uclass, add to the
@@ -496,9 +521,11 @@
To specify the sequence number in the device tree an alias is typically
used. Make sure that the uclass has the DM_UC_FLAG_SEQ_ALIAS flag set.
-aliases {
- serial2 = "/serial@22230000";
-};
+.. code-block:: none
+
+ aliases {
+ serial2 = "/serial@22230000";
+ };
This indicates that in the uclass called "serial", the named node
("/serial@22230000") will be given sequence number 2. Any command or driver
@@ -506,13 +533,15 @@
More commonly you can use node references, which expand to the full path:
-aliases {
- serial2 = &serial_2;
-};
-...
-serial_2: serial@22230000 {
-...
-};
+.. code-block:: none
+
+ aliases {
+ serial2 = &serial_2;
+ };
+ ...
+ serial_2: serial@22230000 {
+ ...
+ };
The alias resolves to the same string in this case, but this version is
easier to read.
@@ -547,7 +576,7 @@
Here an explanation of how a bus fits with a uclass may be useful. Consider
a USB bus with several devices attached to it, each from a different (made
-up) uclass:
+up) uclass::
xhci_usb (UCLASS_USB)
eth (UCLASS_ETHERNET)
@@ -579,7 +608,7 @@
driver, not the child's. In fact it is possible that child has no knowledge
that it is connected to a bus. The same child device may even be used on two
different bus types. As an example. the 'flash' device shown above may also
-be connected on a SATA bus or standalone with no bus:
+be connected on a SATA bus or standalone with no bus::
xhci_usb (UCLASS_USB)
flash (UCLASS_FLASH_STORAGE) - parent data/methods defined by USB bus
@@ -613,20 +642,21 @@
a device then it will not be called. A simple device may have very few
methods actually defined.
-1. Bind stage
+Bind stage
+^^^^^^^^^^
U-Boot discovers devices using one of these two methods:
- - Scan the U_BOOT_DEVICE() definitions. U-Boot looks up the name specified
-by each, to find the appropriate U_BOOT_DRIVER() definition. In this case,
-there is no path by which driver_data may be provided, but the U_BOOT_DEVICE()
-may provide platdata.
+- Scan the U_BOOT_DEVICE() definitions. U-Boot looks up the name specified
+ by each, to find the appropriate U_BOOT_DRIVER() definition. In this case,
+ there is no path by which driver_data may be provided, but the U_BOOT_DEVICE()
+ may provide platdata.
- - Scan through the device tree definitions. U-Boot looks at top-level
-nodes in the the device tree. It looks at the compatible string in each node
-and uses the of_match table of the U_BOOT_DRIVER() structure to find the
-right driver for each node. In this case, the of_match table may provide a
-driver_data value, but platdata cannot be provided until later.
+- Scan through the device tree definitions. U-Boot looks at top-level
+ nodes in the the device tree. It looks at the compatible string in each node
+ and uses the of_match table of the U_BOOT_DRIVER() structure to find the
+ right driver for each node. In this case, the of_match table may provide a
+ driver_data value, but platdata cannot be provided until later.
For each device that is discovered, U-Boot then calls device_bind() to create a
new device, initializes various core fields of the device object such as name,
@@ -653,45 +683,46 @@
U-Boot it may be expensive to probe devices and we don't want to do it until
they are needed, or perhaps until after relocation.
-2. Activation/probe
+Activation/probe
+^^^^^^^^^^^^^^^^
When a device needs to be used, U-Boot activates it, by following these
steps (see device_probe()):
- a. If priv_auto_alloc_size is non-zero, then the device-private space
+ 1. If priv_auto_alloc_size is non-zero, then the device-private space
is allocated for the device and zeroed. It will be accessible as
dev->priv. The driver can put anything it likes in there, but should use
it for run-time information, not platform data (which should be static
and known before the device is probed).
- b. If platdata_auto_alloc_size is non-zero, then the platform data space
+ 2. If platdata_auto_alloc_size is non-zero, then the platform data space
is allocated. This is only useful for device tree operation, since
otherwise you would have to specific the platform data in the
U_BOOT_DEVICE() declaration. The space is allocated for the device and
zeroed. It will be accessible as dev->platdata.
- c. If the device's uclass specifies a non-zero per_device_auto_alloc_size,
+ 3. If the device's uclass specifies a non-zero per_device_auto_alloc_size,
then this space is allocated and zeroed also. It is allocated for and
stored in the device, but it is uclass data. owned by the uclass driver.
It is possible for the device to access it.
- d. If the device's immediate parent specifies a per_child_auto_alloc_size
+ 4. If the device's immediate parent specifies a per_child_auto_alloc_size
then this space is allocated. This is intended for use by the parent
device to keep track of things related to the child. For example a USB
flash stick attached to a USB host controller would likely use this
space. The controller can hold information about the USB state of each
of its children.
- e. All parent devices are probed. It is not possible to activate a device
+ 5. All parent devices are probed. It is not possible to activate a device
unless its predecessors (all the way up to the root device) are activated.
This means (for example) that an I2C driver will require that its bus
be activated.
- f. The device's sequence number is assigned, either the requested one
+ 6. The device's sequence number is assigned, either the requested one
(assuming no conflicts) or the next available one if there is a conflict
or nothing particular is requested.
- g. If the driver provides an ofdata_to_platdata() method, then this is
+ 7. If the driver provides an ofdata_to_platdata() method, then this is
called to convert the device tree data into platform data. This should
do various calls like fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), ...)
to access the node and store the resulting information into dev->platdata.
@@ -707,7 +738,7 @@
data, one day it is possible that U-Boot will cache platform data for
devices which are regularly de/activated).
- h. The device's probe() method is called. This should do anything that
+ 8. The device's probe() method is called. This should do anything that
is required by the device to get it going. This could include checking
that the hardware is actually present, setting up clocks for the
hardware and setting up hardware registers to initial values. The code
@@ -722,40 +753,42 @@
allocate the priv space here yourself. The same applies also to
platdata_auto_alloc_size. Remember to free them in the remove() method.
- i. The device is marked 'activated'
+ 9. The device is marked 'activated'
- j. The uclass's post_probe() method is called, if one exists. This may
+ 10. The uclass's post_probe() method is called, if one exists. This may
cause the uclass to do some housekeeping to record the device as
activated and 'known' by the uclass.
-3. Running stage
+Running stage
+^^^^^^^^^^^^^
The device is now activated and can be used. From now until it is removed
all of the above structures are accessible. The device appears in the
uclass's list of devices (so if the device is in UCLASS_GPIO it will appear
as a device in the GPIO uclass). This is the 'running' state of the device.
-4. Removal stage
+Removal stage
+^^^^^^^^^^^^^
When the device is no-longer required, you can call device_remove() to
remove it. This performs the probe steps in reverse:
- a. The uclass's pre_remove() method is called, if one exists. This may
+ 1. The uclass's pre_remove() method is called, if one exists. This may
cause the uclass to do some housekeeping to record the device as
deactivated and no-longer 'known' by the uclass.
- b. All the device's children are removed. It is not permitted to have
+ 2. All the device's children are removed. It is not permitted to have
an active child device with a non-active parent. This means that
device_remove() is called for all the children recursively at this point.
- c. The device's remove() method is called. At this stage nothing has been
+ 3. The device's remove() method is called. At this stage nothing has been
deallocated so platform data, private data and the uclass data will all
still be present. This is where the hardware can be shut down. It is
intended that the device be completely inactive at this point, For U-Boot
to be sure that no hardware is running, it should be enough to remove
all devices.
- d. The device memory is freed (platform data, private data, uclass data,
+ 4. The device memory is freed (platform data, private data, uclass data,
parent data).
Note: Because the platform data for a U_BOOT_DEVICE() is defined with a
@@ -764,25 +797,26 @@
be dynamically allocated, and thus needs to be deallocated during the
remove() method, either:
- 1. if the platdata_auto_alloc_size is non-zero, the deallocation
- happens automatically within the driver model core; or
+ - if the platdata_auto_alloc_size is non-zero, the deallocation
+ happens automatically within the driver model core; or
- 2. when platdata_auto_alloc_size is 0, both the allocation (in probe()
- or preferably ofdata_to_platdata()) and the deallocation in remove()
- are the responsibility of the driver author.
+ - when platdata_auto_alloc_size is 0, both the allocation (in probe()
+ or preferably ofdata_to_platdata()) and the deallocation in remove()
+ are the responsibility of the driver author.
- e. The device sequence number is set to -1, meaning that it no longer
+ 5. The device sequence number is set to -1, meaning that it no longer
has an allocated sequence. If the device is later reactivated and that
sequence number is still free, it may well receive the name sequence
number again. But from this point, the sequence number previously used
by this device will no longer exist (think of SPI bus 2 being removed
and bus 2 is no longer available for use).
- f. The device is marked inactive. Note that it is still bound, so the
+ 6. The device is marked inactive. Note that it is still bound, so the
device structure itself is not freed at this point. Should the device be
activated again, then the cycle starts again at step 2 above.
-5. Unbind stage
+Unbind stage
+^^^^^^^^^^^^
The device is unbound. This is the step that actually destroys the device.
If a parent has children these will be destroyed first. After this point
@@ -805,24 +839,24 @@
original patches, but makes at least the following changes:
- Tried to aggressively remove boilerplate, so that for most drivers there
-is little or no 'driver model' code to write.
+ is little or no 'driver model' code to write.
- Moved some data from code into data structure - e.g. store a pointer to
-the driver operations structure in the driver, rather than passing it
-to the driver bind function.
+ the driver operations structure in the driver, rather than passing it
+ to the driver bind function.
- Rename some structures to make them more similar to Linux (struct udevice
-instead of struct instance, struct platdata, etc.)
+ instead of struct instance, struct platdata, etc.)
- Change the name 'core' to 'uclass', meaning U-Boot class. It seems that
-this concept relates to a class of drivers (or a subsystem). We shouldn't
-use 'class' since it is a C++ reserved word, so U-Boot class (uclass) seems
-better than 'core'.
+ this concept relates to a class of drivers (or a subsystem). We shouldn't
+ use 'class' since it is a C++ reserved word, so U-Boot class (uclass) seems
+ better than 'core'.
- Remove 'struct driver_instance' and just use a single 'struct udevice'.
-This removes a level of indirection that doesn't seem necessary.
+ This removes a level of indirection that doesn't seem necessary.
- Built in device tree support, to avoid the need for platdata
- Removed the concept of driver relocation, and just make it possible for
-the new driver (created after relocation) to access the old driver data.
-I feel that relocation is a very special case and will only apply to a few
-drivers, many of which can/will just re-init anyway. So the overhead of
-dealing with this might not be worth it.
+ the new driver (created after relocation) to access the old driver data.
+ I feel that relocation is a very special case and will only apply to a few
+ drivers, many of which can/will just re-init anyway. So the overhead of
+ dealing with this might not be worth it.
- Implemented a GPIO system, trying to keep it simple
@@ -903,12 +937,3 @@
lookup service, perhaps searching by name. This is slightly less efficient
so has been left out for now. One small advantage of dynamic numbering might
be fewer merge conflicts in uclass-id.h.
-
-
-Simon Glass
-sjg@chromium.org
-April 2013
-Updated 7-May-13
-Updated 14-Jun-13
-Updated 18-Oct-13
-Updated 5-Nov-13
diff --git a/doc/driver-model/fdt-fixup.txt b/doc/driver-model/fdt-fixup.rst
similarity index 89%
rename from doc/driver-model/fdt-fixup.txt
rename to doc/driver-model/fdt-fixup.rst
index 70344bd..974c090 100644
--- a/doc/driver-model/fdt-fixup.txt
+++ b/doc/driver-model/fdt-fixup.rst
@@ -1,15 +1,11 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. 2017-01-06, Mario Six <mario.six@gdsys.cc>
+
Pre-relocation device tree manipulation
=======================================
-Contents:
-
-1. Purpose
-2. Implementation
-3. Example
-4. Work to be done
-
-1. Purpose
-----------
+Purpose
+-------
In certain markets, it is beneficial for manufacturers of embedded devices to
offer certain ranges of products, where the functionality of the devices within
@@ -61,14 +57,16 @@
means that we can query the hardware for the existence and variety of the
components easily.
-2. Implementation
------------------
+Implementation
+--------------
To take advantage of the pre-relocation device tree manipulation mechanism,
boards have to implement the function board_fix_fdt, which has the following
signature:
-int board_fix_fdt (void *rw_fdt_blob)
+.. code-block:: c
+
+ int board_fix_fdt (void *rw_fdt_blob)
The passed-in void pointer is a writeable pointer to the device tree, which can
be used to manipulate the device tree using e.g. functions from
@@ -79,10 +77,10 @@
(in common/board_f.c).
Furthermore, the Kconfig option OF_BOARD_FIXUP has to be set for the function
-to be called:
+to be called::
-Device Tree Control
--> [*] Board-specific manipulation of Device Tree
+ Device Tree Control
+ -> [*] Board-specific manipulation of Device Tree
+----------------------------------------------------------+
| WARNING: The actual manipulation of the device tree has |
@@ -97,23 +95,27 @@
Hence, the recommended layout of the board_fixup_fdt call-back function is the
following:
-int board_fix_fdt(void *rw_fdt_blob)
-{
- /* Collect information about device's hardware and store them in e.g.
- local variables */
+.. code-block:: c
- /* Do device tree manipulation using the values previously collected */
+ int board_fix_fdt(void *rw_fdt_blob)
+ {
+ /*
+ * Collect information about device's hardware and store
+ * them in e.g. local variables
+ */
- /* Return 0 on successful manipulation and non-zero otherwise */
-}
+ /* Do device tree manipulation using the values previously collected */
+
+ /* Return 0 on successful manipulation and non-zero otherwise */
+ }
If this convention is kept, both an "additive" approach, meaning that nodes for
detected components are added to the device tree, as well as a "subtractive"
approach, meaning that nodes for absent components are removed from the tree,
as well as a combination of both approaches should work.
-3. Example
-----------
+Example
+-------
The controlcenterdc board (board/gdsys/a38x/controlcenterdc.c) features a
board_fix_fdt function, in which six GPIO expanders (which might be present or
@@ -123,10 +125,8 @@
Note that the dm_i2c_simple_probe function does not use the device tree, hence
it is safe to call it after the tree has already been manipulated.
-4. Work to be done
-------------------
+Work to be done
+---------------
* The application of device tree overlay should be possible in board_fixup_fdt,
but has not been tested at this stage.
-
-2017-01-06, Mario Six <mario.six@gdsys.cc>
diff --git a/doc/driver-model/fs_firmware_loader.rst b/doc/driver-model/fs_firmware_loader.rst
new file mode 100644
index 0000000..a44708c
--- /dev/null
+++ b/doc/driver-model/fs_firmware_loader.rst
@@ -0,0 +1,154 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (C) 2018-2019 Intel Corporation <www.intel.com>
+
+File System Firmware Loader
+===========================
+
+This is file system firmware loader for U-Boot framework, which has very close
+to some Linux Firmware API. For the details of Linux Firmware API, you can refer
+to https://01.org/linuxgraphics/gfx-docs/drm/driver-api/firmware/index.html.
+
+File system firmware loader can be used to load whatever(firmware, image,
+and binary) from the storage device in file system format into target location
+such as memory, then consumer driver such as FPGA driver can program FPGA image
+from the target location into FPGA.
+
+To enable firmware loader, CONFIG_FS_LOADER need to be set at
+<board_name>_defconfig such as "CONFIG_FS_LOADER=y".
+
+Firmware Loader API core features
+---------------------------------
+
+Firmware storage device described in device tree source
+-------------------------------------------------------
+For passing data like storage device phandle and partition where the
+firmware loading from to the firmware loader driver, those data could be
+defined in fs-loader node as shown in below:
+
+Example for block device::
+
+ fs_loader0: fs-loader {
+ u-boot,dm-pre-reloc;
+ compatible = "u-boot,fs-loader";
+ phandlepart = <&mmc 1>;
+ };
+
+<&mmc 1> means block storage device pointer and its partition.
+
+Above example is a description for block storage, but for UBI storage
+device, it can be described in FDT as shown in below:
+
+Example for ubi::
+
+ fs_loader1: fs-loader {
+ u-boot,dm-pre-reloc;
+ compatible = "u-boot,fs-loader";
+ mtdpart = "UBI",
+ ubivol = "ubi0";
+ };
+
+Then, firmware-loader property can be added with any device node, which
+driver would use the firmware loader for loading.
+
+The value of the firmware-loader property should be set with phandle
+of the fs-loader node. For example::
+
+ firmware-loader = <&fs_loader0>;
+
+If there are majority of devices using the same fs-loader node, then
+firmware-loader property can be added under /chosen node instead of
+adding to each of device node.
+
+For example::
+
+ /{
+ chosen {
+ firmware-loader = <&fs_loader0>;
+ };
+ };
+
+In each respective driver of devices using firmware loader, the firmware
+loaded instance should be created by DT phandle.
+
+For example of getting DT phandle from /chosen and creating instance:
+
+.. code-block:: c
+
+ chosen_node = ofnode_path("/chosen");
+ if (!ofnode_valid(chosen_node)) {
+ debug("/chosen node was not found.\n");
+ return -ENOENT;
+ }
+
+ phandle_p = ofnode_get_property(chosen_node, "firmware-loader", &size);
+ if (!phandle_p) {
+ debug("firmware-loader property was not found.\n");
+ return -ENOENT;
+ }
+
+ phandle = fdt32_to_cpu(*phandle_p);
+ ret = uclass_get_device_by_phandle_id(UCLASS_FS_FIRMWARE_LOADER,
+ phandle, &dev);
+ if (ret)
+ return ret;
+
+Firmware loader driver is also designed to support U-boot environment
+variables, so all these data from FDT can be overwritten
+through the U-boot environment variable during run time.
+
+For examples:
+
+storage_interface:
+ Storage interface, it can be "mmc", "usb", "sata" or "ubi".
+fw_dev_part:
+ Block device number and its partition, it can be "0:1".
+fw_ubi_mtdpart:
+ UBI device mtd partition, it can be "UBI".
+fw_ubi_volume:
+ UBI volume, it can be "ubi0".
+
+When above environment variables are set, environment values would be
+used instead of data from FDT.
+The benefit of this design allows user to change storage attribute data
+at run time through U-boot console and saving the setting as default
+environment values in the storage for the next power cycle, so no
+compilation is required for both driver and FDT.
+
+File system firmware Loader API
+-------------------------------
+
+.. code-block:: c
+
+ int request_firmware_into_buf(struct udevice *dev,
+ const char *name,
+ void *buf, size_t size, u32 offset)
+
+Load firmware into a previously allocated buffer
+
+Parameters:
+
+* struct udevice \*dev: An instance of a driver
+* const char \*name: name of firmware file
+* void \*buf: address of buffer to load firmware into
+* size_t size: size of buffer
+* u32 offset: offset of a file for start reading into buffer
+
+Returns:
+ size of total read
+ -ve when error
+
+Description:
+ The firmware is loaded directly into the buffer pointed to by buf
+
+Example of calling request_firmware_into_buf API after creating firmware loader
+instance:
+
+.. code-block:: c
+
+ ret = uclass_get_device_by_phandle_id(UCLASS_FS_FIRMWARE_LOADER,
+ phandle, &dev);
+ if (ret)
+ return ret;
+
+ request_firmware_into_buf(dev, filename, buffer_location, buffer_size,
+ offset_ofreading);
diff --git a/doc/driver-model/fs_firmware_loader.txt b/doc/driver-model/fs_firmware_loader.txt
deleted file mode 100644
index 8be6185..0000000
--- a/doc/driver-model/fs_firmware_loader.txt
+++ /dev/null
@@ -1,148 +0,0 @@
-# Copyright (C) 2018-2019 Intel Corporation <www.intel.com>
-#
-# SPDX-License-Identifier: GPL-2.0
-
-Introduction
-============
-
-This is file system firmware loader for U-Boot framework, which has very close
-to some Linux Firmware API. For the details of Linux Firmware API, you can refer
-to https://01.org/linuxgraphics/gfx-docs/drm/driver-api/firmware/index.html.
-
-File system firmware loader can be used to load whatever(firmware, image,
-and binary) from the storage device in file system format into target location
-such as memory, then consumer driver such as FPGA driver can program FPGA image
-from the target location into FPGA.
-
-To enable firmware loader, CONFIG_FS_LOADER need to be set at
-<board_name>_defconfig such as "CONFIG_FS_LOADER=y".
-
-Firmware Loader API core features
----------------------------------
-
-Firmware storage device described in device tree source
--------------------------------------------------------
- For passing data like storage device phandle and partition where the
- firmware loading from to the firmware loader driver, those data could be
- defined in fs-loader node as shown in below:
-
- Example for block device:
- fs_loader0: fs-loader {
- u-boot,dm-pre-reloc;
- compatible = "u-boot,fs-loader";
- phandlepart = <&mmc 1>;
- };
-
- <&mmc 1> means block storage device pointer and its partition.
-
- Above example is a description for block storage, but for UBI storage
- device, it can be described in FDT as shown in below:
-
- Example for ubi:
- fs_loader1: fs-loader {
- u-boot,dm-pre-reloc;
- compatible = "u-boot,fs-loader";
- mtdpart = "UBI",
- ubivol = "ubi0";
- };
-
- Then, firmware-loader property can be added with any device node, which
- driver would use the firmware loader for loading.
-
- The value of the firmware-loader property should be set with phandle
- of the fs-loader node.
- For example:
- firmware-loader = <&fs_loader0>;
-
- If there are majority of devices using the same fs-loader node, then
- firmware-loader property can be added under /chosen node instead of
- adding to each of device node.
-
- For example:
- /{
- chosen {
- firmware-loader = <&fs_loader0>;
- };
- };
-
- In each respective driver of devices using firmware loader, the firmware
- loaded instance should be created by DT phandle.
-
- For example of getting DT phandle from /chosen and creating instance:
- chosen_node = ofnode_path("/chosen");
- if (!ofnode_valid(chosen_node)) {
- debug("/chosen node was not found.\n");
- return -ENOENT;
- }
-
- phandle_p = ofnode_get_property(chosen_node, "firmware-loader", &size);
- if (!phandle_p) {
- debug("firmware-loader property was not found.\n");
- return -ENOENT;
- }
-
- phandle = fdt32_to_cpu(*phandle_p);
- ret = uclass_get_device_by_phandle_id(UCLASS_FS_FIRMWARE_LOADER,
- phandle, &dev);
- if (ret)
- return ret;
-
- Firmware loader driver is also designed to support U-boot environment
- variables, so all these data from FDT can be overwritten
- through the U-boot environment variable during run time.
- For examples:
- "storage_interface" - Storage interface, it can be "mmc", "usb", "sata"
- or "ubi".
- "fw_dev_part" - Block device number and its partition, it can be "0:1".
- "fw_ubi_mtdpart" - UBI device mtd partition, it can be "UBI".
- "fw_ubi_volume" - UBI volume, it can be "ubi0".
-
- When above environment variables are set, environment values would be
- used instead of data from FDT.
- The benefit of this design allows user to change storage attribute data
- at run time through U-boot console and saving the setting as default
- environment values in the storage for the next power cycle, so no
- compilation is required for both driver and FDT.
-
-File system firmware Loader API
--------------------------------
-
-int request_firmware_into_buf(struct udevice *dev,
- const char *name,
- void *buf, size_t size, u32 offset)
---------------------------------------------------------------------
-Load firmware into a previously allocated buffer
-
-Parameters:
-
-1. struct udevice *dev
- An instance of a driver
-
-2. const char *name
- name of firmware file
-
-3. void *buf
- address of buffer to load firmware into
-
-4. size_t size
- size of buffer
-
-5. u32 offset
- offset of a file for start reading into buffer
-
-return:
- size of total read
- -ve when error
-
-Description:
- The firmware is loaded directly into the buffer pointed to by buf
-
-Example of calling request_firmware_into_buf API after creating firmware loader
-instance:
- ret = uclass_get_device_by_phandle_id(UCLASS_FS_FIRMWARE_LOADER,
- phandle, &dev);
- if (ret)
- return ret;
-
- request_firmware_into_buf(dev, filename, buffer_location, buffer_size,
- offset_ofreading);
diff --git a/doc/driver-model/i2c-howto.txt b/doc/driver-model/i2c-howto.rst
similarity index 82%
rename from doc/driver-model/i2c-howto.txt
rename to doc/driver-model/i2c-howto.rst
index 8ba2f6e..938b707 100644
--- a/doc/driver-model/i2c-howto.txt
+++ b/doc/driver-model/i2c-howto.rst
@@ -1,21 +1,23 @@
-How to port a serial driver to driver model
-===========================================
+.. SPDX-License-Identifier: GPL-2.0+
+
+How to port an I2C driver to driver model
+=========================================
Over half of the I2C drivers have been converted as at November 2016. These
ones remain:
- adi_i2c
- davinci_i2c
- fti2c010
- ihs_i2c
- kona_i2c
- lpc32xx_i2c
- pca9564_i2c
- ppc4xx_i2c
- rcar_i2c
- sh_i2c
- soft_i2c
- zynq_i2c
+ * adi_i2c
+ * davinci_i2c
+ * fti2c010
+ * ihs_i2c
+ * kona_i2c
+ * lpc32xx_i2c
+ * pca9564_i2c
+ * ppc4xx_i2c
+ * rcar_i2c
+ * sh_i2c
+ * soft_i2c
+ * zynq_i2c
The deadline for this work is the end of June 2017. If no one steps
forward to convert these, at some point there may come a patch to remove them!
@@ -27,14 +29,14 @@
- Define CONFIG_DM_I2C for your board, vendor or architecture
- If the board does not already use driver model, you need CONFIG_DM also
- Your board should then build, but will not work fully since there will be
- no I2C driver
+ no I2C driver
- Add the U_BOOT_DRIVER piece at the end (e.g. copy tegra_i2c.c for example)
- Add a private struct for the driver data - avoid using static variables
- Implement each of the driver methods, perhaps by calling your old methods
- You may need to adjust the function parameters so that the old and new
- implementations can share most of the existing code
+ implementations can share most of the existing code
- If you convert all existing users of the driver, remove the pre-driver-model
- code
+ code
In terms of patches a conversion series typically has these patches:
- clean up / prepare the driver for conversion
diff --git a/doc/driver-model/index.rst b/doc/driver-model/index.rst
new file mode 100644
index 0000000..ea32c36
--- /dev/null
+++ b/doc/driver-model/index.rst
@@ -0,0 +1,21 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Driver Model
+============
+
+.. toctree::
+ :maxdepth: 2
+
+ design
+ fdt-fixup
+ fs_firmware_loader
+ i2c-howto
+ livetree
+ migration
+ of-plat
+ pci-info
+ pmic-framework
+ remoteproc-framework
+ serial-howto
+ spi-howto
+ usb-info
diff --git a/doc/driver-model/livetree.txt b/doc/driver-model/livetree.rst
similarity index 76%
rename from doc/driver-model/livetree.txt
rename to doc/driver-model/livetree.rst
index 01d4488..9f654f3 100644
--- a/doc/driver-model/livetree.txt
+++ b/doc/driver-model/livetree.rst
@@ -1,6 +1,9 @@
-Driver Model with Live Device Tree
-==================================
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Simon Glass <sjg@chromium.org>
+Live Device Tree
+================
+
Introduction
------------
@@ -20,7 +23,7 @@
The flat device tree has several advantages:
- it is the format produced by the device tree compiler, so no translation
-is needed
+ is needed
- it is fairly compact (e.g. there is no need for pointers)
@@ -53,12 +56,12 @@
node (when the live tree node is not yet set up) or a livetree node. The
caller of an ofnode function does not need to worry about these details.
-The main users of the information in a device tree are drivers. These have
-a 'struct udevice *' which is attached to a device tree node. Therefore it
+The main users of the information in a device tree are drivers. These have
+a 'struct udevice \*' which is attached to a device tree node. Therefore it
makes sense to be able to read device tree properties using the
-'struct udevice *', rather than having to obtain the ofnode first.
+'struct udevice \*', rather than having to obtain the ofnode first.
-The 'dev_read_...()' interface provides this. It allows properties to be
+The 'dev_read\_...()' interface provides this. It allows properties to be
easily read from the device tree using only a device pointer. Under the
hood it uses ofnode so it works with both flat and live device trees.
@@ -85,6 +88,8 @@
For example, the old code may be like this:
+.. code-block:: c
+
struct udevice *bus;
const void *blob = gd->fdt_blob;
int node = dev_of_offset(bus);
@@ -94,17 +99,21 @@
The new code is:
+.. code-block:: c
+
struct udevice *bus;
i2c_bus->regs = (struct i2c_ctlr *)dev_read_addr(dev);
plat->frequency = dev_read_u32_default(bus, "spi-max-frequency", 500000);
-The dev_read_...() interface is more convenient and works with both the
+The dev_read\_...() interface is more convenient and works with both the
flat and live device trees. See include/dm/read.h for a list of functions.
Where properties must be read from sub-nodes or other nodes, you must fall
back to using ofnode. For example, for old code like this:
+.. code-block:: c
+
const void *blob = gd->fdt_blob;
int subnode;
@@ -115,6 +124,8 @@
you should use:
+.. code-block:: c
+
ofnode subnode;
ofnode_for_each_subnode(subnode, dev_ofnode(dev)) {
@@ -128,8 +139,8 @@
The internal data structures of the livetree are defined in include/dm/of.h :
- struct device_node - holds information about a device tree node
- struct property - holds information about a property within a node
+ :struct device_node: holds information about a device tree node
+ :struct property: holds information about a property within a node
Nodes have pointers to their first property, their parent, their first child
and their sibling. This allows nodes to be linked together in a hierarchical
@@ -149,20 +160,29 @@
used. Similarly it is not possible to call ofnode_to_offset() on a livetree
node.
- ofnode_to_np() - converts ofnode to struct device_node *
- ofnode_to_offset() - converts ofnode to offset
+ofnode_to_np():
+ converts ofnode to struct device_node *
+ofnode_to_offset():
+ converts ofnode to offset
- no_to_ofnode() - converts node pointer to ofnode
- offset_to_ofnode() - converts offset to ofnode
+no_to_ofnode():
+ converts node pointer to ofnode
+offset_to_ofnode():
+ converts offset to ofnode
Other useful functions:
- of_live_active() returns true if livetree is in use, false if flat tree
- ofnode_valid() return true if a given node is valid
- ofnode_is_np() returns true if a given node is a livetree node
- ofnode_equal() compares two ofnodes
- ofnode_null() returns a null ofnode (for which ofnode_valid() returns false)
+of_live_active():
+ returns true if livetree is in use, false if flat tree
+ofnode_valid():
+ return true if a given node is valid
+ofnode_is_np():
+ returns true if a given node is a livetree node
+ofnode_equal():
+ compares two ofnodes
+ofnode_null():
+ returns a null ofnode (for which ofnode_valid() returns false)
Phandles
@@ -199,13 +219,13 @@
Internal implementation
-----------------------
-The dev_read_...() functions have two implementations. When
+The dev_read\_...() functions have two implementations. When
CONFIG_DM_DEV_READ_INLINE is enabled, these functions simply call the ofnode
functions directly. This is useful when livetree is not enabled. The ofnode
functions call ofnode_is_np(node) which will always return false if livetree
is disabled, just falling back to flat tree code.
-This optimisation means that without livetree enabled, the dev_read_...() and
+This optimisation means that without livetree enabled, the dev_read\_...() and
ofnode interfaces do not noticeably add to code size.
The CONFIG_DM_DEV_READ_INLINE option defaults to enabled when livetree is
@@ -225,7 +245,7 @@
With a flat device tree, libfdt errors are returned (e.g. -FDT_ERR_NOTFOUND).
For livetree normal 'errno' errors are returned (e.g. -ENOTFOUND). At present
-the ofnode and dev_read_...() functions return either one or other type of
+the ofnode and dev_read\_...() functions return either one or other type of
error. This is clearly not desirable. Once tests are added for all the
functions this can be tidied up.
@@ -236,23 +256,22 @@
Adding a new function for device-tree access involves the following steps:
- Add two dev_read() functions:
- - inline version in the read.h header file, which calls an ofnode
- function
- - standard version in the read.c file (or perhaps another file), which
- also calls an ofnode function
+ - inline version in the read.h header file, which calls an ofnode function
+ - standard version in the read.c file (or perhaps another file), which
+ also calls an ofnode function
- The implementations of these functions can be the same. The purpose
- of the inline version is purely to reduce code size impact.
+ The implementations of these functions can be the same. The purpose
+ of the inline version is purely to reduce code size impact.
- Add an ofnode function. This should call ofnode_is_np() to work out
- whether a livetree or flat tree is used. For the livetree it should
- call an of_...() function. For the flat tree it should call an
- fdt_...() function. The livetree version will be optimised out at
- compile time if livetree is not enabled.
+ whether a livetree or flat tree is used. For the livetree it should
+ call an of\_...() function. For the flat tree it should call an
+ fdt\_...() function. The livetree version will be optimised out at
+ compile time if livetree is not enabled.
- - Add an of_...() function for the livetree implementation. If a similar
- function is available in Linux, the implementation should be taken
- from there and modified as little as possible (generally not at all).
+ - Add an of\_...() function for the livetree implementation. If a similar
+ function is available in Linux, the implementation should be taken
+ from there and modified as little as possible (generally not at all).
Future work
@@ -265,8 +284,3 @@
- support for livetree modification
- addition of more access functions as needed
- support for livetree in SPL and before relocation (if desired)
-
-
---
-Simon Glass <sjg@chromium.org>
-5-Aug-17
diff --git a/doc/driver-model/MIGRATION.txt b/doc/driver-model/migration.rst
similarity index 84%
rename from doc/driver-model/MIGRATION.txt
rename to doc/driver-model/migration.rst
index d38be35..a26e7ab 100644
--- a/doc/driver-model/MIGRATION.txt
+++ b/doc/driver-model/migration.rst
@@ -1,5 +1,7 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
Migration Schedule
-====================
+==================
U-Boot has been migrating to a new driver model since its introduction in
2014. This file describes the schedule for deprecation of pre-driver-model
@@ -8,8 +10,8 @@
CONFIG_DM_MMC
-------------
-Status: In progress
-Deadline: 2019.04
+* Status: In progress
+* Deadline: 2019.04
The subsystem itself has been converted and maintainers should submit patches
switching over to using CONFIG_DM_MMC and other base driver model options in
@@ -18,8 +20,8 @@
CONFIG_DM_USB
-------------
-Status: In progress
-Deadline: 2019.07
+* Status: In progress
+* Deadline: 2019.07
The subsystem itself has been converted along with many of the host controller
and maintainers should submit patches switching over to using CONFIG_DM_USB and
@@ -28,8 +30,8 @@
CONFIG_SATA
-----------
-Status: In progress
-Deadline: 2019.07
+* Status: In progress
+* Deadline: 2019.07
The subsystem itself has been converted along with many of the host controller
and maintainers should submit patches switching over to using CONFIG_AHCI and
@@ -38,8 +40,8 @@
CONFIG_BLK
----------
-Status: In progress
-Deadline: 2019.07
+* Status: In progress
+* Deadline: 2019.07
In concert with maintainers migrating their block device usage to the
appropriate DM driver, CONFIG_BLK needs to be set as well. The final deadline
@@ -48,14 +50,14 @@
Kconfig around using CONFIG_PARTITIONS and CONFIG_HAVE_BLOCK_DEVICE and make
use of CONFIG_BLK / CONFIG_SPL_BLK as needed.
-CONFIG_DM_SPI
-CONFIG_DM_SPI_FLASH
--------------------
+CONFIG_DM_SPI / CONFIG_DM_SPI_FLASH
+-----------------------------------
Board Maintainers should submit the patches for enabling DM_SPI and DM_SPI_FLASH
to move the migration with in the deadline.
+No dm conversion yet::
+
-No dm conversion yet:
drivers/spi/cf_spi.c
drivers/spi/fsl_espi.c
drivers/spi/lpc32xx_ssp.c
@@ -63,10 +65,11 @@
drivers/spi/sh_spi.c
drivers/spi/soft_spi_legacy.c
- Status: In progress
- Deadline: 2019.04
+* Status: In progress
+* Deadline: 2019.04
-Partially converted:
+Partially converted::
+
drivers/spi/davinci_spi.c
drivers/spi/fsl_dspi.c
drivers/spi/kirkwood_spi.c
@@ -74,13 +77,8 @@
drivers/spi/omap3_spi.c
drivers/spi/sh_qspi.c
- Status: In progress
- Deadline: 2019.07
-
---
-Jagan Teki <jagan@openedev.com>
-12/24/2018
-03/14/2018
+* Status: In progress
+* Deadline: 2019.07
CONFIG_DM_PCI
diff --git a/doc/driver-model/of-plat.txt b/doc/driver-model/of-plat.rst
similarity index 65%
rename from doc/driver-model/of-plat.txt
rename to doc/driver-model/of-plat.rst
index 0109ec5..0d3cd8c 100644
--- a/doc/driver-model/of-plat.txt
+++ b/doc/driver-model/of-plat.rst
@@ -1,6 +1,8 @@
-Driver Model Compiled-in Device Tree / Platform Data
-====================================================
+.. SPDX-License-Identifier: GPL-2.0+
+Compiled-in Device Tree / Platform Data
+=======================================
+
Introduction
------------
@@ -40,36 +42,36 @@
strictly necessary. Notable problems include:
- Device tree does not describe data types. But the C code must define a
- type for each property. These are guessed using heuristics which
- are wrong in several fairly common cases. For example an 8-byte value
- is considered to be a 2-item integer array, and is byte-swapped. A
- boolean value that is not present means 'false', but cannot be
- included in the structures since there is generally no mention of it
- in the device tree file.
+ type for each property. These are guessed using heuristics which
+ are wrong in several fairly common cases. For example an 8-byte value
+ is considered to be a 2-item integer array, and is byte-swapped. A
+ boolean value that is not present means 'false', but cannot be
+ included in the structures since there is generally no mention of it
+ in the device tree file.
- Naming of nodes and properties is automatic. This means that they follow
- the naming in the device tree, which may result in C identifiers that
- look a bit strange.
+ the naming in the device tree, which may result in C identifiers that
+ look a bit strange.
- It is not possible to find a value given a property name. Code must use
- the associated C member variable directly in the code. This makes
- the code less robust in the face of device-tree changes. It also
- makes it very unlikely that your driver code will be useful for more
- than one SoC. Even if the code is common, each SoC will end up with
- a different C struct name, and a likely a different format for the
- platform data.
+ the associated C member variable directly in the code. This makes
+ the code less robust in the face of device-tree changes. It also
+ makes it very unlikely that your driver code will be useful for more
+ than one SoC. Even if the code is common, each SoC will end up with
+ a different C struct name, and a likely a different format for the
+ platform data.
- The platform data is provided to drivers as a C structure. The driver
- must use the same structure to access the data. Since a driver
- normally also supports device tree it must use #ifdef to separate
- out this code, since the structures are only available in SPL.
+ must use the same structure to access the data. Since a driver
+ normally also supports device tree it must use #ifdef to separate
+ out this code, since the structures are only available in SPL.
- Correct relations between nodes are not implemented. This means that
- parent/child relations (like bus device iteration) do not work yet.
- Some phandles (those that are recognised as such) are converted into
- a pointer to platform data. This pointer can potentially be used to
- access the referenced device (by searching for the pointer value).
- This feature is not yet implemented, however.
+ parent/child relations (like bus device iteration) do not work yet.
+ Some phandles (those that are recognised as such) are converted into
+ a pointer to platform data. This pointer can potentially be used to
+ access the referenced device (by searching for the pointer value).
+ This feature is not yet implemented, however.
How it works
@@ -78,30 +80,34 @@
The feature is enabled by CONFIG OF_PLATDATA. This is only available in
SPL/TPL and should be tested with:
+.. code-block:: c
+
- #if CONFIG_IS_ENABLED(OF_PLATDATA)
+ #if CONFIG_IS_ENABLED(OF_PLATDATA)
A new tool called 'dtoc' converts a device tree file either into a set of
struct declarations, one for each compatible node, and a set of
U_BOOT_DEVICE() declarations along with the actual platform data for each
device. As an example, consider this MMC node:
- sdmmc: dwmmc@ff0c0000 {
- compatible = "rockchip,rk3288-dw-mshc";
- clock-freq-min-max = <400000 150000000>;
- clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
- <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
- fifo-depth = <0x100>;
- interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
- reg = <0xff0c0000 0x4000>;
- bus-width = <4>;
- cap-mmc-highspeed;
- cap-sd-highspeed;
- card-detect-delay = <200>;
- disable-wp;
- num-slots = <1>;
- pinctrl-names = "default";
- pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>;
+.. code-block:: none
+
+ sdmmc: dwmmc@ff0c0000 {
+ compatible = "rockchip,rk3288-dw-mshc";
+ clock-freq-min-max = <400000 150000000>;
+ clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
+ <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
+ clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+ fifo-depth = <0x100>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0xff0c0000 0x4000>;
+ bus-width = <4>;
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
+ card-detect-delay = <200>;
+ disable-wp;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>;
vmmc-supply = <&vcc_sd>;
status = "okay";
u-boot,dm-pre-reloc;
@@ -112,52 +118,59 @@
CONFIG_OF_SPL_REMOVE_PROPS option. The rest are processed. This will produce
the following C struct declaration:
-struct dtd_rockchip_rk3288_dw_mshc {
- fdt32_t bus_width;
- bool cap_mmc_highspeed;
- bool cap_sd_highspeed;
- fdt32_t card_detect_delay;
- fdt32_t clock_freq_min_max[2];
- struct phandle_1_arg clocks[4];
- bool disable_wp;
- fdt32_t fifo_depth;
- fdt32_t interrupts[3];
- fdt32_t num_slots;
- fdt32_t reg[2];
- fdt32_t vmmc_supply;
-};
+.. code-block:: c
+
+ struct dtd_rockchip_rk3288_dw_mshc {
+ fdt32_t bus_width;
+ bool cap_mmc_highspeed;
+ bool cap_sd_highspeed;
+ fdt32_t card_detect_delay;
+ fdt32_t clock_freq_min_max[2];
+ struct phandle_1_arg clocks[4];
+ bool disable_wp;
+ fdt32_t fifo_depth;
+ fdt32_t interrupts[3];
+ fdt32_t num_slots;
+ fdt32_t reg[2];
+ fdt32_t vmmc_supply;
+ };
and the following device declaration:
-static struct dtd_rockchip_rk3288_dw_mshc dtv_dwmmc_at_ff0c0000 = {
- .fifo_depth = 0x100,
- .cap_sd_highspeed = true,
- .interrupts = {0x0, 0x20, 0x4},
- .clock_freq_min_max = {0x61a80, 0x8f0d180},
- .vmmc_supply = 0xb,
- .num_slots = 0x1,
- .clocks = {{&dtv_clock_controller_at_ff760000, 456},
- {&dtv_clock_controller_at_ff760000, 68},
- {&dtv_clock_controller_at_ff760000, 114},
- {&dtv_clock_controller_at_ff760000, 118}},
- .cap_mmc_highspeed = true,
- .disable_wp = true,
- .bus_width = 0x4,
- .u_boot_dm_pre_reloc = true,
- .reg = {0xff0c0000, 0x4000},
- .card_detect_delay = 0xc8,
-};
-U_BOOT_DEVICE(dwmmc_at_ff0c0000) = {
- .name = "rockchip_rk3288_dw_mshc",
- .platdata = &dtv_dwmmc_at_ff0c0000,
- .platdata_size = sizeof(dtv_dwmmc_at_ff0c0000),
-};
+.. code-block:: c
+
+ static struct dtd_rockchip_rk3288_dw_mshc dtv_dwmmc_at_ff0c0000 = {
+ .fifo_depth = 0x100,
+ .cap_sd_highspeed = true,
+ .interrupts = {0x0, 0x20, 0x4},
+ .clock_freq_min_max = {0x61a80, 0x8f0d180},
+ .vmmc_supply = 0xb,
+ .num_slots = 0x1,
+ .clocks = {{&dtv_clock_controller_at_ff760000, 456},
+ {&dtv_clock_controller_at_ff760000, 68},
+ {&dtv_clock_controller_at_ff760000, 114},
+ {&dtv_clock_controller_at_ff760000, 118}},
+ .cap_mmc_highspeed = true,
+ .disable_wp = true,
+ .bus_width = 0x4,
+ .u_boot_dm_pre_reloc = true,
+ .reg = {0xff0c0000, 0x4000},
+ .card_detect_delay = 0xc8,
+ };
+
+ U_BOOT_DEVICE(dwmmc_at_ff0c0000) = {
+ .name = "rockchip_rk3288_dw_mshc",
+ .platdata = &dtv_dwmmc_at_ff0c0000,
+ .platdata_size = sizeof(dtv_dwmmc_at_ff0c0000),
+ };
The device is then instantiated at run-time and the platform data can be
accessed using:
+.. code-block:: c
+
- struct udevice *dev;
- struct dtd_rockchip_rk3288_dw_mshc *plat = dev_get_platdata(dev);
+ struct udevice *dev;
+ struct dtd_rockchip_rk3288_dw_mshc *plat = dev_get_platdata(dev);
This avoids the code overhead of converting the device tree data to
platform data in the driver. The ofdata_to_platdata() method should
@@ -173,8 +186,10 @@
Where a node has multiple compatible strings, a #define is used to make them
equivalent, e.g.:
-#define dtd_rockchip_rk3299_dw_mshc dtd_rockchip_rk3288_dw_mshc
+.. code-block:: c
+ #define dtd_rockchip_rk3299_dw_mshc dtd_rockchip_rk3288_dw_mshc
+
Converting of-platdata to a useful form
---------------------------------------
@@ -204,6 +219,8 @@
For example:
+.. code-block:: c
+
#include <dt-structs.h>
struct mmc_platdata {
@@ -313,12 +330,12 @@
Future work
-----------
- Consider programmatically reading binding files instead of device tree
- contents
+ contents
- Complete the phandle feature
- Move to using a full Python libfdt module
---
-Simon Glass <sjg@chromium.org>
-Google, Inc
-6/6/16
-Updated Independence Day 2016
+
+.. Simon Glass <sjg@chromium.org>
+.. Google, Inc
+.. 6/6/16
+.. Updated Independence Day 2016
diff --git a/doc/driver-model/pci-info.txt b/doc/driver-model/pci-info.rst
similarity index 94%
rename from doc/driver-model/pci-info.txt
rename to doc/driver-model/pci-info.rst
index 14364c5..d93ab8b 100644
--- a/doc/driver-model/pci-info.txt
+++ b/doc/driver-model/pci-info.rst
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
PCI with Driver Model
=====================
@@ -7,8 +9,7 @@
Any config read will end up at pci_read_config(). This uses
uclass_get_device_by_seq() to get the PCI bus for a particular bus number.
Bus number 0 will need to be requested first, and the alias in the device
-tree file will point to the correct device:
-
+tree file will point to the correct device::
aliases {
pci0 = &pci;
@@ -45,7 +46,7 @@
Note we must describe PCI devices with the same bus hierarchy as the
hardware, otherwise driver model cannot detect the correct parent/children
relationship during PCI bus enumeration thus PCI devices won't be bound to
-their drivers accordingly. A working example like below:
+their drivers accordingly. A working example like below::
pci {
#address-cells = <3>;
@@ -113,7 +114,7 @@
With sandbox we need a device emulator for each device on the bus since there
is no real PCI bus. This works by looking in the device tree node for a
-driver. For example:
+driver. For example::
pci@1f,0 {
@@ -129,11 +130,11 @@
PCI_BDF() for the encoding (it is also specified in the IEEE Std 1275-1994
PCI bus binding document, v2.1)
-When this bus is scanned we will end up with something like this:
+When this bus is scanned we will end up with something like this::
-`- * pci-controller @ 05c660c8, 0
- `- pci@1f,0 @ 05c661c8, 63488
- `- emul@1f,0 @ 05c662c8
+ `- * pci-controller @ 05c660c8, 0
+ `- pci@1f,0 @ 05c661c8, 63488
+ `- emul@1f,0 @ 05c662c8
When accesses go to the pci@1f,0 device they are forwarded to its child, the
emulator.
@@ -144,6 +145,8 @@
node. It is required a "sandbox,dev-info" property must be provided in the
host controller node for this functionality to work.
+.. code-block:: none
+
pci1: pci-controller1 {
compatible = "sandbox,pci";
...
@@ -156,7 +159,7 @@
cells are PCI device number and function number respectively. The third and
fourth cells are PCI vendor ID and device ID respectively.
-When this bus is scanned we will end up with something like this:
+When this bus is scanned we will end up with something like this::
pci [ + ] pci_sandbo |-- pci-controller1
pci_emul [ ] sandbox_sw | |-- sandbox_swap_case_emul
diff --git a/doc/driver-model/pmic-framework.rst b/doc/driver-model/pmic-framework.rst
new file mode 100644
index 0000000..d24a1ba
--- /dev/null
+++ b/doc/driver-model/pmic-framework.rst
@@ -0,0 +1,143 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. (C) Copyright 2014-2015 Samsung Electronics
+.. sectionauthor:: Przemyslaw Marczak <p.marczak@samsung.com>
+
+PMIC framework based on Driver Model
+====================================
+
+Introduction
+------------
+This is an introduction to driver-model multi uclass PMIC IC's support.
+At present it's based on two uclass types:
+
+UCLASS_PMIC:
+ basic uclass type for PMIC I/O, which provides common
+ read/write interface.
+UCLASS_REGULATOR:
+ additional uclass type for specific PMIC features, which are
+ Voltage/Current regulators.
+
+New files:
+
+UCLASS_PMIC:
+ - drivers/power/pmic/pmic-uclass.c
+ - include/power/pmic.h
+UCLASS_REGULATOR:
+ - drivers/power/regulator/regulator-uclass.c
+ - include/power/regulator.h
+
+Commands:
+- common/cmd_pmic.c
+- common/cmd_regulator.c
+
+How doees it work
+-----------------
+The Power Management Integrated Circuits (PMIC) are used in embedded systems
+to provide stable, precise and specific voltage power source with over-voltage
+and thermal protection circuits.
+
+The single PMIC can provide various functions by single or multiple interfaces,
+like in the example below::
+
+ -- SoC
+ |
+ | ______________________________________
+ | BUS 0 | Multi interface PMIC IC |--> LDO out 1
+ | e.g.I2C0 | |--> LDO out N
+ |-----------|---- PMIC device 0 (READ/WRITE ops) |
+ | or SPI0 | |_ REGULATOR device (ldo/... ops) |--> BUCK out 1
+ | | |_ CHARGER device (charger ops) |--> BUCK out M
+ | | |_ MUIC device (microUSB con ops) |
+ | BUS 1 | |_ ... |---> BATTERY
+ | e.g.I2C1 | |
+ |-----------|---- PMIC device 1 (READ/WRITE ops) |---> USB in 1
+ . or SPI1 | |_ RTC device (rtc ops) |---> USB in 2
+ . |______________________________________|---> USB out
+ .
+
+Since U-Boot provides driver model features for I2C and SPI bus drivers,
+the PMIC devices should also support this. By the pmic and regulator API's,
+PMIC drivers can simply provide a common functions, for multi-interface and
+and multi-instance device support.
+
+Basic design assumptions:
+
+- Common I/O API:
+ UCLASS_PMIC. For the multi-function PMIC devices, this can be used as
+ parent I/O device for each IC's interface. Then, each children uses the
+ same dev for read/write.
+
+- Common regulator API:
+ UCLASS_REGULATOR. For driving the regulator attributes, auto setting
+ function or command line interface, based on kernel-style regulator device
+ tree constraints.
+
+For simple implementations, regulator drivers are not required, so the code can
+use pmic read/write directly.
+
+Pmic uclass
+-----------
+The basic information:
+
+* Uclass: 'UCLASS_PMIC'
+* Header: 'include/power/pmic.h'
+* Core: 'drivers/power/pmic/pmic-uclass.c' (config 'CONFIG_DM_PMIC')
+* Command: 'common/cmd_pmic.c' (config 'CONFIG_CMD_PMIC')
+* Example: 'drivers/power/pmic/max77686.c'
+
+For detailed API description, please refer to the header file.
+
+As an example of the pmic driver, please refer to the MAX77686 driver.
+
+Please pay attention for the driver's bind() method. Exactly the function call:
+'pmic_bind_children()', which is used to bind the regulators by using the array
+of regulator's node, compatible prefixes.
+
+The 'pmic; command also supports the new API. So the pmic command can be enabled
+by adding CONFIG_CMD_PMIC.
+The new pmic command allows to:
+- list pmic devices
+- choose the current device (like the mmc command)
+- read or write the pmic register
+- dump all pmic registers
+
+This command can use only UCLASS_PMIC devices, since this uclass is designed
+for pmic I/O operations only.
+
+For more information, please refer to the core file.
+
+Regulator uclass
+----------------
+The basic information:
+
+* Uclass: 'UCLASS_REGULATOR'
+
+* Header: 'include/power/regulator.h'
+
+* Core: 'drivers/power/regulator/regulator-uclass.c'
+ (config 'CONFIG_DM_REGULATOR')
+
+* Binding: 'doc/device-tree-bindings/regulator/regulator.txt'
+
+* Command: 'common/cmd_regulator.c' (config 'CONFIG_CMD_REGULATOR')
+
+* Example: 'drivers/power/regulator/max77686.c'
+ 'drivers/power/pmic/max77686.c' (required I/O driver for the above)
+
+* Example: 'drivers/power/regulator/fixed.c'
+ (config 'CONFIG_DM_REGULATOR_FIXED')
+
+For detailed API description, please refer to the header file.
+
+For the example regulator driver, please refer to the MAX77686 regulator driver,
+but this driver can't operate without pmic's example driver, which provides an
+I/O interface for MAX77686 regulator.
+
+The second example is a fixed Voltage/Current regulator for a common use.
+
+The 'regulator' command also supports the new API. The command allow:
+- list regulator devices
+- choose the current device (like the mmc command)
+- do all regulator-specific operations
+
+For more information, please refer to the command file.
diff --git a/doc/driver-model/pmic-framework.txt b/doc/driver-model/pmic-framework.txt
deleted file mode 100644
index 95b1a66..0000000
--- a/doc/driver-model/pmic-framework.txt
+++ /dev/null
@@ -1,140 +0,0 @@
-#
-# (C) Copyright 2014-2015 Samsung Electronics
-# Przemyslaw Marczak <p.marczak@samsung.com>
-#
-# SPDX-License-Identifier: GPL-2.0+
-#
-
-PMIC framework based on Driver Model
-====================================
-TOC:
-1. Introduction
-2. How does it work
-3. Pmic uclass
-4. Regulator uclass
-
-1. Introduction
-===============
-This is an introduction to driver-model multi uclass PMIC IC's support.
-At present it's based on two uclass types:
-- UCLASS_PMIC - basic uclass type for PMIC I/O, which provides common
- read/write interface.
-- UCLASS_REGULATOR - additional uclass type for specific PMIC features,
- which are Voltage/Current regulators.
-
-New files:
-UCLASS_PMIC:
-- drivers/power/pmic/pmic-uclass.c
-- include/power/pmic.h
-UCLASS_REGULATOR:
-- drivers/power/regulator/regulator-uclass.c
-- include/power/regulator.h
-
-Commands:
-- common/cmd_pmic.c
-- common/cmd_regulator.c
-
-2. How doees it work
-====================
-The Power Management Integrated Circuits (PMIC) are used in embedded systems
-to provide stable, precise and specific voltage power source with over-voltage
-and thermal protection circuits.
-
-The single PMIC can provide various functions by single or multiple interfaces,
-like in the example below.
-
--- SoC
- |
- | ______________________________________
- | BUS 0 | Multi interface PMIC IC |--> LDO out 1
- | e.g.I2C0 | |--> LDO out N
- |-----------|---- PMIC device 0 (READ/WRITE ops) |
- | or SPI0 | |_ REGULATOR device (ldo/... ops) |--> BUCK out 1
- | | |_ CHARGER device (charger ops) |--> BUCK out M
- | | |_ MUIC device (microUSB con ops) |
- | BUS 1 | |_ ... |---> BATTERY
- | e.g.I2C1 | |
- |-----------|---- PMIC device 1 (READ/WRITE ops) |---> USB in 1
- . or SPI1 | |_ RTC device (rtc ops) |---> USB in 2
- . |______________________________________|---> USB out
- .
-
-Since U-Boot provides driver model features for I2C and SPI bus drivers,
-the PMIC devices should also support this. By the pmic and regulator API's,
-PMIC drivers can simply provide a common functions, for multi-interface and
-and multi-instance device support.
-
-Basic design assumptions:
-
-- Common I/O API - UCLASS_PMIC
-For the multi-function PMIC devices, this can be used as parent I/O device
-for each IC's interface. Then, each children uses the same dev for read/write.
-
-- Common regulator API - UCLASS_REGULATOR
-For driving the regulator attributes, auto setting function or command line
-interface, based on kernel-style regulator device tree constraints.
-
-For simple implementations, regulator drivers are not required, so the code can
-use pmic read/write directly.
-
-3. Pmic uclass
-==============
-The basic information:
-* Uclass: 'UCLASS_PMIC'
-* Header: 'include/power/pmic.h'
-* Core: 'drivers/power/pmic/pmic-uclass.c'
- config: 'CONFIG_DM_PMIC'
-* Command: 'common/cmd_pmic.c'
- config: 'CONFIG_CMD_PMIC'
-* Example: 'drivers/power/pmic/max77686.c'
-
-For detailed API description, please refer to the header file.
-
-As an example of the pmic driver, please refer to the MAX77686 driver.
-
-Please pay attention for the driver's bind() method. Exactly the function call:
-'pmic_bind_children()', which is used to bind the regulators by using the array
-of regulator's node, compatible prefixes.
-
-The 'pmic; command also supports the new API. So the pmic command can be enabled
-by adding CONFIG_CMD_PMIC.
-The new pmic command allows to:
-- list pmic devices
-- choose the current device (like the mmc command)
-- read or write the pmic register
-- dump all pmic registers
-
-This command can use only UCLASS_PMIC devices, since this uclass is designed
-for pmic I/O operations only.
-
-For more information, please refer to the core file.
-
-4. Regulator uclass
-===================
-The basic information:
-* Uclass: 'UCLASS_REGULATOR'
-* Header: 'include/power/regulator.h'
-* Core: 'drivers/power/regulator/regulator-uclass.c'
- config: 'CONFIG_DM_REGULATOR'
- binding: 'doc/device-tree-bindings/regulator/regulator.txt'
-* Command: 'common/cmd_regulator.c'
- config: 'CONFIG_CMD_REGULATOR'
-* Example: 'drivers/power/regulator/max77686.c'
- 'drivers/power/pmic/max77686.c' (required I/O driver for the above)
-* Example: 'drivers/power/regulator/fixed.c'
- config" 'CONFIG_DM_REGULATOR_FIXED'
-
-For detailed API description, please refer to the header file.
-
-For the example regulator driver, please refer to the MAX77686 regulator driver,
-but this driver can't operate without pmic's example driver, which provides an
-I/O interface for MAX77686 regulator.
-
-The second example is a fixed Voltage/Current regulator for a common use.
-
-The 'regulator' command also supports the new API. The command allow:
-- list regulator devices
-- choose the current device (like the mmc command)
-- do all regulator-specific operations
-
-For more information, please refer to the command file.
diff --git a/doc/driver-model/remoteproc-framework.rst b/doc/driver-model/remoteproc-framework.rst
new file mode 100644
index 0000000..f21de0a
--- /dev/null
+++ b/doc/driver-model/remoteproc-framework.rst
@@ -0,0 +1,169 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. (C) Copyright 2015
+.. Texas Instruments Incorporated - http://www.ti.com/
+
+Remote Processor Framework
+==========================
+
+Introduction
+------------
+
+This is an introduction to driver-model for Remote Processors found
+on various System on Chip(SoCs). The term remote processor is used to
+indicate that this is not the processor on which U-Boot is operating
+on, instead is yet another processing entity that may be controlled by
+the processor on which we are functional.
+
+The simplified model depends on a single UCLASS - UCLASS_REMOTEPROC
+
+UCLASS_REMOTEPROC:
+ - drivers/remoteproc/rproc-uclass.c
+ - include/remoteproc.h
+
+Commands:
+ - common/cmd_remoteproc.c
+
+Configuration:
+ - CONFIG_REMOTEPROC is selected by drivers as needed
+ - CONFIG_CMD_REMOTEPROC for the commands if required.
+
+How does it work - The driver
+-----------------------------
+
+Overall, the driver statemachine transitions are typically as follows::
+
+ (entry)
+ +-------+
+ +---+ init |
+ | | | <---------------------+
+ | +-------+ |
+ | |
+ | |
+ | +--------+ |
+ Load| | reset | |
+ | | | <----------+ |
+ | +--------+ | |
+ | |Load | |
+ | | | |
+ | +----v----+ reset | |
+ +-> | | (opt) | |
+ | Loaded +-----------+ |
+ | | |
+ +----+----+ |
+ | Start |
+ +---v-----+ (opt) |
+ +->| Running | Stop |
+ Ping +- | +--------------------+
+ (opt) +---------+
+
+(is_running does not change state)
+opt: Optional state transition implemented by driver.
+
+NOTE: It depends on the remote processor as to the exact behavior
+of the statemachine, remoteproc core does not intent to implement
+statemachine logic. Certain processors may allow start/stop without
+reloading the image in the middle, certain other processors may only
+allow us to start the processor(image from a EEPROM/OTP) etc.
+
+It is hence the responsibility of the driver to handle the requisite
+state transitions of the device as necessary.
+
+Basic design assumptions:
+
+Remote processor can operate on a certain firmware that maybe loaded
+and released from reset.
+
+The driver follows a standard UCLASS DM.
+
+in the bare minimum form:
+
+.. code-block:: c
+
+ static const struct dm_rproc_ops sandbox_testproc_ops = {
+ .load = sandbox_testproc_load,
+ .start = sandbox_testproc_start,
+ };
+
+ static const struct udevice_id sandbox_ids[] = {
+ {.compatible = "sandbox,test-processor"},
+ {}
+ };
+
+ U_BOOT_DRIVER(sandbox_testproc) = {
+ .name = "sandbox_test_proc",
+ .of_match = sandbox_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &sandbox_testproc_ops,
+ .probe = sandbox_testproc_probe,
+ };
+
+This allows for the device to be probed as part of the "init" command
+or invocation of 'rproc_init()' function as the system dependencies define.
+
+The driver is expected to maintain it's own statemachine which is
+appropriate for the device it maintains. It must, at the very least
+provide a load and start function. We assume here that the device
+needs to be loaded and started, else, there is no real purpose of
+using the remoteproc framework.
+
+Describing the device using platform data
+-----------------------------------------
+
+*IMPORTANT* NOTE: THIS SUPPORT IS NOT MEANT FOR USE WITH NEWER PLATFORM
+SUPPORT. THIS IS ONLY FOR LEGACY DEVICES. THIS MODE OF INITIALIZATION
+*WILL* BE EVENTUALLY REMOVED ONCE ALL NECESSARY PLATFORMS HAVE MOVED
+TO DM/FDT.
+
+Considering that many platforms are yet to move to device-tree model,
+a simplified definition of a device is as follows:
+
+.. code-block:: c
+
+ struct dm_rproc_uclass_pdata proc_3_test = {
+ .name = "proc_3_legacy",
+ .mem_type = RPROC_INTERNAL_MEMORY_MAPPED,
+ .driver_plat_data = &mydriver_data;
+ };
+
+ U_BOOT_DEVICE(proc_3_demo) = {
+ .name = "sandbox_test_proc",
+ .platdata = &proc_3_test,
+ };
+
+There can be additional data that may be desired depending on the
+remoteproc driver specific needs (for example: SoC integration
+details such as clock handle or something similar). See appropriate
+documentation for specific remoteproc driver for further details.
+These are passed via driver_plat_data.
+
+Describing the device using device tree
+---------------------------------------
+
+.. code-block: none
+
+ / {
+ ...
+ aliases {
+ ...
+ remoteproc0 = &rproc_1;
+ remoteproc1 = &rproc_2;
+
+ };
+ ...
+
+ rproc_1: rproc@1 {
+ compatible = "sandbox,test-processor";
+ remoteproc-name = "remoteproc-test-dev1";
+ };
+
+ rproc_2: rproc@2 {
+ compatible = "sandbox,test-processor";
+ internal-memory-mapped;
+ remoteproc-name = "remoteproc-test-dev2";
+ };
+ ...
+ };
+
+aliases usage is optional, but it is usually recommended to ensure the
+users have a consistent usage model for a platform.
+the compatible string used here is specific to the remoteproc driver involved.
diff --git a/doc/driver-model/remoteproc-framework.txt b/doc/driver-model/remoteproc-framework.txt
deleted file mode 100644
index c6dc00d..0000000
--- a/doc/driver-model/remoteproc-framework.txt
+++ /dev/null
@@ -1,168 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+
-#
-# (C) Copyright 2015
-# Texas Instruments Incorporated - http://www.ti.com/
-#
-
-Remote Processor Framework
-==========================
-TOC:
-1. Introduction
-2. How does it work - The driver
-3. Describing the device using platform data
-4. Describing the device using device tree
-
-1. Introduction
-===============
-
-This is an introduction to driver-model for Remote Processors found
-on various System on Chip(SoCs). The term remote processor is used to
-indicate that this is not the processor on which U-Boot is operating
-on, instead is yet another processing entity that may be controlled by
-the processor on which we are functional.
-
-The simplified model depends on a single UCLASS - UCLASS_REMOTEPROC
-
-UCLASS_REMOTEPROC:
-- drivers/remoteproc/rproc-uclass.c
-- include/remoteproc.h
-
-Commands:
-- common/cmd_remoteproc.c
-
-Configuration:
-CONFIG_REMOTEPROC is selected by drivers as needed
-CONFIG_CMD_REMOTEPROC for the commands if required.
-
-2. How does it work - The driver
-=================================
-
-Overall, the driver statemachine transitions are typically as follows:
- (entry)
- +-------+
- +---+ init |
- | | | <---------------------+
- | +-------+ |
- | |
- | |
- | +--------+ |
-Load| | reset | |
- | | | <----------+ |
- | +--------+ | |
- | |Load | |
- | | | |
- | +----v----+ reset | |
- +-> | | (opt) | |
- | Loaded +-----------+ |
- | | |
- +----+----+ |
- | Start |
- +---v-----+ (opt) |
- +->| Running | Stop |
-Ping +- | +--------------------+
-(opt) +---------+
-
-(is_running does not change state)
-opt: Optional state transition implemented by driver.
-
-NOTE: It depends on the remote processor as to the exact behavior
-of the statemachine, remoteproc core does not intent to implement
-statemachine logic. Certain processors may allow start/stop without
-reloading the image in the middle, certain other processors may only
-allow us to start the processor(image from a EEPROM/OTP) etc.
-
-It is hence the responsibility of the driver to handle the requisite
-state transitions of the device as necessary.
-
-Basic design assumptions:
-
-Remote processor can operate on a certain firmware that maybe loaded
-and released from reset.
-
-The driver follows a standard UCLASS DM.
-
-in the bare minimum form:
-
-static const struct dm_rproc_ops sandbox_testproc_ops = {
- .load = sandbox_testproc_load,
- .start = sandbox_testproc_start,
-};
-
-static const struct udevice_id sandbox_ids[] = {
- {.compatible = "sandbox,test-processor"},
- {}
-};
-
-U_BOOT_DRIVER(sandbox_testproc) = {
- .name = "sandbox_test_proc",
- .of_match = sandbox_ids,
- .id = UCLASS_REMOTEPROC,
- .ops = &sandbox_testproc_ops,
- .probe = sandbox_testproc_probe,
-};
-
-This allows for the device to be probed as part of the "init" command
-or invocation of 'rproc_init()' function as the system dependencies define.
-
-The driver is expected to maintain it's own statemachine which is
-appropriate for the device it maintains. It must, at the very least
-provide a load and start function. We assume here that the device
-needs to be loaded and started, else, there is no real purpose of
-using the remoteproc framework.
-
-3. Describing the device using platform data
-============================================
-
-*IMPORTANT* NOTE: THIS SUPPORT IS NOT MEANT FOR USE WITH NEWER PLATFORM
-SUPPORT. THIS IS ONLY FOR LEGACY DEVICES. THIS MODE OF INITIALIZATION
-*WILL* BE EVENTUALLY REMOVED ONCE ALL NECESSARY PLATFORMS HAVE MOVED
-TO DM/FDT.
-
-Considering that many platforms are yet to move to device-tree model,
-a simplified definition of a device is as follows:
-
-struct dm_rproc_uclass_pdata proc_3_test = {
- .name = "proc_3_legacy",
- .mem_type = RPROC_INTERNAL_MEMORY_MAPPED,
- .driver_plat_data = &mydriver_data;
-};
-
-U_BOOT_DEVICE(proc_3_demo) = {
- .name = "sandbox_test_proc",
- .platdata = &proc_3_test,
-};
-
-There can be additional data that may be desired depending on the
-remoteproc driver specific needs (for example: SoC integration
-details such as clock handle or something similar). See appropriate
-documentation for specific remoteproc driver for further details.
-These are passed via driver_plat_data.
-
-3. Describing the device using device tree
-==========================================
-/ {
- ...
- aliases {
- ...
- remoteproc0 = &rproc_1;
- remoteproc1 = &rproc_2;
-
- };
- ...
-
- rproc_1: rproc@1 {
- compatible = "sandbox,test-processor";
- remoteproc-name = "remoteproc-test-dev1";
- };
-
- rproc_2: rproc@2 {
- compatible = "sandbox,test-processor";
- internal-memory-mapped;
- remoteproc-name = "remoteproc-test-dev2";
- };
- ...
-};
-
-aliases usage is optional, but it is usually recommended to ensure the
-users have a consistent usage model for a platform.
-the compatible string used here is specific to the remoteproc driver involved.
diff --git a/doc/driver-model/serial-howto.txt b/doc/driver-model/serial-howto.rst
similarity index 92%
rename from doc/driver-model/serial-howto.txt
rename to doc/driver-model/serial-howto.rst
index a0df9a7..1469131 100644
--- a/doc/driver-model/serial-howto.txt
+++ b/doc/driver-model/serial-howto.rst
@@ -1,11 +1,13 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
How to port a serial driver to driver model
===========================================
Almost all of the serial drivers have been converted as at January 2016. These
ones remain:
- serial_bfin.c
- serial_pxa.c
+ * serial_bfin.c
+ * serial_pxa.c
The deadline for this work was the end of January 2016. If no one steps
forward to convert these, at some point there may come a patch to remove them!
@@ -17,14 +19,14 @@
- Define CONFIG_DM_SERIAL for your board, vendor or architecture
- If the board does not already use driver model, you need CONFIG_DM also
- Your board should then build, but will not boot since there will be no serial
- driver
+ driver
- Add the U_BOOT_DRIVER piece at the end (e.g. copy serial_s5p.c for example)
- Add a private struct for the driver data - avoid using static variables
- Implement each of the driver methods, perhaps by calling your old methods
- You may need to adjust the function parameters so that the old and new
- implementations can share most of the existing code
+ implementations can share most of the existing code
- If you convert all existing users of the driver, remove the pre-driver-model
- code
+ code
In terms of patches a conversion series typically has these patches:
- clean up / prepare the driver for conversion
diff --git a/doc/driver-model/spi-howto.rst b/doc/driver-model/spi-howto.rst
new file mode 100644
index 0000000..a538fdc
--- /dev/null
+++ b/doc/driver-model/spi-howto.rst
@@ -0,0 +1,692 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+How to port a SPI driver to driver model
+========================================
+
+Here is a rough step-by-step guide. It is based around converting the
+exynos SPI driver to driver model (DM) and the example code is based
+around U-Boot v2014.10-rc2 (commit be9f643). This has been updated for
+v2015.04.
+
+It is quite long since it includes actual code examples.
+
+Before driver model, SPI drivers have their own private structure which
+contains 'struct spi_slave'. With driver model, 'struct spi_slave' still
+exists, but now it is 'per-child data' for the SPI bus. Each child of the
+SPI bus is a SPI slave. The information that was stored in the
+driver-specific slave structure can now be port in private data for the
+SPI bus.
+
+For example, struct tegra_spi_slave looks like this:
+
+.. code-block:: c
+
+ struct tegra_spi_slave {
+ struct spi_slave slave;
+ struct tegra_spi_ctrl *ctrl;
+ };
+
+In this case 'slave' will be in per-child data, and 'ctrl' will be in the
+SPI's buses private data.
+
+
+How long does this take?
+------------------------
+
+You should be able to complete this within 2 hours, including testing but
+excluding preparing the patches. The API is basically the same as before
+with only minor changes:
+
+- methods to set speed and mode are separated out
+- cs_info is used to get information on a chip select
+
+
+Enable driver mode for SPI and SPI flash
+----------------------------------------
+
+Add these to your board config:
+
+* CONFIG_DM_SPI
+* CONFIG_DM_SPI_FLASH
+
+
+Add the skeleton
+----------------
+
+Put this code at the bottom of your existing driver file:
+
+.. code-block:: c
+
+ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+ {
+ return NULL;
+ }
+
+ struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
+ int spi_node)
+ {
+ return NULL;
+ }
+
+ static int exynos_spi_ofdata_to_platdata(struct udevice *dev)
+ {
+ return -ENODEV;
+ }
+
+ static int exynos_spi_probe(struct udevice *dev)
+ {
+ return -ENODEV;
+ }
+
+ static int exynos_spi_remove(struct udevice *dev)
+ {
+ return -ENODEV;
+ }
+
+ static int exynos_spi_claim_bus(struct udevice *dev)
+ {
+
+ return -ENODEV;
+ }
+
+ static int exynos_spi_release_bus(struct udevice *dev)
+ {
+
+ return -ENODEV;
+ }
+
+ static int exynos_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+ {
+
+ return -ENODEV;
+ }
+
+ static int exynos_spi_set_speed(struct udevice *dev, uint speed)
+ {
+ return -ENODEV;
+ }
+
+ static int exynos_spi_set_mode(struct udevice *dev, uint mode)
+ {
+ return -ENODEV;
+ }
+
+ static int exynos_cs_info(struct udevice *bus, uint cs,
+ struct spi_cs_info *info)
+ {
+ return -ENODEV;
+ }
+
+ static const struct dm_spi_ops exynos_spi_ops = {
+ .claim_bus = exynos_spi_claim_bus,
+ .release_bus = exynos_spi_release_bus,
+ .xfer = exynos_spi_xfer,
+ .set_speed = exynos_spi_set_speed,
+ .set_mode = exynos_spi_set_mode,
+ .cs_info = exynos_cs_info,
+ };
+
+ static const struct udevice_id exynos_spi_ids[] = {
+ { .compatible = "samsung,exynos-spi" },
+ { }
+ };
+
+ U_BOOT_DRIVER(exynos_spi) = {
+ .name = "exynos_spi",
+ .id = UCLASS_SPI,
+ .of_match = exynos_spi_ids,
+ .ops = &exynos_spi_ops,
+ .ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
+ .probe = exynos_spi_probe,
+ .remove = exynos_spi_remove,
+ };
+
+
+Replace 'exynos' in the above code with your driver name
+--------------------------------------------------------
+
+
+#ifdef out all of the code in your driver except for the above
+--------------------------------------------------------------
+
+This will allow you to get it building, which means you can work
+incrementally. Since all the methods return an error initially, there is
+less chance that you will accidentally leave something in.
+
+Also, even though your conversion is basically a rewrite, it might help
+reviewers if you leave functions in the same place in the file,
+particularly for large drivers.
+
+
+Add some includes
+-----------------
+
+Add these includes to your driver:
+
+.. code-block:: c
+
+ #include <dm.h>
+ #include <errno.h>
+
+
+Build
+-----
+
+At this point you should be able to build U-Boot for your board with the
+empty SPI driver. You still have empty methods in your driver, but we will
+write these one by one.
+
+Set up your platform data structure
+-----------------------------------
+
+This will hold the information your driver to operate, like its hardware
+address or maximum frequency.
+
+You may already have a struct like this, or you may need to create one
+from some of the #defines or global variables in the driver.
+
+Note that this information is not the run-time information. It should not
+include state that changes. It should be fixed throughout the live of
+U-Boot. Run-time information comes later.
+
+Here is what was in the exynos spi driver:
+
+.. code-block:: c
+
+ struct spi_bus {
+ enum periph_id periph_id;
+ s32 frequency; /* Default clock frequency, -1 for none */
+ struct exynos_spi *regs;
+ int inited; /* 1 if this bus is ready for use */
+ int node;
+ uint deactivate_delay_us; /* Delay to wait after deactivate */
+ };
+
+Of these, inited is handled by DM and node is the device tree node, which
+DM tells you. The name is not quite right. So in this case we would use:
+
+.. code-block:: c
+
+ struct exynos_spi_platdata {
+ enum periph_id periph_id;
+ s32 frequency; /* Default clock frequency, -1 for none */
+ struct exynos_spi *regs;
+ uint deactivate_delay_us; /* Delay to wait after deactivate */
+ };
+
+
+Write ofdata_to_platdata() [for device tree only]
+-------------------------------------------------
+
+This method will convert information in the device tree node into a C
+structure in your driver (called platform data). If you are not using
+device tree, go to 8b.
+
+DM will automatically allocate the struct for us when we are using device
+tree, but we need to tell it the size:
+
+.. code-block:: c
+
+ U_BOOT_DRIVER(spi_exynos) = {
+ ...
+ .platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
+
+
+Here is a sample function. It gets a pointer to the platform data and
+fills in the fields from device tree.
+
+.. code-block:: c
+
+ static int exynos_spi_ofdata_to_platdata(struct udevice *bus)
+ {
+ struct exynos_spi_platdata *plat = bus->platdata;
+ const void *blob = gd->fdt_blob;
+ int node = dev_of_offset(bus);
+
+ plat->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
+ plat->periph_id = pinmux_decode_periph_id(blob, node);
+
+ if (plat->periph_id == PERIPH_ID_NONE) {
+ debug("%s: Invalid peripheral ID %d\n", __func__,
+ plat->periph_id);
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /* Use 500KHz as a suitable default */
+ plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+ 500000);
+ plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+ "spi-deactivate-delay", 0);
+ debug("%s: regs=%p, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+ __func__, plat->regs, plat->periph_id, plat->frequency,
+ plat->deactivate_delay_us);
+
+ return 0;
+ }
+
+
+Add the platform data [non-device-tree only]
+--------------------------------------------
+
+Specify this data in a U_BOOT_DEVICE() declaration in your board file:
+
+.. code-block:: c
+
+ struct exynos_spi_platdata platdata_spi0 = {
+ .periph_id = ...
+ .frequency = ...
+ .regs = ...
+ .deactivate_delay_us = ...
+ };
+
+ U_BOOT_DEVICE(board_spi0) = {
+ .name = "exynos_spi",
+ .platdata = &platdata_spi0,
+ };
+
+You will unfortunately need to put the struct definition into a header file
+in this case so that your board file can use it.
+
+
+Add the device private data
+---------------------------
+
+Most devices have some private data which they use to keep track of things
+while active. This is the run-time information and needs to be stored in
+a structure. There is probably a structure in the driver that includes a
+'struct spi_slave', so you can use that.
+
+.. code-block:: c
+
+ struct exynos_spi_slave {
+ struct spi_slave slave;
+ struct exynos_spi *regs;
+ unsigned int freq; /* Default frequency */
+ unsigned int mode;
+ enum periph_id periph_id; /* Peripheral ID for this device */
+ unsigned int fifo_size;
+ int skip_preamble;
+ struct spi_bus *bus; /* Pointer to our SPI bus info */
+ ulong last_transaction_us; /* Time of last transaction end */
+ };
+
+
+We should rename this to make its purpose more obvious, and get rid of
+the slave structure, so we have:
+
+.. code-block:: c
+
+ struct exynos_spi_priv {
+ struct exynos_spi *regs;
+ unsigned int freq; /* Default frequency */
+ unsigned int mode;
+ enum periph_id periph_id; /* Peripheral ID for this device */
+ unsigned int fifo_size;
+ int skip_preamble;
+ ulong last_transaction_us; /* Time of last transaction end */
+ };
+
+
+DM can auto-allocate this also:
+
+.. code-block:: c
+
+ U_BOOT_DRIVER(spi_exynos) = {
+ ...
+ .priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
+
+
+Note that this is created before the probe method is called, and destroyed
+after the remove method is called. It will be zeroed when the probe
+method is called.
+
+
+Add the probe() and remove() methods
+------------------------------------
+
+Note: It's a good idea to build repeatedly as you are working, to avoid a
+huge amount of work getting things compiling at the end.
+
+The probe method is supposed to set up the hardware. U-Boot used to use
+spi_setup_slave() to do this. So take a look at this function and see
+what you can copy out to set things up.
+
+.. code-block:: c
+
+ static int exynos_spi_probe(struct udevice *bus)
+ {
+ struct exynos_spi_platdata *plat = dev_get_platdata(bus);
+ struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+ priv->regs = plat->regs;
+ if (plat->periph_id == PERIPH_ID_SPI1 ||
+ plat->periph_id == PERIPH_ID_SPI2)
+ priv->fifo_size = 64;
+ else
+ priv->fifo_size = 256;
+
+ priv->skip_preamble = 0;
+ priv->last_transaction_us = timer_get_us();
+ priv->freq = plat->frequency;
+ priv->periph_id = plat->periph_id;
+
+ return 0;
+ }
+
+This implementation doesn't actually touch the hardware, which is somewhat
+unusual for a driver. In this case we will do that when the device is
+claimed by something that wants to use the SPI bus.
+
+For remove we could shut down the clocks, but in this case there is
+nothing to do. DM frees any memory that it allocated, so we can just
+remove exynos_spi_remove() and its reference in U_BOOT_DRIVER.
+
+
+Implement set_speed()
+---------------------
+
+This should set up clocks so that the SPI bus is running at the right
+speed. With the old API spi_claim_bus() would normally do this and several
+of the following functions, so let's look at that function:
+
+.. code-block:: c
+
+ int spi_claim_bus(struct spi_slave *slave)
+ {
+ struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
+ struct exynos_spi *regs = spi_slave->regs;
+ u32 reg = 0;
+ int ret;
+
+ ret = set_spi_clk(spi_slave->periph_id,
+ spi_slave->freq);
+ if (ret < 0) {
+ debug("%s: Failed to setup spi clock\n", __func__);
+ return ret;
+ }
+
+ exynos_pinmux_config(spi_slave->periph_id, PINMUX_FLAG_NONE);
+
+ spi_flush_fifo(slave);
+
+ reg = readl(®s->ch_cfg);
+ reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
+
+ if (spi_slave->mode & SPI_CPHA)
+ reg |= SPI_CH_CPHA_B;
+
+ if (spi_slave->mode & SPI_CPOL)
+ reg |= SPI_CH_CPOL_L;
+
+ writel(reg, ®s->ch_cfg);
+ writel(SPI_FB_DELAY_180, ®s->fb_clk);
+
+ return 0;
+ }
+
+
+It sets up the speed, mode, pinmux, feedback delay and clears the FIFOs.
+With DM these will happen in separate methods.
+
+
+Here is an example for the speed part:
+
+.. code-block:: c
+
+ static int exynos_spi_set_speed(struct udevice *bus, uint speed)
+ {
+ struct exynos_spi_platdata *plat = bus->platdata;
+ struct exynos_spi_priv *priv = dev_get_priv(bus);
+ int ret;
+
+ if (speed > plat->frequency)
+ speed = plat->frequency;
+ ret = set_spi_clk(priv->periph_id, speed);
+ if (ret)
+ return ret;
+ priv->freq = speed;
+ debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
+ return 0;
+ }
+
+
+Implement set_mode()
+--------------------
+
+This should adjust the SPI mode (polarity, etc.). Again this code probably
+comes from the old spi_claim_bus(). Here is an example:
+
+.. code-block:: c
+
+ static int exynos_spi_set_mode(struct udevice *bus, uint mode)
+ {
+ struct exynos_spi_priv *priv = dev_get_priv(bus);
+ uint32_t reg;
+
+ reg = readl(&priv->regs->ch_cfg);
+ reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
+
+ if (mode & SPI_CPHA)
+ reg |= SPI_CH_CPHA_B;
+
+ if (mode & SPI_CPOL)
+ reg |= SPI_CH_CPOL_L;
+
+ writel(reg, &priv->regs->ch_cfg);
+ priv->mode = mode;
+ debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+ return 0;
+ }
+
+
+Implement claim_bus()
+---------------------
+
+This is where a client wants to make use of the bus, so claims it first.
+At this point we need to make sure everything is set up ready for data
+transfer. Note that this function is wholly internal to the driver - at
+present the SPI uclass never calls it.
+
+Here again we look at the old claim function and see some code that is
+needed. It is anything unrelated to speed and mode:
+
+.. code-block:: c
+
+ static int exynos_spi_claim_bus(struct udevice *bus)
+ {
+ struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+ exynos_pinmux_config(priv->periph_id, PINMUX_FLAG_NONE);
+ spi_flush_fifo(priv->regs);
+
+ writel(SPI_FB_DELAY_180, &priv->regs->fb_clk);
+
+ return 0;
+ }
+
+The spi_flush_fifo() function is in the removed part of the code, so we
+need to expose it again (perhaps with an #endif before it and '#if 0'
+after it). It only needs access to priv->regs which is why we have
+passed that in:
+
+.. code-block:: c
+
+ /**
+ * Flush spi tx, rx fifos and reset the SPI controller
+ *
+ * @param regs Pointer to SPI registers
+ */
+ static void spi_flush_fifo(struct exynos_spi *regs)
+ {
+ clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
+ clrbits_le32(®s->ch_cfg, SPI_CH_RST);
+ setbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
+ }
+
+
+Implement release_bus()
+-----------------------
+
+This releases the bus - in our example the old code in spi_release_bus()
+is a call to spi_flush_fifo, so we add:
+
+.. code-block:: c
+
+ static int exynos_spi_release_bus(struct udevice *bus)
+ {
+ struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+ spi_flush_fifo(priv->regs);
+
+ return 0;
+ }
+
+
+Implement xfer()
+----------------
+
+This is the final method that we need to create, and it is where all the
+work happens. The method parameters are the same as the old spi_xfer() with
+the addition of a 'struct udevice' so conversion is pretty easy. Start
+by copying the contents of spi_xfer() to your new xfer() method and proceed
+from there.
+
+If (flags & SPI_XFER_BEGIN) is non-zero then xfer() normally calls an
+activate function, something like this:
+
+.. code-block:: c
+
+ void spi_cs_activate(struct spi_slave *slave)
+ {
+ struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
+
+ /* If it's too soon to do another transaction, wait */
+ if (spi_slave->bus->deactivate_delay_us &&
+ spi_slave->last_transaction_us) {
+ ulong delay_us; /* The delay completed so far */
+ delay_us = timer_get_us() - spi_slave->last_transaction_us;
+ if (delay_us < spi_slave->bus->deactivate_delay_us)
+ udelay(spi_slave->bus->deactivate_delay_us - delay_us);
+ }
+
+ clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+ debug("Activate CS, bus %d\n", spi_slave->slave.bus);
+ spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
+ }
+
+The new version looks like this:
+
+.. code-block:: c
+
+ static void spi_cs_activate(struct udevice *dev)
+ {
+ struct udevice *bus = dev->parent;
+ struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
+ struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+ /* If it's too soon to do another transaction, wait */
+ if (pdata->deactivate_delay_us &&
+ priv->last_transaction_us) {
+ ulong delay_us; /* The delay completed so far */
+ delay_us = timer_get_us() - priv->last_transaction_us;
+ if (delay_us < pdata->deactivate_delay_us)
+ udelay(pdata->deactivate_delay_us - delay_us);
+ }
+
+ clrbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+ debug("Activate CS, bus '%s'\n", bus->name);
+ priv->skip_preamble = priv->mode & SPI_PREAMBLE;
+ }
+
+All we have really done here is change the pointers and print the device name
+instead of the bus number. Other local static functions can be treated in
+the same way.
+
+
+Set up the per-child data and child pre-probe function
+------------------------------------------------------
+
+To minimise the pain and complexity of the SPI subsystem while the driver
+model change-over is in place, struct spi_slave is used to reference a
+SPI bus slave, even though that slave is actually a struct udevice. In fact
+struct spi_slave is the device's child data. We need to make sure this space
+is available. It is possible to allocate more space that struct spi_slave
+needs, but this is the minimum.
+
+.. code-block:: c
+
+ U_BOOT_DRIVER(exynos_spi) = {
+ ...
+ .per_child_auto_alloc_size = sizeof(struct spi_slave),
+ }
+
+
+Optional: Set up cs_info() if you want it
+-----------------------------------------
+
+Sometimes it is useful to know whether a SPI chip select is valid, but this
+is not obvious from outside the driver. In this case you can provide a
+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.
+
+
+Test it
+-------
+
+Now that you have the code written and it compiles, try testing it using
+the 'sf test' command. You may need to enable CONFIG_CMD_SF_TEST for your
+board.
+
+
+Prepare patches and send them to the mailing lists
+--------------------------------------------------
+
+You can use 'tools/patman/patman' to prepare, check and send patches for
+your work. See the README for details.
+
+A little note about SPI uclass features
+---------------------------------------
+
+The SPI uclass keeps some information about each device 'dev' on the bus:
+
+ struct dm_spi_slave_platdata:
+ This is device_get_parent_platdata(dev).
+ This is where the chip select number is stored, along with
+ the default bus speed and mode. It is automatically read
+ from the device tree in spi_child_post_bind(). It must not
+ be changed at run-time after being set up because platform
+ data is supposed to be immutable at run-time.
+ struct spi_slave:
+ This is device_get_parentdata(dev).
+ Already mentioned above. It holds run-time information about
+ the device.
+
+There are also some SPI uclass methods that get called behind the scenes:
+
+ spi_post_bind():
+ Called when a new bus is bound.
+ This scans the device tree for devices on the bus, and binds
+ each one. This in turn causes spi_child_post_bind() to be
+ called for each, which reads the device tree information
+ into the parent (per-child) platform data.
+ spi_child_post_bind():
+ Called when a new child is bound.
+ As mentioned above this reads the device tree information
+ into the per-child platform data
+ spi_child_pre_probe():
+ Called before a new child is probed.
+ This sets up the mode and speed in struct spi_slave by
+ copying it from the parent's platform data for this child.
+ It also sets the 'dev' pointer, needed to permit passing
+ 'struct spi_slave' around the place without needing a
+ separate 'struct udevice' pointer.
+
+The above housekeeping makes it easier to write your SPI driver.
diff --git a/doc/driver-model/spi-howto.txt b/doc/driver-model/spi-howto.txt
deleted file mode 100644
index 38c26f6..0000000
--- a/doc/driver-model/spi-howto.txt
+++ /dev/null
@@ -1,623 +0,0 @@
-How to port a SPI driver to driver model
-========================================
-
-Here is a rough step-by-step guide. It is based around converting the
-exynos SPI driver to driver model (DM) and the example code is based
-around U-Boot v2014.10-rc2 (commit be9f643). This has been updated for
-v2015.04.
-
-It is quite long since it includes actual code examples.
-
-Before driver model, SPI drivers have their own private structure which
-contains 'struct spi_slave'. With driver model, 'struct spi_slave' still
-exists, but now it is 'per-child data' for the SPI bus. Each child of the
-SPI bus is a SPI slave. The information that was stored in the
-driver-specific slave structure can now be port in private data for the
-SPI bus.
-
-For example, struct tegra_spi_slave looks like this:
-
-struct tegra_spi_slave {
- struct spi_slave slave;
- struct tegra_spi_ctrl *ctrl;
-};
-
-In this case 'slave' will be in per-child data, and 'ctrl' will be in the
-SPI's buses private data.
-
-
-0. How long does this take?
-
-You should be able to complete this within 2 hours, including testing but
-excluding preparing the patches. The API is basically the same as before
-with only minor changes:
-
-- methods to set speed and mode are separated out
-- cs_info is used to get information on a chip select
-
-
-1. Enable driver mode for SPI and SPI flash
-
-Add these to your board config:
-
-CONFIG_DM_SPI
-CONFIG_DM_SPI_FLASH
-
-
-2. Add the skeleton
-
-Put this code at the bottom of your existing driver file:
-
-struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- return NULL;
-}
-
-struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
- int spi_node)
-{
- return NULL;
-}
-
-static int exynos_spi_ofdata_to_platdata(struct udevice *dev)
-{
- return -ENODEV;
-}
-
-static int exynos_spi_probe(struct udevice *dev)
-{
- return -ENODEV;
-}
-
-static int exynos_spi_remove(struct udevice *dev)
-{
- return -ENODEV;
-}
-
-static int exynos_spi_claim_bus(struct udevice *dev)
-{
-
- return -ENODEV;
-}
-
-static int exynos_spi_release_bus(struct udevice *dev)
-{
-
- return -ENODEV;
-}
-
-static int exynos_spi_xfer(struct udevice *dev, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
-{
-
- return -ENODEV;
-}
-
-static int exynos_spi_set_speed(struct udevice *dev, uint speed)
-{
- return -ENODEV;
-}
-
-static int exynos_spi_set_mode(struct udevice *dev, uint mode)
-{
- return -ENODEV;
-}
-
-static int exynos_cs_info(struct udevice *bus, uint cs,
- struct spi_cs_info *info)
-{
- return -ENODEV;
-}
-
-static const struct dm_spi_ops exynos_spi_ops = {
- .claim_bus = exynos_spi_claim_bus,
- .release_bus = exynos_spi_release_bus,
- .xfer = exynos_spi_xfer,
- .set_speed = exynos_spi_set_speed,
- .set_mode = exynos_spi_set_mode,
- .cs_info = exynos_cs_info,
-};
-
-static const struct udevice_id exynos_spi_ids[] = {
- { .compatible = "samsung,exynos-spi" },
- { }
-};
-
-U_BOOT_DRIVER(exynos_spi) = {
- .name = "exynos_spi",
- .id = UCLASS_SPI,
- .of_match = exynos_spi_ids,
- .ops = &exynos_spi_ops,
- .ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
- .probe = exynos_spi_probe,
- .remove = exynos_spi_remove,
-};
-
-
-3. Replace 'exynos' in the above code with your driver name
-
-
-4. #ifdef out all of the code in your driver except for the above
-
-This will allow you to get it building, which means you can work
-incrementally. Since all the methods return an error initially, there is
-less chance that you will accidentally leave something in.
-
-Also, even though your conversion is basically a rewrite, it might help
-reviewers if you leave functions in the same place in the file,
-particularly for large drivers.
-
-
-5. Add some includes
-
-Add these includes to your driver:
-
-#include <dm.h>
-#include <errno.h>
-
-
-6. Build
-
-At this point you should be able to build U-Boot for your board with the
-empty SPI driver. You still have empty methods in your driver, but we will
-write these one by one.
-
-7. Set up your platform data structure
-
-This will hold the information your driver to operate, like its hardware
-address or maximum frequency.
-
-You may already have a struct like this, or you may need to create one
-from some of the #defines or global variables in the driver.
-
-Note that this information is not the run-time information. It should not
-include state that changes. It should be fixed throughout the live of
-U-Boot. Run-time information comes later.
-
-Here is what was in the exynos spi driver:
-
-struct spi_bus {
- enum periph_id periph_id;
- s32 frequency; /* Default clock frequency, -1 for none */
- struct exynos_spi *regs;
- int inited; /* 1 if this bus is ready for use */
- int node;
- uint deactivate_delay_us; /* Delay to wait after deactivate */
-};
-
-Of these, inited is handled by DM and node is the device tree node, which
-DM tells you. The name is not quite right. So in this case we would use:
-
-struct exynos_spi_platdata {
- enum periph_id periph_id;
- s32 frequency; /* Default clock frequency, -1 for none */
- struct exynos_spi *regs;
- uint deactivate_delay_us; /* Delay to wait after deactivate */
-};
-
-
-8a. Write ofdata_to_platdata() [for device tree only]
-
-This method will convert information in the device tree node into a C
-structure in your driver (called platform data). If you are not using
-device tree, go to 8b.
-
-DM will automatically allocate the struct for us when we are using device
-tree, but we need to tell it the size:
-
-U_BOOT_DRIVER(spi_exynos) = {
-...
- .platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
-
-
-Here is a sample function. It gets a pointer to the platform data and
-fills in the fields from device tree.
-
-static int exynos_spi_ofdata_to_platdata(struct udevice *bus)
-{
- struct exynos_spi_platdata *plat = bus->platdata;
- const void *blob = gd->fdt_blob;
- int node = dev_of_offset(bus);
-
- plat->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
- plat->periph_id = pinmux_decode_periph_id(blob, node);
-
- if (plat->periph_id == PERIPH_ID_NONE) {
- debug("%s: Invalid peripheral ID %d\n", __func__,
- plat->periph_id);
- return -FDT_ERR_NOTFOUND;
- }
-
- /* Use 500KHz as a suitable default */
- plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
- 500000);
- plat->deactivate_delay_us = fdtdec_get_int(blob, node,
- "spi-deactivate-delay", 0);
- debug("%s: regs=%p, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
- __func__, plat->regs, plat->periph_id, plat->frequency,
- plat->deactivate_delay_us);
-
- return 0;
-}
-
-
-8b. Add the platform data [non-device-tree only]
-
-Specify this data in a U_BOOT_DEVICE() declaration in your board file:
-
-struct exynos_spi_platdata platdata_spi0 = {
- .periph_id = ...
- .frequency = ...
- .regs = ...
- .deactivate_delay_us = ...
-};
-
-U_BOOT_DEVICE(board_spi0) = {
- .name = "exynos_spi",
- .platdata = &platdata_spi0,
-};
-
-You will unfortunately need to put the struct definition into a header file
-in this case so that your board file can use it.
-
-
-9. Add the device private data
-
-Most devices have some private data which they use to keep track of things
-while active. This is the run-time information and needs to be stored in
-a structure. There is probably a structure in the driver that includes a
-'struct spi_slave', so you can use that.
-
-struct exynos_spi_slave {
- struct spi_slave slave;
- struct exynos_spi *regs;
- unsigned int freq; /* Default frequency */
- unsigned int mode;
- enum periph_id periph_id; /* Peripheral ID for this device */
- unsigned int fifo_size;
- int skip_preamble;
- struct spi_bus *bus; /* Pointer to our SPI bus info */
- ulong last_transaction_us; /* Time of last transaction end */
-};
-
-
-We should rename this to make its purpose more obvious, and get rid of
-the slave structure, so we have:
-
-struct exynos_spi_priv {
- struct exynos_spi *regs;
- unsigned int freq; /* Default frequency */
- unsigned int mode;
- enum periph_id periph_id; /* Peripheral ID for this device */
- unsigned int fifo_size;
- int skip_preamble;
- ulong last_transaction_us; /* Time of last transaction end */
-};
-
-
-DM can auto-allocate this also:
-
-U_BOOT_DRIVER(spi_exynos) = {
-...
- .priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
-
-
-Note that this is created before the probe method is called, and destroyed
-after the remove method is called. It will be zeroed when the probe
-method is called.
-
-
-10. Add the probe() and remove() methods
-
-Note: It's a good idea to build repeatedly as you are working, to avoid a
-huge amount of work getting things compiling at the end.
-
-The probe method is supposed to set up the hardware. U-Boot used to use
-spi_setup_slave() to do this. So take a look at this function and see
-what you can copy out to set things up.
-
-
-static int exynos_spi_probe(struct udevice *bus)
-{
- struct exynos_spi_platdata *plat = dev_get_platdata(bus);
- struct exynos_spi_priv *priv = dev_get_priv(bus);
-
- priv->regs = plat->regs;
- if (plat->periph_id == PERIPH_ID_SPI1 ||
- plat->periph_id == PERIPH_ID_SPI2)
- priv->fifo_size = 64;
- else
- priv->fifo_size = 256;
-
- priv->skip_preamble = 0;
- priv->last_transaction_us = timer_get_us();
- priv->freq = plat->frequency;
- priv->periph_id = plat->periph_id;
-
- return 0;
-}
-
-This implementation doesn't actually touch the hardware, which is somewhat
-unusual for a driver. In this case we will do that when the device is
-claimed by something that wants to use the SPI bus.
-
-For remove we could shut down the clocks, but in this case there is
-nothing to do. DM frees any memory that it allocated, so we can just
-remove exynos_spi_remove() and its reference in U_BOOT_DRIVER.
-
-
-11. Implement set_speed()
-
-This should set up clocks so that the SPI bus is running at the right
-speed. With the old API spi_claim_bus() would normally do this and several
-of the following functions, so let's look at that function:
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
- struct exynos_spi *regs = spi_slave->regs;
- u32 reg = 0;
- int ret;
-
- ret = set_spi_clk(spi_slave->periph_id,
- spi_slave->freq);
- if (ret < 0) {
- debug("%s: Failed to setup spi clock\n", __func__);
- return ret;
- }
-
- exynos_pinmux_config(spi_slave->periph_id, PINMUX_FLAG_NONE);
-
- spi_flush_fifo(slave);
-
- reg = readl(®s->ch_cfg);
- reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
-
- if (spi_slave->mode & SPI_CPHA)
- reg |= SPI_CH_CPHA_B;
-
- if (spi_slave->mode & SPI_CPOL)
- reg |= SPI_CH_CPOL_L;
-
- writel(reg, ®s->ch_cfg);
- writel(SPI_FB_DELAY_180, ®s->fb_clk);
-
- return 0;
-}
-
-
-It sets up the speed, mode, pinmux, feedback delay and clears the FIFOs.
-With DM these will happen in separate methods.
-
-
-Here is an example for the speed part:
-
-static int exynos_spi_set_speed(struct udevice *bus, uint speed)
-{
- struct exynos_spi_platdata *plat = bus->platdata;
- struct exynos_spi_priv *priv = dev_get_priv(bus);
- int ret;
-
- if (speed > plat->frequency)
- speed = plat->frequency;
- ret = set_spi_clk(priv->periph_id, speed);
- if (ret)
- return ret;
- priv->freq = speed;
- debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
-
- return 0;
-}
-
-
-12. Implement set_mode()
-
-This should adjust the SPI mode (polarity, etc.). Again this code probably
-comes from the old spi_claim_bus(). Here is an example:
-
-
-static int exynos_spi_set_mode(struct udevice *bus, uint mode)
-{
- struct exynos_spi_priv *priv = dev_get_priv(bus);
- uint32_t reg;
-
- reg = readl(&priv->regs->ch_cfg);
- reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
-
- if (mode & SPI_CPHA)
- reg |= SPI_CH_CPHA_B;
-
- if (mode & SPI_CPOL)
- reg |= SPI_CH_CPOL_L;
-
- writel(reg, &priv->regs->ch_cfg);
- priv->mode = mode;
- debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
-
- return 0;
-}
-
-
-13. Implement claim_bus()
-
-This is where a client wants to make use of the bus, so claims it first.
-At this point we need to make sure everything is set up ready for data
-transfer. Note that this function is wholly internal to the driver - at
-present the SPI uclass never calls it.
-
-Here again we look at the old claim function and see some code that is
-needed. It is anything unrelated to speed and mode:
-
-static int exynos_spi_claim_bus(struct udevice *bus)
-{
- struct exynos_spi_priv *priv = dev_get_priv(bus);
-
- exynos_pinmux_config(priv->periph_id, PINMUX_FLAG_NONE);
- spi_flush_fifo(priv->regs);
-
- writel(SPI_FB_DELAY_180, &priv->regs->fb_clk);
-
- return 0;
-}
-
-The spi_flush_fifo() function is in the removed part of the code, so we
-need to expose it again (perhaps with an #endif before it and '#if 0'
-after it). It only needs access to priv->regs which is why we have
-passed that in:
-
-/**
- * Flush spi tx, rx fifos and reset the SPI controller
- *
- * @param regs Pointer to SPI registers
- */
-static void spi_flush_fifo(struct exynos_spi *regs)
-{
- clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
- clrbits_le32(®s->ch_cfg, SPI_CH_RST);
- setbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
-}
-
-
-14. Implement release_bus()
-
-This releases the bus - in our example the old code in spi_release_bus()
-is a call to spi_flush_fifo, so we add:
-
-static int exynos_spi_release_bus(struct udevice *bus)
-{
- struct exynos_spi_priv *priv = dev_get_priv(bus);
-
- spi_flush_fifo(priv->regs);
-
- return 0;
-}
-
-
-15. Implement xfer()
-
-This is the final method that we need to create, and it is where all the
-work happens. The method parameters are the same as the old spi_xfer() with
-the addition of a 'struct udevice' so conversion is pretty easy. Start
-by copying the contents of spi_xfer() to your new xfer() method and proceed
-from there.
-
-If (flags & SPI_XFER_BEGIN) is non-zero then xfer() normally calls an
-activate function, something like this:
-
-void spi_cs_activate(struct spi_slave *slave)
-{
- struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
-
- /* If it's too soon to do another transaction, wait */
- if (spi_slave->bus->deactivate_delay_us &&
- spi_slave->last_transaction_us) {
- ulong delay_us; /* The delay completed so far */
- delay_us = timer_get_us() - spi_slave->last_transaction_us;
- if (delay_us < spi_slave->bus->deactivate_delay_us)
- udelay(spi_slave->bus->deactivate_delay_us - delay_us);
- }
-
- clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
- debug("Activate CS, bus %d\n", spi_slave->slave.bus);
- spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
-}
-
-The new version looks like this:
-
-static void spi_cs_activate(struct udevice *dev)
-{
- struct udevice *bus = dev->parent;
- struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
- struct exynos_spi_priv *priv = dev_get_priv(bus);
-
- /* If it's too soon to do another transaction, wait */
- if (pdata->deactivate_delay_us &&
- priv->last_transaction_us) {
- ulong delay_us; /* The delay completed so far */
- delay_us = timer_get_us() - priv->last_transaction_us;
- if (delay_us < pdata->deactivate_delay_us)
- udelay(pdata->deactivate_delay_us - delay_us);
- }
-
- clrbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
- debug("Activate CS, bus '%s'\n", bus->name);
- priv->skip_preamble = priv->mode & SPI_PREAMBLE;
-}
-
-All we have really done here is change the pointers and print the device name
-instead of the bus number. Other local static functions can be treated in
-the same way.
-
-
-16. Set up the per-child data and child pre-probe function
-
-To minimise the pain and complexity of the SPI subsystem while the driver
-model change-over is in place, struct spi_slave is used to reference a
-SPI bus slave, even though that slave is actually a struct udevice. In fact
-struct spi_slave is the device's child data. We need to make sure this space
-is available. It is possible to allocate more space that struct spi_slave
-needs, but this is the minimum.
-
-U_BOOT_DRIVER(exynos_spi) = {
-...
- .per_child_auto_alloc_size = sizeof(struct spi_slave),
-}
-
-
-17. Optional: Set up cs_info() if you want it
-
-Sometimes it is useful to know whether a SPI chip select is valid, but this
-is not obvious from outside the driver. In this case you can provide a
-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.
-
-
-18. Test it
-
-Now that you have the code written and it compiles, try testing it using
-the 'sf test' command. You may need to enable CONFIG_CMD_SF_TEST for your
-board.
-
-
-19. Prepare patches and send them to the mailing lists
-
-You can use 'tools/patman/patman' to prepare, check and send patches for
-your work. See the README for details.
-
-20. A little note about SPI uclass features:
-
-The SPI uclass keeps some information about each device 'dev' on the bus:
-
- struct dm_spi_slave_platdata - this is device_get_parent_platdata(dev)
- This is where the chip select number is stored, along with
- the default bus speed and mode. It is automatically read
- from the device tree in spi_child_post_bind(). It must not
- be changed at run-time after being set up because platform
- data is supposed to be immutable at run-time.
- struct spi_slave - this is device_get_parentdata(dev)
- Already mentioned above. It holds run-time information about
- the device.
-
-There are also some SPI uclass methods that get called behind the scenes:
-
- spi_post_bind() - called when a new bus is bound
- This scans the device tree for devices on the bus, and binds
- each one. This in turn causes spi_child_post_bind() to be
- called for each, which reads the device tree information
- into the parent (per-child) platform data.
- spi_child_post_bind() - called when a new child is bound
- As mentioned above this reads the device tree information
- into the per-child platform data
- spi_child_pre_probe() - called before a new child is probed
- This sets up the mode and speed in struct spi_slave by
- copying it from the parent's platform data for this child.
- It also sets the 'dev' pointer, needed to permit passing
- 'struct spi_slave' around the place without needing a
- separate 'struct udevice' pointer.
-
-The above housekeeping makes it easier to write your SPI driver.
diff --git a/doc/driver-model/usb-info.txt b/doc/driver-model/usb-info.rst
similarity index 76%
rename from doc/driver-model/usb-info.txt
rename to doc/driver-model/usb-info.rst
index e07e5ba..1817df4 100644
--- a/doc/driver-model/usb-info.txt
+++ b/doc/driver-model/usb-info.rst
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
How USB works with driver model
===============================
@@ -24,25 +26,27 @@
So far OHCI is not supported. Both EHCI and XHCI drivers should be declared
as drivers in the USB uclass. For example:
-static const struct udevice_id ehci_usb_ids[] = {
- { .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 },
- { .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 },
- { .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 },
- { }
-};
+.. code-block:: c
-U_BOOT_DRIVER(usb_ehci) = {
- .name = "ehci_tegra",
- .id = UCLASS_USB,
- .of_match = ehci_usb_ids,
- .ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
- .probe = tegra_ehci_usb_probe,
- .remove = tegra_ehci_usb_remove,
- .ops = &ehci_usb_ops,
- .platdata_auto_alloc_size = sizeof(struct usb_platdata),
- .priv_auto_alloc_size = sizeof(struct fdt_usb),
- .flags = DM_FLAG_ALLOC_PRIV_DMA,
-};
+ static const struct udevice_id ehci_usb_ids[] = {
+ { .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 },
+ { .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 },
+ { .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 },
+ { }
+ };
+
+ U_BOOT_DRIVER(usb_ehci) = {
+ .name = "ehci_tegra",
+ .id = UCLASS_USB,
+ .of_match = ehci_usb_ids,
+ .ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
+ .probe = tegra_ehci_usb_probe,
+ .remove = tegra_ehci_usb_remove,
+ .ops = &ehci_usb_ops,
+ .platdata_auto_alloc_size = sizeof(struct usb_platdata),
+ .priv_auto_alloc_size = sizeof(struct fdt_usb),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+ };
Here ehci_usb_ids is used to list the controllers that the driver supports.
Each has its own data value. Controllers must be in the UCLASS_USB uclass.
@@ -80,7 +84,7 @@
The following primary data structures are in use:
-- struct usb_device
+- struct usb_device:
This holds information about a device on the bus. All devices have
this structure, even the root hub. The controller itself does not
have this structure. You can access it for a device 'dev' with
@@ -89,19 +93,19 @@
handles that). Once the device is set up, you can find the device
descriptor and current configuration descriptor in this structure.
-- struct usb_platdata
+- struct usb_platdata:
This holds platform data for a controller. So far this is only used
as a work-around for controllers which can act as USB devices in OTG
mode, since the gadget framework does not use driver model.
-- struct usb_dev_platdata
+- struct usb_dev_platdata:
This holds platform data for a device. You can access it for a
device 'dev' with dev_get_parent_platdata(dev). It holds the device
address and speed - anything that can be determined before the device
driver is actually set up. When probing the bus this structure is
used to provide essential information to the device driver.
-- struct usb_bus_priv
+- struct usb_bus_priv:
This is private information for each controller, maintained by the
controller uclass. It is mostly used to keep track of the next
device address to use.
@@ -197,49 +201,49 @@
- This calls usb_init() which works through each controller in turn
- The controller is probed(). This does no enumeration.
- Then usb_scan_bus() is called. This calls usb_scan_device() to scan the
-(only) device that is attached to the controller - a root hub
+ (only) device that is attached to the controller - a root hub
- usb_scan_device() sets up a fake struct usb_device and calls
-usb_setup_device(), passing the port number to be scanned, in this case port
-0
+ usb_setup_device(), passing the port number to be scanned, in this case
+ port 0
- usb_setup_device() first calls usb_prepare_device() to set the device
-address, then usb_select_config() to select the first configuration
+ address, then usb_select_config() to select the first configuration
- at this point the device is enumerated but we do not have a real struct
-udevice for it. But we do have the descriptor in struct usb_device so we can
-use this to figure out what driver to use
+ udevice for it. But we do have the descriptor in struct usb_device so we can
+ use this to figure out what driver to use
- back in usb_scan_device(), we call usb_find_child() to try to find an
-existing device which matches the one we just found on the bus. This can
-happen if the device is mentioned in the device tree, or if we previously
-scanned the bus and so the device was created before
+ existing device which matches the one we just found on the bus. This can
+ happen if the device is mentioned in the device tree, or if we previously
+ scanned the bus and so the device was created before
- if usb_find_child() does not find an existing device, we call
-usb_find_and_bind_driver() which tries to bind one
+ usb_find_and_bind_driver() which tries to bind one
- usb_find_and_bind_driver() searches all available USB drivers (declared
-with USB_DEVICE()). If it finds a match it binds that driver to create a new
-device.
+ with USB_DEVICE()). If it finds a match it binds that driver to create a
+ new device.
- If it does not, it binds a generic driver. A generic driver is good enough
-to allow access to the device (sending it packets, etc.) but all
-functionality will need to be implemented outside the driver model.
+ to allow access to the device (sending it packets, etc.) but all
+ functionality will need to be implemented outside the driver model.
- in any case, when usb_find_child() and/or usb_find_and_bind_driver() are
-done, we have a device with the correct uclass. At this point we want to
-probe the device
+ done, we have a device with the correct uclass. At this point we want to
+ probe the device
- first we store basic information about the new device (address, port,
-speed) in its parent platform data. We cannot store it its private data
-since that will not exist until the device is probed.
+ speed) in its parent platform data. We cannot store it its private data
+ since that will not exist until the device is probed.
- then we call device_probe() which probes the device
- the first probe step is actually the USB controller's (or USB hubs's)
-child_pre_probe() method. This gets called before anything else and is
-intended to set up a child device ready to be used with its parent bus. For
-USB this calls usb_child_pre_probe() which grabs the information that was
-stored in the parent platform data and stores it in the parent private data
-(which is struct usb_device, a real one this time). It then calls
-usb_select_config() again to make sure that everything about the device is
-set up
+ child_pre_probe() method. This gets called before anything else and is
+ intended to set up a child device ready to be used with its parent bus. For
+ USB this calls usb_child_pre_probe() which grabs the information that was
+ stored in the parent platform data and stores it in the parent private data
+ (which is struct usb_device, a real one this time). It then calls
+ usb_select_config() again to make sure that everything about the device is
+ set up
- note that we have called usb_select_config() twice. This is inefficient
-but the alternative is to store additional information in the platform data.
-The time taken is minimal and this way is simpler
+ but the alternative is to store additional information in the platform data.
+ The time taken is minimal and this way is simpler
- at this point the device is set up and ready for use so far as the USB
-subsystem is concerned
+ subsystem is concerned
- the device's probe() method is then called. It can send messages and do
-whatever else it wants to make the device work.
+ whatever else it wants to make the device work.
Note that the first device is always a root hub, and this must be scanned to
find any devices. The above steps will have created a hub (UCLASS_USB_HUB),
@@ -250,25 +254,25 @@
usb_hub_post_probe() is called, and the following steps take place:
- usb_hub_post_probe() calls usb_hub_scan() to scan the hub, which in turn
-calls usb_hub_configure()
+ calls usb_hub_configure()
- hub power is enabled
- we loop through each port on the hub, performing the same steps for each
- first, check if there is a device present. This happens in
-usb_hub_port_connect_change(). If so, then usb_scan_device() is called to
-scan the device, passing the appropriate port number.
+ usb_hub_port_connect_change(). If so, then usb_scan_device() is called to
+ scan the device, passing the appropriate port number.
- you will recognise usb_scan_device() from the steps above. It sets up the
-device ready for use. If it is a hub, it will scan that hub before it
-continues here (recursively, depth-first)
+ device ready for use. If it is a hub, it will scan that hub before it
+ continues here (recursively, depth-first)
- once all hub ports are scanned in this way, the hub is ready for use and
-all of its downstream devices also
+ all of its downstream devices also
- additional controllers are scanned in the same way
The above method has some nice properties:
- the bus enumeration happens by virtue of driver model's natural device flow
- most logic is in the USB controller and hub uclasses; the actual device
-drivers do not need to know they are on a USB bus, at least so far as
-enumeration goes
+ drivers do not need to know they are on a USB bus, at least so far as
+ enumeration goes
- hub scanning happens automatically after a hub is probed
@@ -279,9 +283,9 @@
uclass, they share some common elements with controllers:
- they both attach private data to their children (struct usb_device,
-accessible for a child with dev_get_parent_priv(child))
+ accessible for a child with dev_get_parent_priv(child))
- they both use usb_child_pre_probe() to set up their children as proper USB
-devices
+ devices
Example - Mass Storage
@@ -290,20 +294,22 @@
As an example of a USB device driver, see usb_storage.c. It uses its own
uclass and declares itself as follows:
-U_BOOT_DRIVER(usb_mass_storage) = {
- .name = "usb_mass_storage",
- .id = UCLASS_MASS_STORAGE,
- .of_match = usb_mass_storage_ids,
- .probe = usb_mass_storage_probe,
-};
+.. code-block:: c
-static const struct usb_device_id mass_storage_id_table[] = {
- { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE},
- { } /* Terminating entry */
-};
+ U_BOOT_DRIVER(usb_mass_storage) = {
+ .name = "usb_mass_storage",
+ .id = UCLASS_MASS_STORAGE,
+ .of_match = usb_mass_storage_ids,
+ .probe = usb_mass_storage_probe,
+ };
-USB_DEVICE(usb_mass_storage, mass_storage_id_table);
+ static const struct usb_device_id mass_storage_id_table[] = {
+ { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE},
+ { } /* Terminating entry */
+ };
+
+ USB_DEVICE(usb_mass_storage, mass_storage_id_table);
The USB_DEVICE() macro attaches the given table of matching information to
the given driver. Note that the driver is declared in U_BOOT_DRIVER() as
@@ -347,6 +353,8 @@
Here is an example device tree fragment:
+.. code-block:: none
+
usb@1 {
compatible = "sandbox,usb";
hub {
@@ -369,13 +377,13 @@
The hub is emulated by a hub emulator, and the emulated hub has a single
flash stick to emulate on one of its ports.
-When 'usb start' is used, the following 'dm tree' output will be available:
+When 'usb start' is used, the following 'dm tree' output will be available::
- usb [ + ] `-- usb@1
- usb_hub [ + ] `-- hub
- usb_emul [ + ] |-- hub-emul
- usb_emul [ + ] | `-- flash-stick
- usb_mass_st [ + ] `-- usb_mass_storage
+ usb [ + ] `-- usb@1
+ usb_hub [ + ] `-- hub
+ usb_emul [ + ] |-- hub-emul
+ usb_emul [ + ] | `-- flash-stick
+ usb_mass_st [ + ] `-- usb_mass_storage
This may look confusing. Most of it mirrors the device tree, but the
@@ -393,12 +401,12 @@
it would be possible to speed up enumeration in two ways:
- breadth-first search would allow devices to be reset and probed in
-parallel to some extent
+ parallel to some extent
- enumeration could be lazy, in the sense that we could enumerate just the
-root hub at first, then only progress to the next 'level' when a device is
-used that we cannot find. This could be made easier if the devices were
-statically declared in the device tree (which is acceptable for production
-boards where the same, known, things are on each bus).
+ root hub at first, then only progress to the next 'level' when a device is
+ used that we cannot find. This could be made easier if the devices were
+ statically declared in the device tree (which is acceptable for production
+ boards where the same, known, things are on each bus).
But in common cases the current algorithm is sufficient.
@@ -410,6 +418,6 @@
- Implement USB PHYs in driver model
- Work out a clever way to provide lazy init for USB devices
---
-Simon Glass <sjg@chromium.org>
-23-Mar-15
+
+.. Simon Glass <sjg@chromium.org>
+.. 23-Mar-15
diff --git a/doc/efi.rst b/doc/efi.rst
deleted file mode 100644
index 5337a55..0000000
--- a/doc/efi.rst
+++ /dev/null
@@ -1,22 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0+
-
-EFI subsystem
-=============
-
-Boot services
--------------
-
-.. kernel-doc:: lib/efi_loader/efi_boottime.c
- :internal:
-
-Image relocation
-~~~~~~~~~~~~~~~~
-
-.. kernel-doc:: lib/efi_loader/efi_image_loader.c
- :internal:
-
-Runtime services
-----------------
-
-.. kernel-doc:: lib/efi_loader/efi_runtime.c
- :internal:
diff --git a/doc/index.rst b/doc/index.rst
index 0353c10..9ae2e16 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -1,11 +1,68 @@
.. SPDX-License-Identifier: GPL-2.0+
-#######################
-U-Boot Developer Manual
-#######################
+.. _u-boot_doc:
+
+The U-Boot Documentation
+========================
+
+This is the top level of the U-Boot's documentation tree. U-Boot
+documentation, like the U-Boot itself, is very much a work in progress;
+that is especially true as we work to integrate our many scattered
+documents into a coherent whole. Please note that improvements to the
+documentation are welcome; join the U-Boot list at http://lists.denx.de
+if you want to help out.
+
+.. toctree::
+ :maxdepth: 2
+
+Driver-Model documentation
+--------------------------
+The following holds information on the U-Boot device driver framework:
+driver-model, including the design details of itself and several driver
+subsystems.
+
+.. toctree::
+ :maxdepth: 2
+
+ driver-model/index
+
+U-Boot API documentation
+------------------------
+
+These books get into the details of how specific U-Boot subsystems work
+from the point of view of a U-Boot developer. Much of the information here
+is taken directly from the U-Boot source, with supplemental material added
+as needed (or at least as we managed to add it - probably *not* all that is
+needed).
+
+.. toctree::
+ :maxdepth: 2
+
+ api/index
+
+Architecture-specific doc
+-------------------------
+
+These books provide programming details about architecture-specific
+implementation.
.. toctree::
+ :maxdepth: 2
+
+ arch/index
+
+Board-specific doc
+------------------
+
+These books provide details about board-specific information. They are
+organized in a vendor subdirectory.
+
+.. toctree::
+ :maxdepth: 2
+
+ board/index
+
+Indices and tables
+==================
- efi
- linker_lists
- serial
+* :ref:`genindex`
diff --git a/doc/sphinx/kerneldoc.py b/doc/sphinx/kerneldoc.py
index fbedcc3..e536360 100644
--- a/doc/sphinx/kerneldoc.py
+++ b/doc/sphinx/kerneldoc.py
@@ -39,6 +39,8 @@
from docutils.parsers.rst import directives, Directive
from sphinx.ext.autodoc import AutodocReporter
+import kernellog
+
__version__ = '1.0'
class KernelDocDirective(Directive):
@@ -86,7 +88,8 @@
cmd += [filename]
try:
- env.app.verbose('calling kernel-doc \'%s\'' % (" ".join(cmd)))
+ kernellog.verbose(env.app,
+ 'calling kernel-doc \'%s\'' % (" ".join(cmd)))
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
@@ -96,7 +99,8 @@
if p.returncode != 0:
sys.stderr.write(err)
- env.app.warn('kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode))
+ kernellog.warn(env.app,
+ 'kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode))
return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
elif env.config.kerneldoc_verbosity > 0:
sys.stderr.write(err)
@@ -128,8 +132,8 @@
return node.children
except Exception as e: # pylint: disable=W0703
- env.app.warn('kernel-doc \'%s\' processing failed with: %s' %
- (" ".join(cmd), str(e)))
+ kernellog.warn(env.app, 'kernel-doc \'%s\' processing failed with: %s' %
+ (" ".join(cmd), str(e)))
return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
def setup(app):
diff --git a/doc/sphinx/kernellog.py b/doc/sphinx/kernellog.py
new file mode 100644
index 0000000..af924f5
--- /dev/null
+++ b/doc/sphinx/kernellog.py
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Sphinx has deprecated its older logging interface, but the replacement
+# only goes back to 1.6. So here's a wrapper layer to keep around for
+# as long as we support 1.4.
+#
+import sphinx
+
+if sphinx.__version__[:3] >= '1.6':
+ UseLogging = True
+ from sphinx.util import logging
+ logger = logging.getLogger('kerneldoc')
+else:
+ UseLogging = False
+
+def warn(app, message):
+ if UseLogging:
+ logger.warning(message)
+ else:
+ app.warn(message)
+
+def verbose(app, message):
+ if UseLogging:
+ logger.verbose(message)
+ else:
+ app.verbose(message)
+
+
diff --git a/doc/sphinx/kfigure.py b/doc/sphinx/kfigure.py
index b97228d..fbfe669 100644
--- a/doc/sphinx/kfigure.py
+++ b/doc/sphinx/kfigure.py
@@ -60,6 +60,8 @@
from sphinx.util.nodes import clean_astext
from six import iteritems
+import kernellog
+
PY3 = sys.version_info[0] == 3
if PY3:
@@ -171,20 +173,20 @@
This function is called once, when the builder is initiated.
"""
global dot_cmd, convert_cmd # pylint: disable=W0603
- app.verbose("kfigure: check installed tools ...")
+ kernellog.verbose(app, "kfigure: check installed tools ...")
dot_cmd = which('dot')
convert_cmd = which('convert')
if dot_cmd:
- app.verbose("use dot(1) from: " + dot_cmd)
+ kernellog.verbose(app, "use dot(1) from: " + dot_cmd)
else:
- app.warn("dot(1) not found, for better output quality install "
- "graphviz from http://www.graphviz.org")
+ kernellog.warn(app, "dot(1) not found, for better output quality install "
+ "graphviz from http://www.graphviz.org")
if convert_cmd:
- app.verbose("use convert(1) from: " + convert_cmd)
+ kernellog.verbose(app, "use convert(1) from: " + convert_cmd)
else:
- app.warn(
+ kernellog.warn(app,
"convert(1) not found, for SVG to PDF conversion install "
"ImageMagick (https://www.imagemagick.org)")
@@ -220,12 +222,13 @@
# in kernel builds, use 'make SPHINXOPTS=-v' to see verbose messages
- app.verbose('assert best format for: ' + img_node['uri'])
+ kernellog.verbose(app, 'assert best format for: ' + img_node['uri'])
if in_ext == '.dot':
if not dot_cmd:
- app.verbose("dot from graphviz not available / include DOT raw.")
+ kernellog.verbose(app,
+ "dot from graphviz not available / include DOT raw.")
img_node.replace_self(file2literal(src_fname))
elif translator.builder.format == 'latex':
@@ -252,7 +255,8 @@
if translator.builder.format == 'latex':
if convert_cmd is None:
- app.verbose("no SVG to PDF conversion available / include SVG raw.")
+ kernellog.verbose(app,
+ "no SVG to PDF conversion available / include SVG raw.")
img_node.replace_self(file2literal(src_fname))
else:
dst_fname = path.join(translator.builder.outdir, fname + '.pdf')
@@ -265,18 +269,19 @@
_name = dst_fname[len(translator.builder.outdir) + 1:]
if isNewer(dst_fname, src_fname):
- app.verbose("convert: {out}/%s already exists and is newer" % _name)
+ kernellog.verbose(app,
+ "convert: {out}/%s already exists and is newer" % _name)
else:
ok = False
mkdir(path.dirname(dst_fname))
if in_ext == '.dot':
- app.verbose('convert DOT to: {out}/' + _name)
+ kernellog.verbose(app, 'convert DOT to: {out}/' + _name)
ok = dot2format(app, src_fname, dst_fname)
elif in_ext == '.svg':
- app.verbose('convert SVG to: {out}/' + _name)
+ kernellog.verbose(app, 'convert SVG to: {out}/' + _name)
ok = svg2pdf(app, src_fname, dst_fname)
if not ok:
@@ -305,7 +310,8 @@
with open(out_fname, "w") as out:
exit_code = subprocess.call(cmd, stdout = out)
if exit_code != 0:
- app.warn("Error #%d when calling: %s" % (exit_code, " ".join(cmd)))
+ kernellog.warn(app,
+ "Error #%d when calling: %s" % (exit_code, " ".join(cmd)))
return bool(exit_code == 0)
def svg2pdf(app, svg_fname, pdf_fname):
@@ -322,7 +328,7 @@
# use stdout and stderr from parent
exit_code = subprocess.call(cmd)
if exit_code != 0:
- app.warn("Error #%d when calling: %s" % (exit_code, " ".join(cmd)))
+ kernellog.warn(app, "Error #%d when calling: %s" % (exit_code, " ".join(cmd)))
return bool(exit_code == 0)
@@ -415,15 +421,15 @@
app = self.builder.app
srclang = node.get('srclang')
- app.verbose('visit kernel-render node lang: "%s"' % (srclang))
+ kernellog.verbose(app, 'visit kernel-render node lang: "%s"' % (srclang))
tmp_ext = RENDER_MARKUP_EXT.get(srclang, None)
if tmp_ext is None:
- app.warn('kernel-render: "%s" unknown / include raw.' % (srclang))
+ kernellog.warn(app, 'kernel-render: "%s" unknown / include raw.' % (srclang))
return
if not dot_cmd and tmp_ext == '.dot':
- app.verbose("dot from graphviz not available / include raw.")
+ kernellog.verbose(app, "dot from graphviz not available / include raw.")
return
literal_block = node[0]
diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt
index 78b59e7..eee0651 100644
--- a/doc/uImage.FIT/signature.txt
+++ b/doc/uImage.FIT/signature.txt
@@ -216,7 +216,7 @@
kernel = "kernel-1";
fdt = "fdt-1";
};
- conf-1 {
+ conf-2 {
kernel = "kernel-2";
fdt = "fdt-2";
};
@@ -232,7 +232,7 @@
kernel = "kernel-1";
fdt = "fdt-1";
};
- conf-1 {
+ conf-2 {
kernel = "kernel-2";
fdt = "fdt-2";
};
@@ -337,6 +337,7 @@
the legacy image format is default disabled by not defining
CONFIG_LEGACY_IMAGE_FORMAT
+
Testing
-------
An easy way to test signing and verification is to use the test script
@@ -349,6 +350,8 @@
$ make O=sandbox sandbox_config
$ make O=sandbox
$ O=sandbox ./test/vboot/vboot_test.sh
+
+
Simple Verified Boot Test
=========================
@@ -388,8 +391,8 @@
Test passed
-Hardware Signing with PKCS#11
------------------------------
+Hardware Signing with PKCS#11 or with HSM
+-----------------------------------------
Securely managing private signing keys can challenging, especially when the
keys are stored on the file system of a computer that is connected to the
@@ -402,14 +405,43 @@
device.
Requirements:
-Smartcard/USB token/HSM which can work with the pkcs11 engine
+Smartcard/USB token/HSM which can work with some openssl engine
openssl
+
+For pkcs11 engine usage:
libp11 (provides pkcs11 engine)
p11-kit (recommended to simplify setup)
opensc (for smartcards and smartcard like USB devices)
gnutls (recommended for key generation, p11tool)
+For generic HSMs respective openssl engine must be installed and locateable by
+openssl. This may require setting up LD_LIBRARY_PATH if engine is not installed
+to openssl's default search paths.
+
+PKCS11 engine support forms "key id" based on "keydir" and with
+"key-name-hint". "key-name-hint" is used as "object" name and "keydir" if
+defined is used to define (prefix for) which PKCS11 source is being used for
+lookup up for the key.
+
+PKCS11 engine key ids:
+ "pkcs11:<keydir>;object=<key-name-hint>;type=<public|private>"
+or
+ "pkcs11:object=<key-name-hint>;type=<public|private>",
+
+Generic HSM engine support forms "key id" based on "keydir" and with
+"key-name-hint". If "keydir" is specified for mkimage it is used as a prefix in
+"key id" and is appended with "key-name-hint".
+
+Generic engine key ids:
+ "<keydir><key-name-hint>"
+or
+ "<key-name-hint>"
+
+As mkimage does not at this time support prompting for passwords HSM may need
+key preloading wrapper to be used when invoking mkimage.
+
-The following examples use the Nitrokey Pro. Instructions for other devices may vary.
+The following examples use the Nitrokey Pro using pkcs11 engine. Instructions
+for other devices may vary.
Notes on pkcs11 engine setup:
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index baaf431..c23b668 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -208,7 +208,11 @@
if (ret)
return ret;
- return blk_select_hwpart(dev, hwpart);
+ ret = blk_select_hwpart(dev, hwpart);
+ if (!ret)
+ blkcache_invalidate(if_type, devnum);
+
+ return ret;
}
int blk_list_part(enum if_type if_type)
@@ -348,7 +352,13 @@
int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
{
- return blk_select_hwpart(desc->bdev, hwpart);
+ int ret;
+
+ ret = blk_select_hwpart(desc->bdev, hwpart);
+ if (!ret)
+ blkcache_invalidate(desc->if_type, desc->devnum);
+
+ return ret;
}
int blk_first_device(int if_type, struct udevice **devp)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 96969b9..7b81eac 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -98,6 +98,7 @@
Enable the STM32 clock (RCC) driver. Enable support for
manipulating STM32MP1's on-SoC clocks.
+source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/at91/Kconfig"
source "drivers/clk/exynos/Kconfig"
source "drivers/clk/imx/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 719b9b8..f0ced49 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_rate.o
obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_factor.o
+obj-y += analogbits/
obj-y += imx/
obj-y += tegra/
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
diff --git a/drivers/clk/analogbits/Kconfig b/drivers/clk/analogbits/Kconfig
new file mode 100644
index 0000000..1d25e6f
--- /dev/null
+++ b/drivers/clk/analogbits/Kconfig
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config CLK_ANALOGBITS_WRPLL_CLN28HPC
+ bool
diff --git a/drivers/clk/analogbits/Makefile b/drivers/clk/analogbits/Makefile
new file mode 100644
index 0000000..ec1bb40
--- /dev/null
+++ b/drivers/clk/analogbits/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o
diff --git a/drivers/clk/sifive/wrpll-cln28hpc.c b/drivers/clk/analogbits/wrpll-cln28hpc.c
similarity index 69%
rename from drivers/clk/sifive/wrpll-cln28hpc.c
rename to drivers/clk/analogbits/wrpll-cln28hpc.c
index d377849..776ead3 100644
--- a/drivers/clk/sifive/wrpll-cln28hpc.c
+++ b/drivers/clk/analogbits/wrpll-cln28hpc.c
@@ -1,20 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2019 Western Digital Corporation or its affiliates.
- *
- * Copyright (C) 2018 SiFive, Inc.
+ * Copyright (C) 2018-2019 SiFive, Inc.
* Wesley Terpstra
* Paul Walmsley
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
* This library supports configuration parsing and reprogramming of
* the CLN28HPC variant of the Analog Bits Wide Range PLL. The
* intention is for this library to be reusable for any device that
@@ -29,14 +18,14 @@
* References:
* - Analog Bits "Wide Range PLL Datasheet", version 2015.10.01
* - SiFive FU540-C000 Manual v1p0, Chapter 7 "Clocking and Reset"
+ * https://static.dev.sifive.com/FU540-C000-v1.0.pdf
*/
#include <linux/bug.h>
#include <linux/err.h>
#include <linux/log2.h>
#include <linux/math64.h>
-
-#include "analogbits-wrpll-cln28hpc.h"
+#include <linux/clk/analogbits-wrpll-cln28hpc.h>
/* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */
#define MIN_INPUT_FREQ 7000000
@@ -85,40 +74,38 @@
* range selection.
*
* Return: The RANGE value to be presented to the PLL configuration inputs,
- * or -1 upon error.
+ * or a negative return code upon error.
*/
static int __wrpll_calc_filter_range(unsigned long post_divr_freq)
{
- u8 range;
-
if (post_divr_freq < MIN_POST_DIVR_FREQ ||
post_divr_freq > MAX_POST_DIVR_FREQ) {
WARN(1, "%s: post-divider reference freq out of range: %lu",
__func__, post_divr_freq);
- return -1;
+ return -ERANGE;
}
- if (post_divr_freq < 11000000)
- range = 1;
- else if (post_divr_freq < 18000000)
- range = 2;
- else if (post_divr_freq < 30000000)
- range = 3;
- else if (post_divr_freq < 50000000)
- range = 4;
- else if (post_divr_freq < 80000000)
- range = 5;
- else if (post_divr_freq < 130000000)
- range = 6;
- else
- range = 7;
+ switch (post_divr_freq) {
+ case 0 ... 10999999:
+ return 1;
+ case 11000000 ... 17999999:
+ return 2;
+ case 18000000 ... 29999999:
+ return 3;
+ case 30000000 ... 49999999:
+ return 4;
+ case 50000000 ... 79999999:
+ return 5;
+ case 80000000 ... 129999999:
+ return 6;
+ }
- return range;
+ return 7;
}
/**
* __wrpll_calc_fbdiv() - return feedback fixed divide value
- * @c: ptr to a struct analogbits_wrpll_cfg record to read from
+ * @c: ptr to a struct wrpll_cfg record to read from
*
* The internal feedback path includes a fixed by-two divider; the
* external feedback path does not. Return the appropriate divider
@@ -133,7 +120,7 @@
* Return: 2 if internal feedback is enabled or 1 if external feedback
* is enabled.
*/
-static u8 __wrpll_calc_fbdiv(struct analogbits_wrpll_cfg *c)
+static u8 __wrpll_calc_fbdiv(const struct wrpll_cfg *c)
{
return (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) ? 2 : 1;
}
@@ -173,7 +160,7 @@
*vco_rate = MIN_VCO_FREQ;
} else {
divq = ilog2(s);
- *vco_rate = target_rate << divq;
+ *vco_rate = (u64)target_rate << divq;
}
wcd_out:
@@ -182,7 +169,7 @@
/**
* __wrpll_update_parent_rate() - update PLL data when parent rate changes
- * @c: ptr to a struct analogbits_wrpll_cfg record to write PLL data to
+ * @c: ptr to a struct wrpll_cfg record to write PLL data to
* @parent_rate: PLL input refclk rate (pre-R-divider)
*
* Pre-compute some data used by the PLL configuration algorithm when
@@ -190,46 +177,40 @@
* computation when the parent rate remains constant - expected to be
* the common case.
*
- * Returns: 0 upon success or -1 if the reference clock rate is out of range.
+ * Returns: 0 upon success or -ERANGE if the reference clock rate is
+ * out of range.
*/
-static int __wrpll_update_parent_rate(struct analogbits_wrpll_cfg *c,
+static int __wrpll_update_parent_rate(struct wrpll_cfg *c,
unsigned long parent_rate)
{
u8 max_r_for_parent;
if (parent_rate > MAX_INPUT_FREQ || parent_rate < MIN_POST_DIVR_FREQ)
- return -1;
+ return -ERANGE;
- c->_parent_rate = parent_rate;
+ c->parent_rate = parent_rate;
max_r_for_parent = div_u64(parent_rate, MIN_POST_DIVR_FREQ);
- c->_max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent);
+ c->max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent);
- /* Round up */
- c->_init_r = div_u64(parent_rate + MAX_POST_DIVR_FREQ - 1,
- MAX_POST_DIVR_FREQ);
+ c->init_r = DIV_ROUND_UP_ULL(parent_rate, MAX_POST_DIVR_FREQ);
return 0;
}
-/*
- * Public functions
- */
-
/**
- * analogbits_wrpll_configure() - compute PLL configuration for a target rate
- * @c: ptr to a struct analogbits_wrpll_cfg record to write into
+ * wrpll_configure() - compute PLL configuration for a target rate
+ * @c: ptr to a struct wrpll_cfg record to write into
* @target_rate: target PLL output clock rate (post-Q-divider)
* @parent_rate: PLL input refclk rate (pre-R-divider)
*
- * Given a pointer to a PLL context @c, a desired PLL target output
- * rate @target_rate, and a reference clock input rate @parent_rate,
- * compute the appropriate PLL signal configuration values. PLL
- * reprogramming is not glitchless, so the caller should switch any
- * downstream logic to a different clock source or clock-gate it
- * before presenting these values to the PLL configuration signals.
+ * Compute the appropriate PLL signal configuration values and store
+ * in PLL context @c. PLL reprogramming is not glitchless, so the
+ * caller should switch any downstream logic to a different clock
+ * source or clock-gate it before presenting these values to the PLL
+ * configuration signals.
*
* The caller must pass this function a pre-initialized struct
- * analogbits_wrpll_cfg record: either initialized to zero (with the
+ * wrpll_cfg record: either initialized to zero (with the
* exception of the .name and .flags fields) or read from the PLL.
*
* Context: Any context. Caller must protect the memory pointed to by @c
@@ -237,41 +218,26 @@
*
* Return: 0 upon success; anything else upon failure.
*/
-int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
- u32 target_rate,
- unsigned long parent_rate)
+int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
+ unsigned long parent_rate)
{
unsigned long ratio;
u64 target_vco_rate, delta, best_delta, f_pre_div, vco, vco_pre;
- u32 best_f, f, post_divr_freq, fbcfg;
+ u32 best_f, f, post_divr_freq;
u8 fbdiv, divq, best_r, r;
-
- if (!c)
- return -1;
+ int range;
if (c->flags == 0) {
WARN(1, "%s called with uninitialized PLL config", __func__);
- return -1;
+ return -EINVAL;
}
- fbcfg = WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK;
- if ((c->flags & fbcfg) == fbcfg) {
- WARN(1, "%s called with invalid PLL config", __func__);
- return -1;
- }
-
- if (c->flags == WRPLL_FLAGS_EXT_FEEDBACK_MASK) {
- WARN(1, "%s: external feedback mode not currently supported",
- __func__);
- return -1;
- }
-
/* Initialize rounding data if it hasn't been initialized already */
- if (parent_rate != c->_parent_rate) {
+ if (parent_rate != c->parent_rate) {
if (__wrpll_update_parent_rate(c, parent_rate)) {
pr_err("%s: PLL input rate is out of range\n",
__func__);
- return -1;
+ return -ERANGE;
}
}
@@ -282,11 +248,12 @@
c->flags |= WRPLL_FLAGS_BYPASS_MASK;
return 0;
}
+
c->flags &= ~WRPLL_FLAGS_BYPASS_MASK;
/* Calculate the Q shift and target VCO rate */
divq = __wrpll_calc_divq(target_rate, &target_vco_rate);
- if (divq == 0)
+ if (!divq)
return -1;
c->divq = divq;
@@ -302,8 +269,7 @@
* Consider all values for R which land within
* [MIN_POST_DIVR_FREQ, MAX_POST_DIVR_FREQ]; prefer smaller R
*/
- for (r = c->_init_r; r <= c->_max_r; ++r) {
- /* What is the best F we can pick in this case? */
+ for (r = c->init_r; r <= c->max_r; ++r) {
f_pre_div = ratio * r;
f = (f_pre_div + (1 << ROUND_SHIFT)) >> ROUND_SHIFT;
f >>= (fbdiv - 1);
@@ -335,46 +301,54 @@
post_divr_freq = div_u64(parent_rate, best_r);
/* Pick the best PLL jitter filter */
- c->range = __wrpll_calc_filter_range(post_divr_freq);
+ range = __wrpll_calc_filter_range(post_divr_freq);
+ if (range < 0)
+ return range;
+ c->range = range;
return 0;
}
/**
- * analogbits_wrpll_calc_output_rate() - calculate the PLL's target output rate
- * @c: ptr to a struct analogbits_wrpll_cfg record to read from
+ * wrpll_calc_output_rate() - calculate the PLL's target output rate
+ * @c: ptr to a struct wrpll_cfg record to read from
* @parent_rate: PLL refclk rate
*
* Given a pointer to the PLL's current input configuration @c and the
* PLL's input reference clock rate @parent_rate (before the R
* pre-divider), calculate the PLL's output clock rate (after the Q
- * post-divider)
+ * post-divider).
*
* Context: Any context. Caller must protect the memory pointed to by @c
* from simultaneous modification.
*
- * Return: the PLL's output clock rate, in Hz.
+ * Return: the PLL's output clock rate, in Hz. The return value from
+ * this function is intended to be convenient to pass directly
+ * to the Linux clock framework; thus there is no explicit
+ * error return value.
*/
-unsigned long analogbits_wrpll_calc_output_rate(struct analogbits_wrpll_cfg *c,
- unsigned long parent_rate)
+unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
+ unsigned long parent_rate)
{
u8 fbdiv;
u64 n;
- WARN(c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK,
- "external feedback mode not yet supported");
+ if (c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK) {
+ WARN(1, "external feedback mode not yet supported");
+ return ULONG_MAX;
+ }
fbdiv = __wrpll_calc_fbdiv(c);
n = parent_rate * fbdiv * (c->divf + 1);
- n = div_u64(n, (c->divr + 1));
+ n = div_u64(n, c->divr + 1);
n >>= c->divq;
return n;
}
/**
- * analogbits_wrpll_calc_max_lock_us() - return the time for the PLL to lock
- * @c: ptr to a struct analogbits_wrpll_cfg record to read from
+ * wrpll_calc_max_lock_us() - return the time for the PLL to lock
+ * @c: ptr to a struct wrpll_cfg record to read from
*
* Return the minimum amount of time (in microseconds) that the caller
* must wait after reprogramming the PLL to ensure that it is locked
@@ -384,7 +358,7 @@
* Return: the minimum amount of time the caller must wait for the PLL
* to lock (in microseconds)
*/
-unsigned int analogbits_wrpll_calc_max_lock_us(struct analogbits_wrpll_cfg *c)
+unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c)
{
return MAX_LOCK_US;
}
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 79b3b04..06a8258 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -51,6 +51,8 @@
else
clk->id = 0;
+ clk->data = 0;
+
return 0;
}
diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c
index 6ffa05b..5806d48 100644
--- a/drivers/clk/clk_stm32mp1.c
+++ b/drivers/clk/clk_stm32mp1.c
@@ -300,6 +300,7 @@
_DSI_SEL,
_ADC12_SEL,
_SPI1_SEL,
+ _RTC_SEL,
_PARENT_SEL_NB,
_UNKNOWN_SEL = 0xff,
};
@@ -534,6 +535,7 @@
STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB2ENSETR, 5, ADC12, _HCLK2),
@@ -569,6 +571,8 @@
STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
+
+ STM32MP1_CLK(RCC_BDCR, 20, RTC, _RTC_SEL),
};
static const u8 i2c12_parents[] = {_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER};
@@ -594,6 +598,7 @@
static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q};
static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER,
_PLL3_R};
+static const u8 rtc_parents[] = {_UNKNOWN_ID, _LSE, _LSI, _HSE};
static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
STM32MP1_CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents),
@@ -619,6 +624,9 @@
STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents),
STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x1, adc_parents),
STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents),
+ STM32MP1_CLK_PARENT(_RTC_SEL, RCC_BDCR, RCC_BDCR_RTCSRC_SHIFT,
+ (RCC_BDCR_RTCSRC_MASK >> RCC_BDCR_RTCSRC_SHIFT),
+ rtc_parents),
};
#ifdef STM32MP1_CLOCK_TREE_INIT
@@ -734,6 +742,7 @@
[_DSI_SEL] = "DSI",
[_ADC12_SEL] = "ADC12",
[_SPI1_SEL] = "SPI1",
+ [_RTC_SEL] = "RTC",
};
static const struct stm32mp1_clk_data stm32mp1_data = {
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c
index aa6a8ad..d9950c1 100644
--- a/drivers/clk/rockchip/clk_rk3399.c
+++ b/drivers/clk/rockchip/clk_rk3399.c
@@ -38,8 +38,8 @@
};
#define RATE_TO_DIV(input_rate, output_rate) \
- ((input_rate) / (output_rate) - 1);
-#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
+ ((input_rate) / (output_rate) - 1)
+#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
#define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
.refdiv = _refdiv,\
@@ -53,15 +53,15 @@
static const struct pll_div ppll_init_cfg = PLL_DIVISORS(PPLL_HZ, 2, 2, 1);
#endif
-static const struct pll_div apll_l_1600_cfg = PLL_DIVISORS(1600*MHz, 3, 1, 1);
-static const struct pll_div apll_l_600_cfg = PLL_DIVISORS(600*MHz, 1, 2, 1);
+static const struct pll_div apll_l_1600_cfg = PLL_DIVISORS(1600 * MHz, 3, 1, 1);
+static const struct pll_div apll_l_600_cfg = PLL_DIVISORS(600 * MHz, 1, 2, 1);
static const struct pll_div *apll_l_cfgs[] = {
[APLL_L_1600_MHZ] = &apll_l_1600_cfg,
[APLL_L_600_MHZ] = &apll_l_600_cfg,
};
-static const struct pll_div apll_b_600_cfg = PLL_DIVISORS(600*MHz, 1, 2, 1);
+static const struct pll_div apll_b_600_cfg = PLL_DIVISORS(600 * MHz, 1, 2, 1);
static const struct pll_div *apll_b_cfgs[] = {
[APLL_B_600_MHZ] = &apll_b_600_cfg,
};
@@ -393,7 +393,7 @@
fref_khz = ref_khz / refdiv;
fbdiv = vco_khz / fref_khz;
- if ((fbdiv >= max_fbdiv) || (fbdiv <= min_fbdiv))
+ if (fbdiv >= max_fbdiv || fbdiv <= min_fbdiv)
continue;
diff_khz = vco_khz - fbdiv * fref_khz;
if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) {
@@ -409,7 +409,7 @@
div->fbdiv = fbdiv;
}
- if (best_diff_khz > 4 * (MHz/KHz)) {
+ if (best_diff_khz > 4 * (MHz / KHz)) {
printf("%s: Failed to match output frequency %u, "
"difference is %u Hz,exceed 4MHZ\n", __func__, freq_hz,
best_diff_khz * KHz);
@@ -489,28 +489,21 @@
}
#define I2C_CLK_REG_MASK(bus) \
- (I2C_DIV_CON_MASK << \
- CLK_I2C ##bus## _DIV_CON_SHIFT | \
- CLK_I2C_PLL_SEL_MASK << \
- CLK_I2C ##bus## _PLL_SEL_SHIFT)
+ (I2C_DIV_CON_MASK << CLK_I2C ##bus## _DIV_CON_SHIFT | \
+ CLK_I2C_PLL_SEL_MASK << CLK_I2C ##bus## _PLL_SEL_SHIFT)
#define I2C_CLK_REG_VALUE(bus, clk_div) \
- ((clk_div - 1) << \
- CLK_I2C ##bus## _DIV_CON_SHIFT | \
- CLK_I2C_PLL_SEL_GPLL << \
- CLK_I2C ##bus## _PLL_SEL_SHIFT)
+ ((clk_div - 1) << CLK_I2C ##bus## _DIV_CON_SHIFT | \
+ CLK_I2C_PLL_SEL_GPLL << CLK_I2C ##bus## _PLL_SEL_SHIFT)
#define I2C_CLK_DIV_VALUE(con, bus) \
- (con >> CLK_I2C ##bus## _DIV_CON_SHIFT) & \
- I2C_DIV_CON_MASK;
+ ((con >> CLK_I2C ##bus## _DIV_CON_SHIFT) & I2C_DIV_CON_MASK)
#define I2C_PMUCLK_REG_MASK(bus) \
- (I2C_DIV_CON_MASK << \
- CLK_I2C ##bus## _DIV_CON_SHIFT)
+ (I2C_DIV_CON_MASK << CLK_I2C ##bus## _DIV_CON_SHIFT)
#define I2C_PMUCLK_REG_VALUE(bus, clk_div) \
- ((clk_div - 1) << \
- CLK_I2C ##bus## _DIV_CON_SHIFT)
+ ((clk_div - 1) << CLK_I2C ##bus## _DIV_CON_SHIFT)
static ulong rk3399_i2c_get_clk(struct rk3399_cru *cru, ulong clk_id)
{
@@ -597,9 +590,9 @@
*/
struct spi_clkreg {
- uint8_t reg; /* CLKSEL_CON[reg] register in CRU */
- uint8_t div_shift;
- uint8_t sel_shift;
+ u8 reg; /* CLKSEL_CON[reg] register in CRU */
+ u8 div_shift;
+ u8 sel_shift;
};
/*
@@ -678,7 +671,7 @@
static ulong rk3399_vop_set_clk(struct rk3399_cru *cru, ulong clk_id, u32 hz)
{
struct pll_div vpll_config = {0};
- int aclk_vop = 198*MHz;
+ int aclk_vop = 198 * MHz;
void *aclkreg_addr, *dclkreg_addr;
u32 div;
@@ -710,7 +703,7 @@
rkclk_set_pll(&cru->vpll_con[0], &vpll_config);
rk_clrsetreg(dclkreg_addr,
- DCLK_VOP_DCLK_SEL_MASK | DCLK_VOP_PLL_SEL_MASK|
+ DCLK_VOP_DCLK_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
DCLK_VOP_DIV_CON_MASK,
DCLK_VOP_DCLK_SEL_DIVOUT << DCLK_VOP_DCLK_SEL_SHIFT |
DCLK_VOP_PLL_SEL_VPLL << DCLK_VOP_PLL_SEL_SHIFT |
@@ -750,7 +743,7 @@
ulong clk_id, ulong set_rate)
{
int src_clk_div;
- int aclk_emmc = 198*MHz;
+ int aclk_emmc = 198 * MHz;
switch (clk_id) {
case HCLK_SDMMC:
@@ -776,7 +769,7 @@
break;
case SCLK_EMMC:
/* Select aclk_emmc source from GPLL */
- src_clk_div = DIV_ROUND_UP(GPLL_HZ , aclk_emmc);
+ src_clk_div = DIV_ROUND_UP(GPLL_HZ, aclk_emmc);
assert(src_clk_div - 1 < 32);
rk_clrsetreg(&cru->clksel_con[21],
@@ -834,23 +827,31 @@
/* clk_ddrc == DPLL = 24MHz / refdiv * fbdiv / postdiv1 / postdiv2 */
switch (set_rate) {
- case 200*MHz:
+ case 50 * MHz:
+ dpll_cfg = (struct pll_div)
+ {.refdiv = 1, .fbdiv = 12, .postdiv1 = 3, .postdiv2 = 2};
+ break;
+ case 200 * MHz:
dpll_cfg = (struct pll_div)
{.refdiv = 1, .fbdiv = 50, .postdiv1 = 6, .postdiv2 = 1};
break;
- case 300*MHz:
+ case 300 * MHz:
dpll_cfg = (struct pll_div)
{.refdiv = 2, .fbdiv = 100, .postdiv1 = 4, .postdiv2 = 1};
break;
- case 666*MHz:
+ case 400 * MHz:
+ dpll_cfg = (struct pll_div)
+ {.refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1};
+ break;
+ case 666 * MHz:
dpll_cfg = (struct pll_div)
{.refdiv = 2, .fbdiv = 111, .postdiv1 = 2, .postdiv2 = 1};
break;
- case 800*MHz:
+ case 800 * MHz:
dpll_cfg = (struct pll_div)
{.refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1};
break;
- case 933*MHz:
+ case 933 * MHz:
dpll_cfg = (struct pll_div)
{.refdiv = 1, .fbdiv = 116, .postdiv1 = 3, .postdiv2 = 1};
break;
@@ -916,7 +917,6 @@
case SCLK_UART2:
case SCLK_UART3:
return 24000000;
- break;
case PCLK_HDMI_CTRL:
break;
case DCLK_VOP0:
@@ -1014,7 +1014,8 @@
return ret;
}
-static int __maybe_unused rk3399_gmac_set_parent(struct clk *clk, struct clk *parent)
+static int __maybe_unused rk3399_gmac_set_parent(struct clk *clk,
+ struct clk *parent)
{
struct rk3399_clk_priv *priv = dev_get_priv(clk->dev);
const char *clock_output_name;
@@ -1024,7 +1025,7 @@
* If the requested parent is in the same clock-controller and
* the id is SCLK_MAC ("clk_gmac"), switch to the internal clock.
*/
- if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC)) {
+ if (parent->dev == clk->dev && parent->id == SCLK_MAC) {
debug("%s: switching RGMII to SCLK_MAC\n", __func__);
rk_clrreg(&priv->cru->clksel_con[19], BIT(4));
return 0;
@@ -1049,7 +1050,8 @@
return -EINVAL;
}
-static int __maybe_unused rk3399_clk_set_parent(struct clk *clk, struct clk *parent)
+static int __maybe_unused rk3399_clk_set_parent(struct clk *clk,
+ struct clk *parent)
{
switch (clk->id) {
case SCLK_RMII_SRC:
@@ -1078,6 +1080,18 @@
case PCLK_GMAC:
/* Required to successfully probe the Designware GMAC driver */
return 0;
+
+ case SCLK_USB3OTG0_REF:
+ case SCLK_USB3OTG1_REF:
+ case SCLK_USB3OTG0_SUSPEND:
+ case SCLK_USB3OTG1_SUSPEND:
+ case ACLK_USB3OTG0:
+ case ACLK_USB3OTG1:
+ case ACLK_USB3_RKSOC_AXI_PERF:
+ case ACLK_USB3:
+ case ACLK_USB3_GRF:
+ /* Required to successfully probe the Designware USB3 driver */
+ return 0;
}
debug("%s: unsupported clk %ld\n", __func__, clk->id);
diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
index 644881b..c4d0a1f 100644
--- a/drivers/clk/sifive/Kconfig
+++ b/drivers/clk/sifive/Kconfig
@@ -1,8 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-config CLK_ANALOGBITS_WRPLL_CLN28HPC
- bool
-
config CLK_SIFIVE
bool "SiFive SoC driver support"
depends on CLK
@@ -17,10 +14,3 @@
Supports the Power Reset Clock interface (PRCI) IP block found in
FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC,
enable this driver.
-
-config CLK_SIFIVE_GEMGXL_MGMT
- bool "GEMGXL management for SiFive FU540 SoCs"
- depends on CLK_SIFIVE
- help
- Supports the GEMGXL management IP block found in FU540 SoCs to
- control GEM TX clock operation mode for 10/100/1000 Mbps.
diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
index f8263e7..b224279 100644
--- a/drivers/clk/sifive/Makefile
+++ b/drivers/clk/sifive/Makefile
@@ -1,7 +1,3 @@
# SPDX-License-Identifier: GPL-2.0+
-obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o
-
obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o
-
-obj-$(CONFIG_CLK_SIFIVE_GEMGXL_MGMT) += gemgxl-mgmt.o
diff --git a/drivers/clk/sifive/analogbits-wrpll-cln28hpc.h b/drivers/clk/sifive/analogbits-wrpll-cln28hpc.h
deleted file mode 100644
index 4432e24..0000000
--- a/drivers/clk/sifive/analogbits-wrpll-cln28hpc.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2019 Western Digital Corporation or its affiliates.
- *
- * Copyright (C) 2018 SiFive, Inc.
- * Wesley Terpstra
- * Paul Walmsley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
-#define __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
-
-#include <linux/types.h>
-
-/* DIVQ_VALUES: number of valid DIVQ values */
-#define DIVQ_VALUES 6
-
-/*
- * Bit definitions for struct analogbits_wrpll_cfg.flags
- *
- * WRPLL_FLAGS_BYPASS_FLAG: if set, the PLL is either in bypass, or should be
- * programmed to enter bypass
- * WRPLL_FLAGS_RESET_FLAG: if set, the PLL is in reset
- * WRPLL_FLAGS_INT_FEEDBACK_FLAG: if set, the PLL is configured for internal
- * feedback mode
- * WRPLL_FLAGS_EXT_FEEDBACK_FLAG: if set, the PLL is configured for external
- * feedback mode (not yet supported by this driver)
- *
- * The flags WRPLL_FLAGS_INT_FEEDBACK_FLAG and WRPLL_FLAGS_EXT_FEEDBACK_FLAG are
- * mutually exclusive. If both bits are set, or both are zero, the struct
- * analogbits_wrpll_cfg record is uninitialized or corrupt.
- */
-#define WRPLL_FLAGS_BYPASS_SHIFT 0
-#define WRPLL_FLAGS_BYPASS_MASK BIT(WRPLL_FLAGS_BYPASS_SHIFT)
-#define WRPLL_FLAGS_RESET_SHIFT 1
-#define WRPLL_FLAGS_RESET_MASK BIT(WRPLL_FLAGS_RESET_SHIFT)
-#define WRPLL_FLAGS_INT_FEEDBACK_SHIFT 2
-#define WRPLL_FLAGS_INT_FEEDBACK_MASK BIT(WRPLL_FLAGS_INT_FEEDBACK_SHIFT)
-#define WRPLL_FLAGS_EXT_FEEDBACK_SHIFT 3
-#define WRPLL_FLAGS_EXT_FEEDBACK_MASK BIT(WRPLL_FLAGS_EXT_FEEDBACK_SHIFT)
-
-/**
- * struct analogbits_wrpll_cfg - WRPLL configuration values
- * @divr: reference divider value (6 bits), as presented to the PLL signals.
- * @divf: feedback divider value (9 bits), as presented to the PLL signals.
- * @divq: output divider value (3 bits), as presented to the PLL signals.
- * @flags: PLL configuration flags. See above for more information.
- * @range: PLL loop filter range. See below for more information.
- * @_output_rate_cache: cached output rates, swept across DIVQ.
- * @_parent_rate: PLL refclk rate for which values are valid
- * @_max_r: maximum possible R divider value, given @parent_rate
- * @_init_r: initial R divider value to start the search from
- *
- * @divr, @divq, @divq, @range represent what the PLL expects to see
- * on its input signals. Thus @divr and @divf are the actual divisors
- * minus one. @divq is a power-of-two divider; for example, 1 =
- * divide-by-2 and 6 = divide-by-64. 0 is an invalid @divq value.
- *
- * When initially passing a struct analogbits_wrpll_cfg record, the
- * record should be zero-initialized with the exception of the @flags
- * field. The only flag bits that need to be set are either
- * WRPLL_FLAGS_INT_FEEDBACK or WRPLL_FLAGS_EXT_FEEDBACK.
- *
- * Field names beginning with an underscore should be considered
- * private to the wrpll-cln28hpc.c code.
- */
-struct analogbits_wrpll_cfg {
- u8 divr;
- u8 divq;
- u8 range;
- u8 flags;
- u16 divf;
- u32 _output_rate_cache[DIVQ_VALUES];
- unsigned long _parent_rate;
- u8 _max_r;
- u8 _init_r;
-};
-
-/*
- * Function prototypes
- */
-
-int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
- u32 target_rate,
- unsigned long parent_rate);
-
-unsigned int analogbits_wrpll_calc_max_lock_us(struct analogbits_wrpll_cfg *c);
-
-unsigned long analogbits_wrpll_calc_output_rate(struct analogbits_wrpll_cfg *c,
- unsigned long parent_rate);
-
-#endif /* __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H */
diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c
index 2d47ebc..ce0769f 100644
--- a/drivers/clk/sifive/fu540-prci.c
+++ b/drivers/clk/sifive/fu540-prci.c
@@ -37,9 +37,8 @@
#include <errno.h>
#include <linux/math64.h>
-#include <dt-bindings/clk/sifive-fu540-prci.h>
-
-#include "analogbits-wrpll-cln28hpc.h"
+#include <linux/clk/analogbits-wrpll-cln28hpc.h>
+#include <dt-bindings/clock/sifive-fu540-prci.h>
/*
* EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
@@ -159,30 +158,32 @@
* PRCI per-device instance data
*/
struct __prci_data {
- void *base;
- struct clk parent;
+ void *va;
+ struct clk parent_hfclk;
+ struct clk parent_rtcclk;
};
/**
* struct __prci_wrpll_data - WRPLL configuration and integration data
* @c: WRPLL current configuration record
- * @bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
- * @no_bypass: fn ptr to code to not bypass the WRPLL (if applicable; else NULL)
+ * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
+ * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
* @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
*
- * @bypass and @no_bypass are used for WRPLL instances that contain a separate
- * external glitchless clock mux downstream from the PLL. The WRPLL internal
- * bypass mux is not glitchless.
+ * @enable_bypass and @disable_bypass are used for WRPLL instances
+ * that contain a separate external glitchless clock mux downstream
+ * from the PLL. The WRPLL internal bypass mux is not glitchless.
*/
struct __prci_wrpll_data {
- struct analogbits_wrpll_cfg c;
- void (*bypass)(struct __prci_data *pd);
- void (*no_bypass)(struct __prci_data *pd);
+ struct wrpll_cfg c;
+ void (*enable_bypass)(struct __prci_data *pd);
+ void (*disable_bypass)(struct __prci_data *pd);
u8 cfg0_offs;
};
struct __prci_clock;
+/* struct __prci_clock_ops - clock operations */
struct __prci_clock_ops {
int (*set_rate)(struct __prci_clock *pc,
unsigned long rate,
@@ -198,8 +199,7 @@
* struct __prci_clock - describes a clock device managed by PRCI
* @name: user-readable clock name string - should match the manual
* @parent_name: parent name for this clock
- * @ops: struct clk_ops for the Linux clock framework to use for control
- * @hw: Linux-private clock data
+ * @ops: struct __prci_clock_ops for control
* @pwd: WRPLL-specific data, associated with this clock (if not NULL)
* @pd: PRCI-specific data associated with this clock (if not NULL)
*
@@ -233,19 +233,19 @@
*/
static u32 __prci_readl(struct __prci_data *pd, u32 offs)
{
- return readl(pd->base + offs);
+ return readl(pd->va + offs);
}
static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
{
- return writel(v, pd->base + offs);
+ writel(v, pd->va + offs);
}
/* WRPLL-related private functions */
/**
* __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
- * @c: ptr to a struct analogbits_wrpll_cfg record to write config into
+ * @c: ptr to a struct wrpll_cfg record to write config into
* @r: value read from the PRCI PLL configuration register
*
* Given a value @r read from an FU540 PRCI PLL configuration register,
@@ -257,7 +257,7 @@
*
* Context: Any context.
*/
-static void __prci_wrpll_unpack(struct analogbits_wrpll_cfg *c, u32 r)
+static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
{
u32 v;
@@ -280,15 +280,13 @@
c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
WRPLL_FLAGS_EXT_FEEDBACK_MASK);
- if (r & PRCI_COREPLLCFG0_FSE_MASK)
- c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
- else
- c->flags |= WRPLL_FLAGS_EXT_FEEDBACK_MASK;
+ /* external feedback mode not supported */
+ c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
}
/**
* __prci_wrpll_pack() - pack PLL configuration parameters into a register value
- * @c: pointer to a struct analogbits_wrpll_cfg record containing the PLL's cfg
+ * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
*
* Using a set of WRPLL configuration values pointed to by @c,
* assemble a PRCI PLL configuration register value, and return it to
@@ -301,7 +299,7 @@
* Returns: a value suitable for writing into a PRCI PLL configuration
* register
*/
-static u32 __prci_wrpll_pack(struct analogbits_wrpll_cfg *c)
+static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
{
u32 r = 0;
@@ -309,8 +307,9 @@
r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
- if (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK)
- r |= PRCI_COREPLLCFG0_FSE_MASK;
+
+ /* external feedback mode not supported */
+ r |= PRCI_COREPLLCFG0_FSE_MASK;
return r;
}
@@ -349,11 +348,11 @@
*/
static void __prci_wrpll_write_cfg(struct __prci_data *pd,
struct __prci_wrpll_data *pwd,
- struct analogbits_wrpll_cfg *c)
+ struct wrpll_cfg *c)
{
__prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
- memcpy(&pwd->c, c, sizeof(struct analogbits_wrpll_cfg));
+ memcpy(&pwd->c, c, sizeof(*c));
}
/* Core clock mux control */
@@ -404,7 +403,7 @@
{
struct __prci_wrpll_data *pwd = pc->pwd;
- return analogbits_wrpll_calc_output_rate(&pwd->c, parent_rate);
+ return wrpll_calc_output_rate(&pwd->c, parent_rate);
}
static unsigned long sifive_fu540_prci_wrpll_round_rate(
@@ -413,13 +412,13 @@
unsigned long *parent_rate)
{
struct __prci_wrpll_data *pwd = pc->pwd;
- struct analogbits_wrpll_cfg c;
+ struct wrpll_cfg c;
memcpy(&c, &pwd->c, sizeof(c));
- analogbits_wrpll_configure_for_rate(&c, rate, *parent_rate);
+ wrpll_configure_for_rate(&c, rate, *parent_rate);
- return analogbits_wrpll_calc_output_rate(&c, *parent_rate);
+ return wrpll_calc_output_rate(&c, *parent_rate);
}
static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc,
@@ -430,19 +429,19 @@
struct __prci_data *pd = pc->pd;
int r;
- r = analogbits_wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
+ r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
if (r)
- return -ERANGE;
+ return r;
- if (pwd->bypass)
- pwd->bypass(pd);
+ if (pwd->enable_bypass)
+ pwd->enable_bypass(pd);
__prci_wrpll_write_cfg(pd, pwd, &pwd->c);
- udelay(analogbits_wrpll_calc_max_lock_us(&pwd->c));
+ udelay(wrpll_calc_max_lock_us(&pwd->c));
- if (pwd->no_bypass)
- pwd->no_bypass(pd);
+ if (pwd->disable_bypass)
+ pwd->disable_bypass(pd);
return 0;
}
@@ -484,8 +483,8 @@
static struct __prci_wrpll_data __prci_corepll_data = {
.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
- .bypass = __prci_coreclksel_use_hfclk,
- .no_bypass = __prci_coreclksel_use_corepll,
+ .enable_bypass = __prci_coreclksel_use_hfclk,
+ .disable_bypass = __prci_coreclksel_use_corepll,
};
static struct __prci_wrpll_data __prci_ddrpll_data = {
@@ -526,6 +525,27 @@
},
};
+static ulong sifive_fu540_prci_parent_rate(struct __prci_clock *pc)
+{
+ ulong parent_rate;
+ struct __prci_clock *p;
+
+ if (strcmp(pc->parent_name, "corepll") == 0) {
+ p = &__prci_init_clocks[PRCI_CLK_COREPLL];
+ if (!p->pd || !p->ops->recalc_rate)
+ return -ENXIO;
+
+ return p->ops->recalc_rate(p, sifive_fu540_prci_parent_rate(p));
+ }
+
+ if (strcmp(pc->parent_name, "rtcclk") == 0)
+ parent_rate = clk_get_rate(&pc->pd->parent_rtcclk);
+ else
+ parent_rate = clk_get_rate(&pc->pd->parent_hfclk);
+
+ return parent_rate;
+}
+
static ulong sifive_fu540_prci_get_rate(struct clk *clk)
{
struct __prci_clock *pc;
@@ -537,7 +557,7 @@
if (!pc->pd || !pc->ops->recalc_rate)
return -ENXIO;
- return pc->ops->recalc_rate(pc, clk_get_rate(&pc->pd->parent));
+ return pc->ops->recalc_rate(pc, sifive_fu540_prci_parent_rate(pc));
}
static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate)
@@ -552,7 +572,7 @@
if (!pc->pd || !pc->ops->set_rate)
return -ENXIO;
- err = pc->ops->set_rate(pc, rate, clk_get_rate(&pc->pd->parent));
+ err = pc->ops->set_rate(pc, rate, sifive_fu540_prci_parent_rate(pc));
if (err)
return err;
@@ -565,14 +585,18 @@
struct __prci_clock *pc;
struct __prci_data *pd = dev_get_priv(dev);
- pd->base = (void *)dev_read_addr(dev);
- if (IS_ERR(pd->base))
- return PTR_ERR(pd->base);
+ pd->va = (void *)dev_read_addr(dev);
+ if (IS_ERR(pd->va))
+ return PTR_ERR(pd->va);
- err = clk_get_by_index(dev, 0, &pd->parent);
+ err = clk_get_by_index(dev, 0, &pd->parent_hfclk);
if (err)
return err;
+ err = clk_get_by_index(dev, 1, &pd->parent_rtcclk);
+ if (err)
+ return err;
+
for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) {
pc = &__prci_init_clocks[i];
pc->pd = pd;
@@ -589,8 +613,7 @@
};
static const struct udevice_id sifive_fu540_prci_ids[] = {
- { .compatible = "sifive,fu540-c000-prci0" },
- { .compatible = "sifive,aloeprci0" },
+ { .compatible = "sifive,fu540-c000-prci" },
{ }
};
diff --git a/drivers/clk/sifive/gemgxl-mgmt.c b/drivers/clk/sifive/gemgxl-mgmt.c
deleted file mode 100644
index eb37416..0000000
--- a/drivers/clk/sifive/gemgxl-mgmt.c
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2019, Bin Meng <bmeng.cn@gmail.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm.h>
-#include <asm/io.h>
-
-struct gemgxl_mgmt_regs {
- __u32 tx_clk_sel;
-};
-
-struct gemgxl_mgmt_platdata {
- struct gemgxl_mgmt_regs *regs;
-};
-
-static int gemgxl_mgmt_ofdata_to_platdata(struct udevice *dev)
-{
- struct gemgxl_mgmt_platdata *plat = dev_get_platdata(dev);
-
- plat->regs = (struct gemgxl_mgmt_regs *)dev_read_addr(dev);
-
- return 0;
-}
-
-static ulong gemgxl_mgmt_set_rate(struct clk *clk, ulong rate)
-{
- struct gemgxl_mgmt_platdata *plat = dev_get_platdata(clk->dev);
-
- /*
- * GEMGXL TX clock operation mode:
- *
- * 0 = GMII mode. Use 125 MHz gemgxlclk from PRCI in TX logic
- * and output clock on GMII output signal GTX_CLK
- * 1 = MII mode. Use MII input signal TX_CLK in TX logic
- */
- writel(rate != 125000000, &plat->regs->tx_clk_sel);
-
- return 0;
-}
-
-const struct clk_ops gemgxl_mgmt_ops = {
- .set_rate = gemgxl_mgmt_set_rate,
-};
-
-static const struct udevice_id gemgxl_mgmt_match[] = {
- { .compatible = "sifive,cadencegemgxlmgmt0", },
- { /* sentinel */ }
-};
-
-U_BOOT_DRIVER(sifive_gemgxl_mgmt) = {
- .name = "sifive-gemgxl-mgmt",
- .id = UCLASS_CLK,
- .of_match = gemgxl_mgmt_match,
- .ofdata_to_platdata = gemgxl_mgmt_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct gemgxl_mgmt_platdata),
- .ops = &gemgxl_mgmt_ops,
-};
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 0d15e50..474c164 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -388,7 +388,8 @@
if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)
pinctrl_select_state(dev, "default");
- if (dev->parent && device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) {
+ if (CONFIG_IS_ENABLED(POWER_DOMAIN) && dev->parent &&
+ device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) {
if (!power_domain_get(dev, &pd))
power_domain_on(&pd);
}
@@ -409,10 +410,16 @@
goto fail;
}
- /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
- ret = clk_set_defaults(dev);
- if (ret)
- goto fail;
+ /* Only handle devices that have a valid ofnode */
+ if (dev_of_valid(dev)) {
+ /*
+ * Process 'assigned-{clocks/clock-parents/clock-rates}'
+ * properties
+ */
+ ret = clk_set_defaults(dev);
+ if (ret)
+ goto fail;
+ }
if (drv->probe) {
ret = drv->probe(dev);
diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c
index 1bfaaee..4e256d9 100644
--- a/drivers/core/of_addr.c
+++ b/drivers/core/of_addr.c
@@ -318,6 +318,10 @@
return __of_translate_address(dev, in_addr, "ranges");
}
+u64 of_translate_dma_address(const struct device_node *dev, const __be32 *in_addr)
+{
+ return __of_translate_address(dev, in_addr, "dma-ranges");
+}
static int __of_address_to_resource(const struct device_node *dev,
const __be32 *addrp, u64 size, unsigned int flags,
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index c72c6e2..2ac73af 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -770,6 +770,14 @@
return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
}
+u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
+{
+ if (ofnode_is_np(node))
+ return of_translate_dma_address(ofnode_to_np(node), in_addr);
+ else
+ return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
+}
+
int ofnode_device_is_compatible(ofnode node, const char *compat)
{
if (ofnode_is_np(node))
@@ -876,5 +884,5 @@
if (value)
return ofnode_write_string(node, "status", "okay");
else
- return ofnode_write_string(node, "status", "disable");
+ return ofnode_write_string(node, "status", "disabled");
}
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 6bda077..1a044b0 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -265,6 +265,11 @@
return ofnode_translate_address(dev_ofnode(dev), in_addr);
}
+u64 dev_translate_dma_address(struct udevice *dev, const fdt32_t *in_addr)
+{
+ return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
+}
+
int dev_read_alias_highest_id(const char *stem)
{
if (of_live_active())
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index 5ef0f71..d1d12ee 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -108,6 +108,48 @@
return 0;
}
+int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index)
+{
+ struct regmap *map;
+ int addr_len, size_len;
+ int ret;
+
+ addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
+ if (addr_len < 0) {
+ debug("%s: Error while reading the addr length (ret = %d)\n",
+ ofnode_get_name(node), addr_len);
+ return addr_len;
+ }
+
+ size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
+ if (size_len < 0) {
+ debug("%s: Error while reading the size length: (ret = %d)\n",
+ ofnode_get_name(node), size_len);
+ return size_len;
+ }
+
+ map = regmap_alloc(1);
+ if (!map)
+ return -ENOMEM;
+
+ ret = init_range(node, map->ranges, addr_len, size_len, index);
+ if (ret)
+ return ret;
+
+ if (ofnode_read_bool(node, "little-endian"))
+ map->endianness = REGMAP_LITTLE_ENDIAN;
+ else if (ofnode_read_bool(node, "big-endian"))
+ map->endianness = REGMAP_BIG_ENDIAN;
+ else if (ofnode_read_bool(node, "native-endian"))
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+ else /* Default: native endianness */
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+
+ *mapp = map;
+
+ return ret;
+}
+
int regmap_init_mem(ofnode node, struct regmap **mapp)
{
struct regmap_range *range;
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 095a9bc..4772db3 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -330,7 +330,7 @@
config SYS_I2C_OMAP24XX
bool "TI OMAP2+ I2C driver"
- depends on ARCH_OMAP2PLUS
+ depends on ARCH_OMAP2PLUS || ARCH_K3
help
Add support for the OMAP2+ I2C driver.
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 890ef35..4cdae41 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -468,14 +468,15 @@
If unsure, say N.
-config MMC_SDHCI_K3_ARASAN
- bool "Arasan SDHCI controller for TI's K3 based SoCs"
+config MMC_SDHCI_AM654
+ bool "SDHCI Controller on TI's Am654 devices"
depends on ARCH_K3
depends on MMC_SDHCI
depends on DM_MMC && OF_CONTROL && BLK
+ depends on REGMAP
help
- Support for Arasan SDHCI host controller on Texas Instruments'
- K3 family based SoC platforms
+ Support for Secure Digital Host Controller Interface (SDHCI)
+ controllers present on TI's AM654 SOCs.
config MMC_SDHCI_KONA
bool "SDHCI support on Broadcom KONA platform"
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 3c8c53a..6cc018b 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -50,7 +50,7 @@
obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o
obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o
obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o
-obj-$(CONFIG_MMC_SDHCI_K3_ARASAN) += k3_arsan_sdhci.o
+obj-$(CONFIG_MMC_SDHCI_AM654) += am654_sdhci.o
obj-$(CONFIG_MMC_SDHCI_KONA) += kona_sdhci.o
obj-$(CONFIG_MMC_SDHCI_MSM) += msm_sdhci.o
obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o
diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c
new file mode 100644
index 0000000..fb0fb58
--- /dev/null
+++ b/drivers/mmc/am654_sdhci.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Texas Instruments' K3 SD Host Controller Interface
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <power-domain.h>
+#include <regmap.h>
+#include <sdhci.h>
+
+/* CTL_CFG Registers */
+#define CTL_CFG_2 0x14
+
+#define SLOTTYPE_MASK GENMASK(31, 30)
+#define SLOTTYPE_EMBEDDED BIT(30)
+
+/* PHY Registers */
+#define PHY_CTRL1 0x100
+#define PHY_CTRL2 0x104
+#define PHY_CTRL3 0x108
+#define PHY_CTRL4 0x10C
+#define PHY_CTRL5 0x110
+#define PHY_CTRL6 0x114
+#define PHY_STAT1 0x130
+#define PHY_STAT2 0x134
+
+#define IOMUX_ENABLE_SHIFT 31
+#define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT)
+#define OTAPDLYENA_SHIFT 20
+#define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT)
+#define OTAPDLYSEL_SHIFT 12
+#define OTAPDLYSEL_MASK GENMASK(15, 12)
+#define STRBSEL_SHIFT 24
+#define STRBSEL_MASK GENMASK(27, 24)
+#define SEL50_SHIFT 8
+#define SEL50_MASK BIT(SEL50_SHIFT)
+#define SEL100_SHIFT 9
+#define SEL100_MASK BIT(SEL100_SHIFT)
+#define DLL_TRIM_ICP_SHIFT 4
+#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
+#define DR_TY_SHIFT 20
+#define DR_TY_MASK GENMASK(22, 20)
+#define ENDLL_SHIFT 1
+#define ENDLL_MASK BIT(ENDLL_SHIFT)
+#define DLLRDY_SHIFT 0
+#define DLLRDY_MASK BIT(DLLRDY_SHIFT)
+#define PDB_SHIFT 0
+#define PDB_MASK BIT(PDB_SHIFT)
+#define CALDONE_SHIFT 1
+#define CALDONE_MASK BIT(CALDONE_SHIFT)
+#define RETRIM_SHIFT 17
+#define RETRIM_MASK BIT(RETRIM_SHIFT)
+
+#define DRIVER_STRENGTH_50_OHM 0x0
+#define DRIVER_STRENGTH_33_OHM 0x1
+#define DRIVER_STRENGTH_66_OHM 0x2
+#define DRIVER_STRENGTH_100_OHM 0x3
+#define DRIVER_STRENGTH_40_OHM 0x4
+
+#define AM654_SDHCI_MIN_FREQ 400000
+
+struct am654_sdhci_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+ struct regmap *base;
+ bool non_removable;
+ u32 otap_del_sel;
+ u32 trm_icp;
+ u32 drv_strength;
+ bool dll_on;
+};
+
+static void am654_sdhci_set_control_reg(struct sdhci_host *host)
+{
+ struct mmc *mmc = (struct mmc *)host->mmc;
+ u32 reg;
+
+ if (IS_SD(host->mmc) &&
+ mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+ reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ reg |= SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
+ }
+
+ sdhci_set_uhs_timing(host);
+}
+
+static int am654_sdhci_set_ios_post(struct sdhci_host *host)
+{
+ struct udevice *dev = host->mmc->dev;
+ struct am654_sdhci_plat *plat = dev_get_platdata(dev);
+ unsigned int speed = host->mmc->clock;
+ int sel50, sel100;
+ u32 mask, val;
+ int ret;
+
+ /* Reset SD Clock Enable */
+ val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ val &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, val, SDHCI_CLOCK_CONTROL);
+
+ /* power off phy */
+ if (plat->dll_on) {
+ regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0);
+
+ plat->dll_on = false;
+ }
+
+ /* restart clock */
+ sdhci_set_clock(host->mmc, speed);
+
+ /* switch phy back on */
+ if (speed > AM654_SDHCI_MIN_FREQ) {
+ mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
+ val = (1 << OTAPDLYENA_SHIFT) |
+ (plat->otap_del_sel << OTAPDLYSEL_SHIFT);
+ regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
+ switch (speed) {
+ case 200000000:
+ sel50 = 0;
+ sel100 = 0;
+ break;
+ case 100000000:
+ sel50 = 0;
+ sel100 = 1;
+ break;
+ default:
+ sel50 = 1;
+ sel100 = 0;
+ }
+
+ /* Configure PHY DLL frequency */
+ mask = SEL50_MASK | SEL100_MASK;
+ val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
+ regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
+
+ /* Enable DLL */
+ regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK,
+ 0x1 << ENDLL_SHIFT);
+ /*
+ * Poll for DLL ready. Use a one second timeout.
+ * Works in all experiments done so far
+ */
+ ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
+ val & DLLRDY_MASK, 1000, 1000000);
+ if (ret)
+ return ret;
+
+ plat->dll_on = true;
+ }
+
+ return 0;
+}
+
+const struct sdhci_ops am654_sdhci_ops = {
+ .set_ios_post = &am654_sdhci_set_ios_post,
+ .set_control_reg = &am654_sdhci_set_control_reg,
+};
+
+int am654_sdhci_init(struct am654_sdhci_plat *plat)
+{
+ u32 ctl_cfg_2 = 0;
+ u32 mask, val;
+ int ret;
+
+ /* Reset OTAP to default value */
+ mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
+ regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0);
+
+ regmap_read(plat->base, PHY_STAT1, &val);
+ if (~val & CALDONE_MASK) {
+ /* Calibrate IO lines */
+ regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK, PDB_MASK);
+ ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
+ val & CALDONE_MASK, 1, 20);
+ if (ret)
+ return ret;
+ }
+
+ /* Configure DLL TRIM */
+ mask = DLL_TRIM_ICP_MASK;
+ val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
+
+ /* Configure DLL driver strength */
+ mask |= DR_TY_MASK;
+ val |= plat->drv_strength << DR_TY_SHIFT;
+ regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
+
+ /* Enable pins by setting IO mux to 0 */
+ regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0);
+
+ /* Set slot type based on SD or eMMC */
+ if (plat->non_removable)
+ ctl_cfg_2 = SLOTTYPE_EMBEDDED;
+
+ regmap_update_bits(plat->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2);
+
+ return 0;
+}
+
+static int am654_sdhci_probe(struct udevice *dev)
+{
+ struct am654_sdhci_plat *plat = dev_get_platdata(dev);
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct sdhci_host *host = dev_get_priv(dev);
+ struct mmc_config *cfg = &plat->cfg;
+ struct power_domain sdhci_pwrdmn;
+ struct clk clk;
+ unsigned long clock;
+ int ret;
+
+ ret = power_domain_get_by_index(dev, &sdhci_pwrdmn, 0);
+ if (!ret) {
+ ret = power_domain_on(&sdhci_pwrdmn);
+ if (ret) {
+ dev_err(dev, "Power domain on failed (%d)\n", ret);
+ return ret;
+ }
+ } else if (ret != -ENOENT && ret != -ENODEV && ret != -ENOSYS) {
+ dev_err(dev, "failed to get power domain (%d)\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret) {
+ dev_err(dev, "failed to get clock\n");
+ return ret;
+ }
+
+ clock = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(clock)) {
+ dev_err(dev, "failed to get rate\n");
+ return clock;
+ }
+
+ host->max_clk = clock;
+ host->mmc = &plat->mmc;
+ host->mmc->dev = dev;
+ ret = sdhci_setup_cfg(cfg, host, cfg->f_max,
+ AM654_SDHCI_MIN_FREQ);
+ if (ret)
+ return ret;
+ host->ops = &am654_sdhci_ops;
+ host->mmc->priv = host;
+ upriv->mmc = host->mmc;
+
+ regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1);
+
+ am654_sdhci_init(plat);
+
+ return sdhci_probe(dev);
+}
+
+static int am654_sdhci_ofdata_to_platdata(struct udevice *dev)
+{
+ struct am654_sdhci_plat *plat = dev_get_platdata(dev);
+ struct sdhci_host *host = dev_get_priv(dev);
+ struct mmc_config *cfg = &plat->cfg;
+ u32 drv_strength;
+ int ret;
+
+ host->name = dev->name;
+ host->ioaddr = (void *)dev_read_addr(dev);
+ plat->non_removable = dev_read_bool(dev, "non-removable");
+
+ ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp);
+ if (ret)
+ return ret;
+
+ ret = dev_read_u32(dev, "ti,otap-del-sel", &plat->otap_del_sel);
+ if (ret)
+ return ret;
+
+ ret = dev_read_u32(dev, "ti,driver-strength-ohm", &drv_strength);
+ if (ret)
+ return ret;
+
+ switch (drv_strength) {
+ case 50:
+ plat->drv_strength = DRIVER_STRENGTH_50_OHM;
+ break;
+ case 33:
+ plat->drv_strength = DRIVER_STRENGTH_33_OHM;
+ break;
+ case 66:
+ plat->drv_strength = DRIVER_STRENGTH_66_OHM;
+ break;
+ case 100:
+ plat->drv_strength = DRIVER_STRENGTH_100_OHM;
+ break;
+ case 40:
+ plat->drv_strength = DRIVER_STRENGTH_40_OHM;
+ break;
+ default:
+ dev_err(dev, "Invalid driver strength\n");
+ return -EINVAL;
+ }
+
+ ret = mmc_of_parse(dev, cfg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int am654_sdhci_bind(struct udevice *dev)
+{
+ struct am654_sdhci_plat *plat = dev_get_platdata(dev);
+
+ return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static const struct udevice_id am654_sdhci_ids[] = {
+ { .compatible = "ti,am654-sdhci-5.1" },
+ { }
+};
+
+U_BOOT_DRIVER(am654_sdhci_drv) = {
+ .name = "am654_sdhci",
+ .id = UCLASS_MMC,
+ .of_match = am654_sdhci_ids,
+ .ofdata_to_platdata = am654_sdhci_ofdata_to_platdata,
+ .ops = &sdhci_ops,
+ .bind = am654_sdhci_bind,
+ .probe = am654_sdhci_probe,
+ .priv_auto_alloc_size = sizeof(struct sdhci_host),
+ .platdata_auto_alloc_size = sizeof(struct am654_sdhci_plat),
+};
diff --git a/drivers/mmc/k3_arsan_sdhci.c b/drivers/mmc/k3_arsan_sdhci.c
deleted file mode 100644
index d5f2857..0000000
--- a/drivers/mmc/k3_arsan_sdhci.c
+++ /dev/null
@@ -1,109 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
- *
- * Texas Instruments' K3 SD Host Controller Interface
- */
-
-#include <clk.h>
-#include <common.h>
-#include <dm.h>
-#include <malloc.h>
-#include <power-domain.h>
-#include <sdhci.h>
-
-#define K3_ARASAN_SDHCI_MIN_FREQ 0
-
-struct k3_arasan_sdhci_plat {
- struct mmc_config cfg;
- struct mmc mmc;
- unsigned int f_max;
-};
-
-static int k3_arasan_sdhci_probe(struct udevice *dev)
-{
- struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
- struct sdhci_host *host = dev_get_priv(dev);
- struct power_domain sdhci_pwrdmn;
- struct clk clk;
- unsigned long clock;
- int ret;
-
- ret = power_domain_get_by_index(dev, &sdhci_pwrdmn, 0);
- if (ret) {
- dev_err(dev, "failed to get power domain\n");
- return ret;
- }
-
- ret = power_domain_on(&sdhci_pwrdmn);
- if (ret) {
- dev_err(dev, "Power domain on failed\n");
- return ret;
- }
-
- ret = clk_get_by_index(dev, 0, &clk);
- if (ret) {
- dev_err(dev, "failed to get clock\n");
- return ret;
- }
-
- clock = clk_get_rate(&clk);
- if (IS_ERR_VALUE(clock)) {
- dev_err(dev, "failed to get rate\n");
- return clock;
- }
-
- host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
- SDHCI_QUIRK_BROKEN_R1B;
-
- host->max_clk = clock;
-
- ret = sdhci_setup_cfg(&plat->cfg, host, plat->f_max,
- K3_ARASAN_SDHCI_MIN_FREQ);
- host->mmc = &plat->mmc;
- if (ret)
- return ret;
- host->mmc->priv = host;
- host->mmc->dev = dev;
- upriv->mmc = host->mmc;
-
- return sdhci_probe(dev);
-}
-
-static int k3_arasan_sdhci_ofdata_to_platdata(struct udevice *dev)
-{
- struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev);
- struct sdhci_host *host = dev_get_priv(dev);
-
- host->name = dev->name;
- host->ioaddr = (void *)dev_read_addr(dev);
- host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
- plat->f_max = dev_read_u32_default(dev, "max-frequency", 0);
-
- return 0;
-}
-
-static int k3_arasan_sdhci_bind(struct udevice *dev)
-{
- struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev);
-
- return sdhci_bind(dev, &plat->mmc, &plat->cfg);
-}
-
-static const struct udevice_id k3_arasan_sdhci_ids[] = {
- { .compatible = "arasan,sdhci-5.1" },
- { }
-};
-
-U_BOOT_DRIVER(k3_arasan_sdhci_drv) = {
- .name = "k3_arasan_sdhci",
- .id = UCLASS_MMC,
- .of_match = k3_arasan_sdhci_ids,
- .ofdata_to_platdata = k3_arasan_sdhci_ofdata_to_platdata,
- .ops = &sdhci_ops,
- .bind = k3_arasan_sdhci_bind,
- .probe = k3_arasan_sdhci_probe,
- .priv_auto_alloc_size = sizeof(struct sdhci_host),
- .platdata_auto_alloc_size = sizeof(struct k3_arasan_sdhci_plat),
-};
diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index cb623d5..dd3d557 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -68,15 +68,15 @@
if (host->bus_width == 8)
host->host_caps |= MMC_MODE_8BIT;
- ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
-
host->mmc = &plat->mmc;
- if (ret)
- return ret;
host->mmc->priv = &prv->host;
host->mmc->dev = dev;
upriv->mmc = host->mmc;
+ ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
+ if (ret)
+ return ret;
+
return sdhci_probe(dev);
}
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index c4e8879..0a0770c 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -8,6 +8,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <errno.h>
#include <malloc.h>
#include <mmc.h>
@@ -409,7 +410,7 @@
return 0;
}
#endif
-static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
+int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
{
struct sdhci_host *host = mmc->priv;
unsigned int div, clk = 0, timeout;
@@ -533,6 +534,34 @@
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
}
+void sdhci_set_uhs_timing(struct sdhci_host *host)
+{
+ struct mmc *mmc = (struct mmc *)host->mmc;
+ u32 reg;
+
+ reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ reg &= ~SDHCI_CTRL_UHS_MASK;
+
+ switch (mmc->selected_mode) {
+ case UHS_SDR50:
+ case MMC_HS_52:
+ reg |= SDHCI_CTRL_UHS_SDR50;
+ break;
+ case UHS_DDR50:
+ case MMC_DDR_52:
+ reg |= SDHCI_CTRL_UHS_DDR50;
+ break;
+ case UHS_SDR104:
+ case MMC_HS_200:
+ reg |= SDHCI_CTRL_UHS_SDR104;
+ break;
+ default:
+ reg |= SDHCI_CTRL_UHS_SDR12;
+ }
+
+ sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
+}
+
#ifdef CONFIG_DM_MMC
static int sdhci_set_ios(struct udevice *dev)
{
@@ -583,7 +612,7 @@
/* If available, call the driver specific "post" set_ios() function */
if (host->ops && host->ops->set_ios_post)
- host->ops->set_ios_post(host);
+ return host->ops->set_ios_post(host);
return 0;
}
@@ -681,8 +710,18 @@
u32 f_max, u32 f_min)
{
u32 caps, caps_1 = 0;
+#if CONFIG_IS_ENABLED(DM_MMC)
+ u32 mask[2] = {0};
+ int ret;
+ ret = dev_read_u32_array(host->mmc->dev, "sdhci-caps-mask",
+ mask, 2);
+ if (ret && ret != -1)
+ return ret;
+ caps = ~mask[1] & sdhci_readl(host, SDHCI_CAPABILITIES);
+#else
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+#endif
#ifdef CONFIG_MMC_SDHCI_SDMA
if (!(caps & SDHCI_CAN_DO_SDMA)) {
@@ -722,7 +761,11 @@
/* Check whether the clock multiplier is supported or not */
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
+#if CONFIG_IS_ENABLED(DM_MMC)
+ caps_1 = ~mask[0] & sdhci_readl(host, SDHCI_CAPABILITIES_1);
+#else
caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+#endif
host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >>
SDHCI_CLOCK_MUL_SHIFT;
}
@@ -779,9 +822,6 @@
cfg->host_caps &= ~MMC_MODE_HS_52MHz;
}
- if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
- caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
-
if (!(cfg->voltages & MMC_VDD_165_195) ||
(host->quirks & SDHCI_QUIRK_NO_1_8_V))
caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c
index b576511..829b756 100644
--- a/drivers/mmc/xenon_sdhci.c
+++ b/drivers/mmc/xenon_sdhci.c
@@ -326,7 +326,7 @@
}
/* Platform specific function for post set_ios configuration */
-static void xenon_sdhci_set_ios_post(struct sdhci_host *host)
+static int xenon_sdhci_set_ios_post(struct sdhci_host *host)
{
struct xenon_sdhci_priv *priv = host->mmc->priv;
uint speed = host->mmc->tran_speed;
@@ -364,6 +364,8 @@
/* Re-init the PHY */
xenon_mmc_phy_set(host);
+
+ return 0;
}
/* Install a driver specific handler for post set_ios configuration */
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index 0802378..c525084 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -48,11 +48,6 @@
[MMC_HS_200] = MMC_HS200_BUS_SPEED,
};
-#define SDHCI_HOST_CTRL2 0x3E
-#define SDHCI_CTRL2_MODE_MASK 0x7
-#define SDHCI_18V_SIGNAL 0x8
-#define SDHCI_CTRL_EXEC_TUNING 0x0040
-#define SDHCI_CTRL_TUNED_CLK 0x80
#define SDHCI_TUNING_LOOP_COUNT 40
static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid)
@@ -99,9 +94,9 @@
host = priv->host;
deviceid = priv->deviceid;
- ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl |= SDHCI_CTRL_EXEC_TUNING;
- sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2);
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
mdelay(1);
@@ -133,7 +128,7 @@
sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
mmc_send_cmd(mmc, &cmd, NULL);
- ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
udelay(1);
@@ -142,7 +137,7 @@
if (tuning_loop_counter < 0) {
ctrl &= ~SDHCI_CTRL_TUNED_CLK;
- sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2);
+ sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL2);
}
if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
@@ -184,36 +179,14 @@
return;
if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
- reg = sdhci_readw(host, SDHCI_HOST_CTRL2);
- reg |= SDHCI_18V_SIGNAL;
- sdhci_writew(host, reg, SDHCI_HOST_CTRL2);
+ reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ reg |= SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
}
if (mmc->selected_mode > SD_HS &&
- mmc->selected_mode <= UHS_DDR50) {
- reg = sdhci_readw(host, SDHCI_HOST_CTRL2);
- reg &= ~SDHCI_CTRL2_MODE_MASK;
- switch (mmc->selected_mode) {
- case UHS_SDR12:
- reg |= UHS_SDR12_BUS_SPEED;
- break;
- case UHS_SDR25:
- reg |= UHS_SDR25_BUS_SPEED;
- break;
- case UHS_SDR50:
- reg |= UHS_SDR50_BUS_SPEED;
- break;
- case UHS_SDR104:
- reg |= UHS_SDR104_BUS_SPEED;
- break;
- case UHS_DDR50:
- reg |= UHS_DDR50_BUS_SPEED;
- break;
- default:
- break;
- }
- sdhci_writew(host, reg, SDHCI_HOST_CTRL2);
- }
+ mmc->selected_mode <= UHS_DDR50)
+ sdhci_set_uhs_timing(host);
}
#endif
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 635f8d7..883b849 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -24,6 +24,18 @@
This is currently implemented in net/mdio-uclass.c
Look in include/miiphy.h for details.
+config DM_MDIO_MUX
+ bool "Enable Driver Model for MDIO MUX devices"
+ depends on DM_MDIO
+ help
+ Enable driver model for MDIO MUX devices
+
+ Adds UCLASS_MDIO_MUX DM class supporting MDIO MUXes. Useful for
+ systems that support DM_MDIO and integrate one or multiple muxes on
+ the MDIO bus.
+ This is currently implemented in net/mdio-mux-uclass.c
+ Look in include/miiphy.h for details.
+
config MDIO_SANDBOX
depends on DM_MDIO && SANDBOX
default y
@@ -34,6 +46,16 @@
This driver is used in for testing in test/dm/mdio.c
+config MDIO_MUX_SANDBOX
+ depends on DM_MDIO_MUX && MDIO_SANDBOX
+ default y
+ bool "Sandbox: Mocked MDIO-MUX driver"
+ help
+ This driver implements dummy select/deselect ops mimicking a MUX on
+ the MDIO bux. It uses mdio_sandbox driver as parent MDIO.
+
+ This driver is used for testing in test/dm/mdio.c
+
menuconfig NETDEVICES
bool "Network device support"
depends on NET
@@ -566,4 +588,19 @@
This driver supports HIGMACV300 Ethernet controller found on
HiSilicon SoCs.
+config FSL_ENETC
+ bool "NXP ENETC Ethernet controller"
+ depends on DM_PCI && DM_ETH && DM_MDIO
+ help
+ This driver supports the NXP ENETC Ethernet controller found on some
+ of the NXP SoCs.
+
+config MDIO_MUX_I2CREG
+ bool "MDIO MUX accessed as a register over I2C"
+ depends on DM_MDIO_MUX && DM_I2C
+ help
+ This driver is used for MDIO muxes driven by writing to a register of
+ an I2C chip. The board it was developed for uses a mux controlled by
+ on-board FPGA which in turn is accessed as a chip over I2C.
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 4003842..71c0889 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -37,6 +37,8 @@
obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o
obj-$(CONFIG_MACB) += macb.o
obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
+obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o
+obj-$(CONFIG_MDIO_MUX_SANDBOX) += mdio_mux_sandbox.o
obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o
obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o
obj-$(CONFIG_MVGBE) += mvgbe.o
@@ -78,3 +80,4 @@
obj-y += mscc_eswitch/
obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o
obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
+obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 2c5d956..c4fe40b 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -480,18 +480,16 @@
static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
{
struct phy_device *phydev;
- int mask = 0xffffffff, ret;
+ int phy_addr = -1, ret;
#ifdef CONFIG_PHY_ADDR
- mask = 1 << CONFIG_PHY_ADDR;
+ phy_addr = CONFIG_PHY_ADDR;
#endif
- phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
+ phydev = phy_connect(priv->bus, phy_addr, dev, priv->interface);
if (!phydev)
return -ENODEV;
- phy_connect_dev(phydev, dev);
-
phydev->supported &= PHY_GBIT_FEATURES;
if (priv->max_speed) {
ret = phy_set_supported(phydev, priv->max_speed);
@@ -677,10 +675,10 @@
struct dw_eth_dev *priv = dev_get_priv(dev);
u32 iobase = pdata->iobase;
ulong ioaddr;
- int ret;
+ int ret, err;
struct reset_ctl_bulk reset_bulk;
#ifdef CONFIG_CLK
- int i, err, clock_nb;
+ int i, clock_nb;
priv->clock_count = 0;
clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
@@ -753,13 +751,23 @@
priv->interface = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
- dw_mdio_init(dev->name, dev);
+ ret = dw_mdio_init(dev->name, dev);
+ if (ret) {
+ err = ret;
+ goto mdio_err;
+ }
priv->bus = miiphy_get_dev_by_name(dev->name);
ret = dw_phy_init(priv, dev);
debug("%s, ret=%d\n", __func__, ret);
+ if (!ret)
+ return 0;
- return ret;
+ /* continue here for cleanup if no PHY found */
+ err = ret;
+ mdio_unregister(priv->bus);
+ mdio_free(priv->bus);
+mdio_err:
#ifdef CONFIG_CLK
clk_err:
@@ -767,8 +775,8 @@
if (ret)
pr_err("failed to disable all clocks\n");
- return err;
#endif
+ return err;
}
static int designware_eth_remove(struct udevice *dev)
diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
new file mode 100644
index 0000000..e7c5062
--- /dev/null
+++ b/drivers/net/fsl_enetc.c
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ENETC ethernet controller driver
+ * Copyright 2017-2019 NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <memalign.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <miiphy.h>
+
+#include "fsl_enetc.h"
+
+/*
+ * Bind the device:
+ * - set a more explicit name on the interface
+ */
+static int enetc_bind(struct udevice *dev)
+{
+ char name[16];
+ static int eth_num_devices;
+
+ /*
+ * prefer using PCI function numbers to number interfaces, but these
+ * are only available if dts nodes are present. For PCI they are
+ * optional, handle that case too. Just in case some nodes are present
+ * and some are not, use different naming scheme - enetc-N based on
+ * PCI function # and enetc#N based on interface count
+ */
+ if (ofnode_valid(dev->node))
+ sprintf(name, "enetc-%u", PCI_FUNC(pci_get_devfn(dev)));
+ else
+ sprintf(name, "enetc#%u", eth_num_devices++);
+ device_set_name(dev, name);
+
+ return 0;
+}
+
+/* MDIO wrappers, we're using these to drive internal MDIO to get to serdes */
+static int enetc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct enetc_mdio_priv priv;
+
+ priv.regs_base = bus->priv;
+ return enetc_mdio_read_priv(&priv, addr, devad, reg);
+}
+
+static int enetc_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct enetc_mdio_priv priv;
+
+ priv.regs_base = bus->priv;
+ return enetc_mdio_write_priv(&priv, addr, devad, reg, val);
+}
+
+/* only interfaces that can pin out through serdes have internal MDIO */
+static bool enetc_has_imdio(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+
+ return !!(priv->imdio.priv);
+}
+
+/* set up serdes for SGMII */
+static int enetc_init_sgmii(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ bool is2500 = false;
+ u16 reg;
+
+ if (!enetc_has_imdio(dev))
+ return 0;
+
+ if (priv->if_type == PHY_INTERFACE_MODE_SGMII_2500)
+ is2500 = true;
+
+ /*
+ * Set to SGMII mode, for 1Gbps enable AN, for 2.5Gbps set fixed speed.
+ * Although fixed speed is 1Gbps, we could be running at 2.5Gbps based
+ * on PLL configuration. Setting 1G for 2.5G here is counter intuitive
+ * but intentional.
+ */
+ reg = ENETC_PCS_IF_MODE_SGMII;
+ reg |= is2500 ? ENETC_PCS_IF_MODE_SPEED_1G : ENETC_PCS_IF_MODE_SGMII_AN;
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+ ENETC_PCS_IF_MODE, reg);
+
+ /* Dev ability - SGMII */
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+ ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SGMII);
+
+ /* Adjust link timer for SGMII */
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+ ENETC_PCS_LINK_TIMER1, ENETC_PCS_LINK_TIMER1_VAL);
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+ ENETC_PCS_LINK_TIMER2, ENETC_PCS_LINK_TIMER2_VAL);
+
+ reg = ENETC_PCS_CR_DEF_VAL;
+ reg |= is2500 ? ENETC_PCS_CR_RST : ENETC_PCS_CR_RESET_AN;
+ /* restart PCS AN */
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+ ENETC_PCS_CR, reg);
+
+ return 0;
+}
+
+/* set up MAC for RGMII */
+static int enetc_init_rgmii(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ u32 if_mode;
+
+ /* enable RGMII AN */
+ if_mode = enetc_read_port(priv, ENETC_PM_IF_MODE);
+ if_mode |= ENETC_PM_IF_MODE_AN_ENA;
+ enetc_write_port(priv, ENETC_PM_IF_MODE, if_mode);
+
+ return 0;
+}
+
+/* set up MAC and serdes for SXGMII */
+static int enetc_init_sxgmii(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ u32 if_mode;
+
+ /* set ifmode to (US)XGMII */
+ if_mode = enetc_read_port(priv, ENETC_PM_IF_MODE);
+ if_mode &= ~ENETC_PM_IF_IFMODE_MASK;
+ enetc_write_port(priv, ENETC_PM_IF_MODE, if_mode);
+
+ if (!enetc_has_imdio(dev))
+ return 0;
+
+ /* Dev ability - SXGMII */
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL,
+ ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII);
+
+ /* Restart PCS AN */
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL,
+ ENETC_PCS_CR,
+ ENETC_PCS_CR_RST | ENETC_PCS_CR_RESET_AN);
+
+ return 0;
+}
+
+/* Apply protocol specific configuration to MAC, serdes as needed */
+static void enetc_start_pcs(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ const char *if_str;
+
+ priv->if_type = PHY_INTERFACE_MODE_NONE;
+
+ /* check internal mdio capability, not all ports need it */
+ if (enetc_read_port(priv, ENETC_PCAPR0) & ENETC_PCAPRO_MDIO) {
+ /*
+ * set up internal MDIO, this is part of ETH PCI function and is
+ * used to access serdes / internal SoC PHYs.
+ * We don't currently register it as a MDIO bus as it goes away
+ * when the interface is removed, so it can't practically be
+ * used in the console.
+ */
+ priv->imdio.read = enetc_mdio_read;
+ priv->imdio.write = enetc_mdio_write;
+ priv->imdio.priv = priv->port_regs + ENETC_PM_IMDIO_BASE;
+ strncpy(priv->imdio.name, dev->name, MDIO_NAME_LEN);
+ }
+
+ if (!ofnode_valid(dev->node)) {
+ enetc_dbg(dev, "no enetc ofnode found, skipping PCS set-up\n");
+ return;
+ }
+
+ if_str = ofnode_read_string(dev->node, "phy-mode");
+ if (if_str)
+ priv->if_type = phy_get_interface_by_name(if_str);
+ else
+ enetc_dbg(dev,
+ "phy-mode property not found, defaulting to SGMII\n");
+ if (priv->if_type < 0)
+ priv->if_type = PHY_INTERFACE_MODE_NONE;
+
+ switch (priv->if_type) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_SGMII_2500:
+ enetc_init_sgmii(dev);
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ enetc_init_rgmii(dev);
+ break;
+ case PHY_INTERFACE_MODE_XGMII:
+ enetc_init_sxgmii(dev);
+ break;
+ };
+}
+
+/* Configure the actual/external ethernet PHY, if one is found */
+static void enetc_start_phy(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ struct udevice *miidev;
+ struct phy_device *phy;
+ u32 phandle, phy_id;
+ ofnode phy_node;
+ int supported;
+
+ if (!ofnode_valid(dev->node)) {
+ enetc_dbg(dev, "no enetc ofnode found, skipping PHY set-up\n");
+ return;
+ }
+
+ if (ofnode_read_u32(dev->node, "phy-handle", &phandle)) {
+ enetc_dbg(dev, "phy-handle not found, skipping PHY set-up\n");
+ return;
+ }
+
+ phy_node = ofnode_get_by_phandle(phandle);
+ if (!ofnode_valid(phy_node)) {
+ enetc_dbg(dev, "invalid phy node, skipping PHY set-up\n");
+ return;
+ }
+ enetc_dbg(dev, "phy node: %s\n", ofnode_get_name(phy_node));
+
+ if (ofnode_read_u32(phy_node, "reg", &phy_id)) {
+ enetc_dbg(dev,
+ "missing reg in PHY node, skipping PHY set-up\n");
+ return;
+ }
+
+ if (uclass_get_device_by_ofnode(UCLASS_MDIO,
+ ofnode_get_parent(phy_node),
+ &miidev)) {
+ enetc_dbg(dev, "can't find MDIO bus for node %s\n",
+ ofnode_get_name(ofnode_get_parent(phy_node)));
+ return;
+ }
+
+ phy = dm_mdio_phy_connect(miidev, phy_id, dev, priv->if_type);
+ if (!phy) {
+ enetc_dbg(dev, "dm_mdio_phy_connect returned null\n");
+ return;
+ }
+
+ supported = GENMASK(6, 0); /* speeds up to 1G & AN */
+ phy->advertising = phy->supported & supported;
+ phy_config(phy);
+ phy_startup(phy);
+}
+
+/*
+ * Probe ENETC driver:
+ * - initialize port and station interface BARs
+ */
+static int enetc_probe(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+
+ if (ofnode_valid(dev->node) && !ofnode_is_available(dev->node)) {
+ enetc_dbg(dev, "interface disabled\n");
+ return -ENODEV;
+ }
+
+ priv->enetc_txbd = memalign(ENETC_BD_ALIGN,
+ sizeof(struct enetc_tx_bd) * ENETC_BD_CNT);
+ priv->enetc_rxbd = memalign(ENETC_BD_ALIGN,
+ sizeof(union enetc_rx_bd) * ENETC_BD_CNT);
+
+ if (!priv->enetc_txbd || !priv->enetc_rxbd) {
+ /* free should be able to handle NULL, just free all pointers */
+ free(priv->enetc_txbd);
+ free(priv->enetc_rxbd);
+
+ return -ENOMEM;
+ }
+
+ /* initialize register */
+ priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
+ if (!priv->regs_base) {
+ enetc_dbg(dev, "failed to map BAR0\n");
+ return -EINVAL;
+ }
+ priv->port_regs = priv->regs_base + ENETC_PORT_REGS_OFF;
+
+ dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+
+ return 0;
+}
+
+/*
+ * Remove the driver from an interface:
+ * - free up allocated memory
+ */
+static int enetc_remove(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+
+ free(priv->enetc_txbd);
+ free(priv->enetc_rxbd);
+
+ return 0;
+}
+
+/* ENETC Port MAC address registers, accepts big-endian format */
+static void enetc_set_primary_mac_addr(struct enetc_priv *priv, const u8 *addr)
+{
+ u16 lower = *(const u16 *)(addr + 4);
+ u32 upper = *(const u32 *)addr;
+
+ enetc_write_port(priv, ENETC_PSIPMAR0, upper);
+ enetc_write_port(priv, ENETC_PSIPMAR1, lower);
+}
+
+/* Configure port parameters (# of rings, frame size, enable port) */
+static void enetc_enable_si_port(struct enetc_priv *priv)
+{
+ u32 val;
+
+ /* set Rx/Tx BDR count */
+ val = ENETC_PSICFGR_SET_TXBDR(ENETC_TX_BDR_CNT);
+ val |= ENETC_PSICFGR_SET_RXBDR(ENETC_RX_BDR_CNT);
+ enetc_write_port(priv, ENETC_PSICFGR(0), val);
+ /* set Rx max frame size */
+ enetc_write_port(priv, ENETC_PM_MAXFRM, ENETC_RX_MAXFRM_SIZE);
+ /* enable MAC port */
+ enetc_write_port(priv, ENETC_PM_CC, ENETC_PM_CC_RX_TX_EN);
+ /* enable port */
+ enetc_write_port(priv, ENETC_PMR, ENETC_PMR_SI0_EN);
+ /* set SI cache policy */
+ enetc_write(priv, ENETC_SICAR0,
+ ENETC_SICAR_RD_CFG | ENETC_SICAR_WR_CFG);
+ /* enable SI */
+ enetc_write(priv, ENETC_SIMR, ENETC_SIMR_EN);
+}
+
+/* returns DMA address for a given buffer index */
+static inline u64 enetc_rxb_address(struct udevice *dev, int i)
+{
+ return cpu_to_le64(dm_pci_virt_to_mem(dev, net_rx_packets[i]));
+}
+
+/*
+ * Setup a single Tx BD Ring (ID = 0):
+ * - set Tx buffer descriptor address
+ * - set the BD count
+ * - initialize the producer and consumer index
+ */
+static void enetc_setup_tx_bdr(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ struct bd_ring *tx_bdr = &priv->tx_bdr;
+ u64 tx_bd_add = (u64)priv->enetc_txbd;
+
+ /* used later to advance to the next Tx BD */
+ tx_bdr->bd_count = ENETC_BD_CNT;
+ tx_bdr->next_prod_idx = 0;
+ tx_bdr->next_cons_idx = 0;
+ tx_bdr->cons_idx = priv->regs_base +
+ ENETC_BDR(TX, ENETC_TX_BDR_ID, ENETC_TBCIR);
+ tx_bdr->prod_idx = priv->regs_base +
+ ENETC_BDR(TX, ENETC_TX_BDR_ID, ENETC_TBPIR);
+
+ /* set Tx BD address */
+ enetc_bdr_write(priv, TX, ENETC_TX_BDR_ID, ENETC_TBBAR0,
+ lower_32_bits(tx_bd_add));
+ enetc_bdr_write(priv, TX, ENETC_TX_BDR_ID, ENETC_TBBAR1,
+ upper_32_bits(tx_bd_add));
+ /* set Tx 8 BD count */
+ enetc_bdr_write(priv, TX, ENETC_TX_BDR_ID, ENETC_TBLENR,
+ tx_bdr->bd_count);
+
+ /* reset both producer/consumer indexes */
+ enetc_write_reg(tx_bdr->cons_idx, tx_bdr->next_cons_idx);
+ enetc_write_reg(tx_bdr->prod_idx, tx_bdr->next_prod_idx);
+
+ /* enable TX ring */
+ enetc_bdr_write(priv, TX, ENETC_TX_BDR_ID, ENETC_TBMR, ENETC_TBMR_EN);
+}
+
+/*
+ * Setup a single Rx BD Ring (ID = 0):
+ * - set Rx buffer descriptors address (one descriptor per buffer)
+ * - set buffer size as max frame size
+ * - enable Rx ring
+ * - reset consumer and producer indexes
+ * - set buffer for each descriptor
+ */
+static void enetc_setup_rx_bdr(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ struct bd_ring *rx_bdr = &priv->rx_bdr;
+ u64 rx_bd_add = (u64)priv->enetc_rxbd;
+ int i;
+
+ /* used later to advance to the next BD produced by ENETC HW */
+ rx_bdr->bd_count = ENETC_BD_CNT;
+ rx_bdr->next_prod_idx = 0;
+ rx_bdr->next_cons_idx = 0;
+ rx_bdr->cons_idx = priv->regs_base +
+ ENETC_BDR(RX, ENETC_RX_BDR_ID, ENETC_RBCIR);
+ rx_bdr->prod_idx = priv->regs_base +
+ ENETC_BDR(RX, ENETC_RX_BDR_ID, ENETC_RBPIR);
+
+ /* set Rx BD address */
+ enetc_bdr_write(priv, RX, ENETC_RX_BDR_ID, ENETC_RBBAR0,
+ lower_32_bits(rx_bd_add));
+ enetc_bdr_write(priv, RX, ENETC_RX_BDR_ID, ENETC_RBBAR1,
+ upper_32_bits(rx_bd_add));
+ /* set Rx BD count (multiple of 8) */
+ enetc_bdr_write(priv, RX, ENETC_RX_BDR_ID, ENETC_RBLENR,
+ rx_bdr->bd_count);
+ /* set Rx buffer size */
+ enetc_bdr_write(priv, RX, ENETC_RX_BDR_ID, ENETC_RBBSR, PKTSIZE_ALIGN);
+
+ /* fill Rx BD */
+ memset(priv->enetc_rxbd, 0,
+ rx_bdr->bd_count * sizeof(union enetc_rx_bd));
+ for (i = 0; i < rx_bdr->bd_count; i++) {
+ priv->enetc_rxbd[i].w.addr = enetc_rxb_address(dev, i);
+ /* each RX buffer must be aligned to 64B */
+ WARN_ON(priv->enetc_rxbd[i].w.addr & (ARCH_DMA_MINALIGN - 1));
+ }
+
+ /* reset producer (ENETC owned) and consumer (SW owned) index */
+ enetc_write_reg(rx_bdr->cons_idx, rx_bdr->next_cons_idx);
+ enetc_write_reg(rx_bdr->prod_idx, rx_bdr->next_prod_idx);
+
+ /* enable Rx ring */
+ enetc_bdr_write(priv, RX, ENETC_RX_BDR_ID, ENETC_RBMR, ENETC_RBMR_EN);
+}
+
+/*
+ * Start ENETC interface:
+ * - perform FLR
+ * - enable access to port and SI registers
+ * - set mac address
+ * - setup TX/RX buffer descriptors
+ * - enable Tx/Rx rings
+ */
+static int enetc_start(struct udevice *dev)
+{
+ struct eth_pdata *plat = dev_get_platdata(dev);
+ struct enetc_priv *priv = dev_get_priv(dev);
+
+ /* reset and enable the PCI device */
+ dm_pci_flr(dev);
+ dm_pci_clrset_config16(dev, PCI_COMMAND, 0,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ if (!is_valid_ethaddr(plat->enetaddr)) {
+ enetc_dbg(dev, "invalid MAC address, generate random ...\n");
+ net_random_ethaddr(plat->enetaddr);
+ }
+ enetc_set_primary_mac_addr(priv, plat->enetaddr);
+
+ enetc_enable_si_port(priv);
+
+ /* setup Tx/Rx buffer descriptors */
+ enetc_setup_tx_bdr(dev);
+ enetc_setup_rx_bdr(dev);
+
+ enetc_start_pcs(dev);
+ enetc_start_phy(dev);
+
+ return 0;
+}
+
+/*
+ * Stop the network interface:
+ * - just quiesce it, we can wipe all configuration as _start starts from
+ * scratch each time
+ */
+static void enetc_stop(struct udevice *dev)
+{
+ /* FLR is sufficient to quiesce the device */
+ dm_pci_flr(dev);
+}
+
+/*
+ * ENETC transmit packet:
+ * - check if Tx BD ring is full
+ * - set buffer/packet address (dma address)
+ * - set final fragment flag
+ * - try while producer index equals consumer index or timeout
+ */
+static int enetc_send(struct udevice *dev, void *packet, int length)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ struct bd_ring *txr = &priv->tx_bdr;
+ void *nv_packet = (void *)packet;
+ int tries = ENETC_POLL_TRIES;
+ u32 pi, ci;
+
+ pi = txr->next_prod_idx;
+ ci = enetc_read_reg(txr->cons_idx) & ENETC_BDR_IDX_MASK;
+ /* Tx ring is full when */
+ if (((pi + 1) % txr->bd_count) == ci) {
+ enetc_dbg(dev, "Tx BDR full\n");
+ return -ETIMEDOUT;
+ }
+ enetc_dbg(dev, "TxBD[%d]send: pkt_len=%d, buff @0x%x%08x\n", pi, length,
+ upper_32_bits((u64)nv_packet), lower_32_bits((u64)nv_packet));
+
+ /* prepare Tx BD */
+ memset(&priv->enetc_txbd[pi], 0x0, sizeof(struct enetc_tx_bd));
+ priv->enetc_txbd[pi].addr =
+ cpu_to_le64(dm_pci_virt_to_mem(dev, nv_packet));
+ priv->enetc_txbd[pi].buf_len = cpu_to_le16(length);
+ priv->enetc_txbd[pi].frm_len = cpu_to_le16(length);
+ priv->enetc_txbd[pi].flags = cpu_to_le16(ENETC_TXBD_FLAGS_F);
+ dmb();
+ /* send frame: increment producer index */
+ pi = (pi + 1) % txr->bd_count;
+ txr->next_prod_idx = pi;
+ enetc_write_reg(txr->prod_idx, pi);
+ while ((--tries >= 0) &&
+ (pi != (enetc_read_reg(txr->cons_idx) & ENETC_BDR_IDX_MASK)))
+ udelay(10);
+
+ return tries > 0 ? 0 : -ETIMEDOUT;
+}
+
+/*
+ * Receive frame:
+ * - wait for the next BD to get ready bit set
+ * - clean up the descriptor
+ * - move on and indicate to HW that the cleaned BD is available for Rx
+ */
+static int enetc_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ struct bd_ring *rxr = &priv->rx_bdr;
+ int tries = ENETC_POLL_TRIES;
+ int pi = rxr->next_prod_idx;
+ int ci = rxr->next_cons_idx;
+ u32 status;
+ int len;
+ u8 rdy;
+
+ do {
+ dmb();
+ status = le32_to_cpu(priv->enetc_rxbd[pi].r.lstatus);
+ /* check if current BD is ready to be consumed */
+ rdy = ENETC_RXBD_STATUS_R(status);
+ } while (--tries >= 0 && !rdy);
+
+ if (!rdy)
+ return -EAGAIN;
+
+ dmb();
+ len = le16_to_cpu(priv->enetc_rxbd[pi].r.buf_len);
+ *packetp = (uchar *)enetc_rxb_address(dev, pi);
+ enetc_dbg(dev, "RxBD[%d]: len=%d err=%d pkt=0x%x%08x\n", pi, len,
+ ENETC_RXBD_STATUS_ERRORS(status),
+ upper_32_bits((u64)*packetp), lower_32_bits((u64)*packetp));
+
+ /* BD clean up and advance to next in ring */
+ memset(&priv->enetc_rxbd[pi], 0, sizeof(union enetc_rx_bd));
+ priv->enetc_rxbd[pi].w.addr = enetc_rxb_address(dev, pi);
+ rxr->next_prod_idx = (pi + 1) % rxr->bd_count;
+ ci = (ci + 1) % rxr->bd_count;
+ rxr->next_cons_idx = ci;
+ dmb();
+ /* free up the slot in the ring for HW */
+ enetc_write_reg(rxr->cons_idx, ci);
+
+ return len;
+}
+
+static const struct eth_ops enetc_ops = {
+ .start = enetc_start,
+ .send = enetc_send,
+ .recv = enetc_recv,
+ .stop = enetc_stop,
+};
+
+U_BOOT_DRIVER(eth_enetc) = {
+ .name = "enetc_eth",
+ .id = UCLASS_ETH,
+ .bind = enetc_bind,
+ .probe = enetc_probe,
+ .remove = enetc_remove,
+ .ops = &enetc_ops,
+ .priv_auto_alloc_size = sizeof(struct enetc_priv),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+static struct pci_device_id enetc_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_ETH) },
+ {}
+};
+
+U_BOOT_PCI_DEVICE(eth_enetc, enetc_ids);
diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h
new file mode 100644
index 0000000..0bb4cdf
--- /dev/null
+++ b/drivers/net/fsl_enetc.h
@@ -0,0 +1,229 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * ENETC ethernet controller driver
+ * Copyright 2017-2019 NXP
+ */
+
+#ifndef _ENETC_H
+#define _ENETC_H
+
+#define enetc_dbg(dev, fmt, args...) debug("%s:" fmt, dev->name, ##args)
+
+/* PCI function IDs */
+#define PCI_DEVICE_ID_ENETC_ETH 0xE100
+#define PCI_DEVICE_ID_ENETC_MDIO 0xEE01
+
+/* ENETC Ethernet controller registers */
+/* Station interface register offsets */
+#define ENETC_SIMR 0x000
+#define ENETC_SIMR_EN BIT(31)
+#define ENETC_SICAR0 0x040
+/* write cache cfg: snoop, no allocate, data & BD coherent */
+#define ENETC_SICAR_WR_CFG 0x6767
+/* read cache cfg: coherent copy, look up, don't alloc in cache */
+#define ENETC_SICAR_RD_CFG 0x27270000
+#define ENETC_SIROCT 0x300
+#define ENETC_SIRFRM 0x308
+#define ENETC_SITOCT 0x320
+#define ENETC_SITFRM 0x328
+
+/* Rx/Tx Buffer Descriptor Ring registers */
+enum enetc_bdr_type {TX, RX};
+#define ENETC_BDR(type, n, off) (0x8000 + (type) * 0x100 + (n) * 0x200 + (off))
+#define ENETC_BDR_IDX_MASK 0xffff
+
+/* Rx BDR reg offsets */
+#define ENETC_RBMR 0x00
+#define ENETC_RBMR_EN BIT(31)
+#define ENETC_RBBSR 0x08
+/* initial consumer index for Rx BDR */
+#define ENETC_RBCIR 0x0c
+#define ENETC_RBBAR0 0x10
+#define ENETC_RBBAR1 0x14
+#define ENETC_RBPIR 0x18
+#define ENETC_RBLENR 0x20
+
+/* Tx BDR reg offsets */
+#define ENETC_TBMR 0x00
+#define ENETC_TBMR_EN BIT(31)
+#define ENETC_TBBAR0 0x10
+#define ENETC_TBBAR1 0x14
+#define ENETC_TBPIR 0x18
+#define ENETC_TBCIR 0x1c
+#define ENETC_TBLENR 0x20
+
+/* Port registers offset */
+#define ENETC_PORT_REGS_OFF 0x10000
+
+/* Port registers */
+#define ENETC_PMR 0x0000
+#define ENETC_PMR_SI0_EN BIT(16)
+#define ENETC_PSIPMMR 0x0018
+#define ENETC_PSIPMAR0 0x0100
+#define ENETC_PSIPMAR1 0x0104
+#define ENETC_PCAPR0 0x0900
+#define ENETC_PCAPRO_MDIO BIT(11)
+#define ENETC_PSICFGR(n) (0x0940 + (n) * 0x10)
+#define ENETC_PSICFGR_SET_TXBDR(val) ((val) & 0xff)
+#define ENETC_PSICFGR_SET_RXBDR(val) (((val) & 0xff) << 16)
+/* MAC configuration */
+#define ENETC_PM_CC 0x8008
+#define ENETC_PM_CC_DEFAULT 0x0810
+#define ENETC_PM_CC_RX_TX_EN 0x8813
+#define ENETC_PM_MAXFRM 0x8014
+#define ENETC_RX_MAXFRM_SIZE PKTSIZE_ALIGN
+#define ENETC_PM_IMDIO_BASE 0x8030
+#define ENETC_PM_IF_MODE 0x8300
+#define ENETC_PM_IF_MODE_RG BIT(2)
+#define ENETC_PM_IF_MODE_AN_ENA BIT(15)
+#define ENETC_PM_IF_IFMODE_MASK GENMASK(1, 0)
+
+/* buffer descriptors count must be multiple of 8 and aligned to 128 bytes */
+#define ENETC_BD_CNT CONFIG_SYS_RX_ETH_BUFFER
+#define ENETC_BD_ALIGN 128
+
+/* single pair of Rx/Tx rings */
+#define ENETC_RX_BDR_CNT 1
+#define ENETC_TX_BDR_CNT 1
+#define ENETC_RX_BDR_ID 0
+#define ENETC_TX_BDR_ID 0
+
+/* Tx buffer descriptor */
+struct enetc_tx_bd {
+ __le64 addr;
+ __le16 buf_len;
+ __le16 frm_len;
+ __le16 err_csum;
+ __le16 flags;
+};
+
+#define ENETC_TXBD_FLAGS_F BIT(15)
+#define ENETC_POLL_TRIES 32000
+
+/* Rx buffer descriptor */
+union enetc_rx_bd {
+ /* SW provided BD format */
+ struct {
+ __le64 addr;
+ u8 reserved[8];
+ } w;
+
+ /* ENETC returned BD format */
+ struct {
+ __le16 inet_csum;
+ __le16 parse_summary;
+ __le32 rss_hash;
+ __le16 buf_len;
+ __le16 vlan_opt;
+ union {
+ struct {
+ __le16 flags;
+ __le16 error;
+ };
+ __le32 lstatus;
+ };
+ } r;
+};
+
+#define ENETC_RXBD_STATUS_R(status) (((status) >> 30) & 0x1)
+#define ENETC_RXBD_STATUS_F(status) (((status) >> 31) & 0x1)
+#define ENETC_RXBD_STATUS_ERRORS(status) (((status) >> 16) & 0xff)
+#define ENETC_RXBD_STATUS(flags) ((flags) << 16)
+
+/* Tx/Rx ring info */
+struct bd_ring {
+ void *cons_idx;
+ void *prod_idx;
+ /* next BD index to use */
+ int next_prod_idx;
+ int next_cons_idx;
+ int bd_count;
+};
+
+/* ENETC private structure */
+struct enetc_priv {
+ struct enetc_tx_bd *enetc_txbd;
+ union enetc_rx_bd *enetc_rxbd;
+
+ void *regs_base; /* base ENETC registers */
+ void *port_regs; /* base ENETC port registers */
+
+ /* Rx/Tx buffer descriptor rings info */
+ struct bd_ring tx_bdr;
+ struct bd_ring rx_bdr;
+
+ int if_type;
+ struct mii_dev imdio;
+};
+
+/* register accessors */
+#define enetc_read_reg(x) readl((x))
+#define enetc_write_reg(x, val) writel((val), (x))
+#define enetc_read(priv, off) enetc_read_reg((priv)->regs_base + (off))
+#define enetc_write(priv, off, v) \
+ enetc_write_reg((priv)->regs_base + (off), v)
+
+/* port register accessors */
+#define enetc_port_regs(priv, off) ((priv)->port_regs + (off))
+#define enetc_read_port(priv, off) \
+ enetc_read_reg(enetc_port_regs((priv), (off)))
+#define enetc_write_port(priv, off, v) \
+ enetc_write_reg(enetc_port_regs((priv), (off)), v)
+
+/* BDR register accessors, see ENETC_BDR() */
+#define enetc_bdr_read(priv, t, n, off) \
+ enetc_read(priv, ENETC_BDR(t, n, off))
+#define enetc_bdr_write(priv, t, n, off, val) \
+ enetc_write(priv, ENETC_BDR(t, n, off), val)
+
+/* PCS / internal SoC PHY ID, it defaults to 0 on all interfaces */
+#define ENETC_PCS_PHY_ADDR 0
+
+/* PCS registers */
+#define ENETC_PCS_CR 0x00
+#define ENETC_PCS_CR_RESET_AN 0x1200
+#define ENETC_PCS_CR_DEF_VAL 0x0140
+#define ENETC_PCS_CR_RST BIT(15)
+#define ENETC_PCS_DEV_ABILITY 0x04
+#define ENETC_PCS_DEV_ABILITY_SGMII 0x4001
+#define ENETC_PCS_DEV_ABILITY_SXGMII 0x5001
+#define ENETC_PCS_LINK_TIMER1 0x12
+#define ENETC_PCS_LINK_TIMER1_VAL 0x06a0
+#define ENETC_PCS_LINK_TIMER2 0x13
+#define ENETC_PCS_LINK_TIMER2_VAL 0x0003
+#define ENETC_PCS_IF_MODE 0x14
+#define ENETC_PCS_IF_MODE_SGMII BIT(0)
+#define ENETC_PCS_IF_MODE_SGMII_AN BIT(1)
+#define ENETC_PCS_IF_MODE_SPEED_1G BIT(3)
+
+/* PCS replicator block for USXGMII */
+#define ENETC_PCS_DEVAD_REPL 0x1f
+
+/* ENETC external MDIO registers */
+#define ENETC_MDIO_BASE 0x1c00
+#define ENETC_MDIO_CFG 0x00
+#define ENETC_EMDIO_CFG_C22 0x00809508
+#define ENETC_EMDIO_CFG_C45 0x00809548
+#define ENETC_EMDIO_CFG_RD_ER BIT(1)
+#define ENETC_EMDIO_CFG_BSY BIT(0)
+#define ENETC_MDIO_CTL 0x04
+#define ENETC_MDIO_CTL_READ BIT(15)
+#define ENETC_MDIO_DATA 0x08
+#define ENETC_MDIO_STAT 0x0c
+
+#define ENETC_MDIO_READ_ERR 0xffff
+
+struct enetc_mdio_priv {
+ void *regs_base;
+};
+
+/*
+ * these functions are implemented by ENETC_MDIO and are re-used by ENETC driver
+ * to drive serdes / internal SoC PHYs
+ */
+int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+ int reg);
+int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+ int reg, u16 val);
+
+#endif /* _ENETC_H */
diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c
new file mode 100644
index 0000000..60d2153
--- /dev/null
+++ b/drivers/net/fsl_enetc_mdio.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ENETC ethernet controller driver
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <pci.h>
+#include <miiphy.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <miiphy.h>
+
+#include "fsl_enetc.h"
+
+static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv)
+{
+ while (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY)
+ cpu_relax();
+}
+
+int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+ int reg)
+{
+ if (devad == MDIO_DEVAD_NONE)
+ enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
+ else
+ enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
+ enetc_mdio_wait_bsy(priv);
+
+ if (devad == MDIO_DEVAD_NONE) {
+ enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
+ (addr << 5) | reg);
+ } else {
+ enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
+ enetc_mdio_wait_bsy(priv);
+
+ enetc_write(priv, ENETC_MDIO_STAT, reg);
+ enetc_mdio_wait_bsy(priv);
+
+ enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
+ (addr << 5) | devad);
+ }
+
+ enetc_mdio_wait_bsy(priv);
+ if (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_RD_ER)
+ return ENETC_MDIO_READ_ERR;
+
+ return enetc_read(priv, ENETC_MDIO_DATA);
+}
+
+int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+ int reg, u16 val)
+{
+ if (devad == MDIO_DEVAD_NONE)
+ enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
+ else
+ enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
+ enetc_mdio_wait_bsy(priv);
+
+ if (devad != MDIO_DEVAD_NONE) {
+ enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
+ enetc_write(priv, ENETC_MDIO_STAT, reg);
+ } else {
+ enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + reg);
+ }
+ enetc_mdio_wait_bsy(priv);
+
+ enetc_write(priv, ENETC_MDIO_DATA, val);
+ enetc_mdio_wait_bsy(priv);
+
+ return 0;
+}
+
+/* DM wrappers */
+static int dm_enetc_mdio_read(struct udevice *dev, int addr, int devad, int reg)
+{
+ struct enetc_mdio_priv *priv = dev_get_priv(dev);
+
+ return enetc_mdio_read_priv(priv, addr, devad, reg);
+}
+
+static int dm_enetc_mdio_write(struct udevice *dev, int addr, int devad,
+ int reg, u16 val)
+{
+ struct enetc_mdio_priv *priv = dev_get_priv(dev);
+
+ return enetc_mdio_write_priv(priv, addr, devad, reg, val);
+}
+
+static const struct mdio_ops enetc_mdio_ops = {
+ .read = dm_enetc_mdio_read,
+ .write = dm_enetc_mdio_write,
+};
+
+static int enetc_mdio_bind(struct udevice *dev)
+{
+ char name[16];
+ static int eth_num_devices;
+
+ /*
+ * prefer using PCI function numbers to number interfaces, but these
+ * are only available if dts nodes are present. For PCI they are
+ * optional, handle that case too. Just in case some nodes are present
+ * and some are not, use different naming scheme - enetc-N based on
+ * PCI function # and enetc#N based on interface count
+ */
+ if (ofnode_valid(dev->node))
+ sprintf(name, "emdio-%u", PCI_FUNC(pci_get_devfn(dev)));
+ else
+ sprintf(name, "emdio#%u", eth_num_devices++);
+ device_set_name(dev, name);
+
+ return 0;
+}
+
+static int enetc_mdio_probe(struct udevice *dev)
+{
+ struct enetc_mdio_priv *priv = dev_get_priv(dev);
+
+ priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
+ if (!priv->regs_base) {
+ enetc_dbg(dev, "failed to map BAR0\n");
+ return -EINVAL;
+ }
+
+ priv->regs_base += ENETC_MDIO_BASE;
+
+ dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(enetc_mdio) = {
+ .name = "enetc_mdio",
+ .id = UCLASS_MDIO,
+ .bind = enetc_mdio_bind,
+ .probe = enetc_mdio_probe,
+ .ops = &enetc_mdio_ops,
+ .priv_auto_alloc_size = sizeof(struct enetc_mdio_priv),
+};
+
+static struct pci_device_id enetc_mdio_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_MDIO) },
+};
+
+U_BOOT_PCI_DEVICE(enetc_mdio, enetc_mdio_ids);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index a7eddd6..c99cf66 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -45,9 +45,17 @@
DECLARE_GLOBAL_DATA_PTR;
-#define MACB_RX_BUFFER_SIZE 4096
-#define MACB_RX_RING_SIZE (MACB_RX_BUFFER_SIZE / 128)
+/*
+ * These buffer sizes must be power of 2 and divisible
+ * by RX_BUFFER_MULTIPLE
+ */
+#define MACB_RX_BUFFER_SIZE 128
+#define GEM_RX_BUFFER_SIZE 2048
+#define RX_BUFFER_MULTIPLE 64
+
+#define MACB_RX_RING_SIZE 32
#define MACB_TX_RING_SIZE 16
+
#define MACB_TX_TIMEOUT 1000
#define MACB_AUTONEG_TIMEOUT 5000000
@@ -77,31 +85,16 @@
#define MACB_RX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_RX_RING_SIZE))
#define MACB_TX_DUMMY_DMA_DESC_SIZE (DMA_DESC_BYTES(1))
-#define RXADDR_USED 0x00000001
-#define RXADDR_WRAP 0x00000002
-
#define RXBUF_FRMLEN_MASK 0x00000fff
-#define RXBUF_FRAME_START 0x00004000
-#define RXBUF_FRAME_END 0x00008000
-#define RXBUF_TYPEID_MATCH 0x00400000
-#define RXBUF_ADDR4_MATCH 0x00800000
-#define RXBUF_ADDR3_MATCH 0x01000000
-#define RXBUF_ADDR2_MATCH 0x02000000
-#define RXBUF_ADDR1_MATCH 0x04000000
-#define RXBUF_BROADCAST 0x80000000
-
#define TXBUF_FRMLEN_MASK 0x000007ff
-#define TXBUF_FRAME_END 0x00008000
-#define TXBUF_NOCRC 0x00010000
-#define TXBUF_EXHAUSTED 0x08000000
-#define TXBUF_UNDERRUN 0x10000000
-#define TXBUF_MAXRETRY 0x20000000
-#define TXBUF_WRAP 0x40000000
-#define TXBUF_USED 0x80000000
struct macb_device {
void *regs;
+ bool is_big_endian;
+
+ const struct macb_config *config;
+
unsigned int rx_tail;
unsigned int tx_head;
unsigned int tx_tail;
@@ -112,6 +105,7 @@
void *tx_buffer;
struct macb_dma_desc *rx_ring;
struct macb_dma_desc *tx_ring;
+ size_t rx_buffer_size;
unsigned long rx_buffer_dma;
unsigned long rx_ring_dma;
@@ -137,6 +131,13 @@
phy_interface_t phy_interface;
#endif
};
+
+struct macb_config {
+ unsigned int dma_burst_length;
+
+ int (*clk_init)(struct udevice *dev, ulong rate);
+};
+
#ifndef CONFIG_DM_ETH
#define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
#endif
@@ -316,9 +317,9 @@
paddr = dma_map_single(packet, length, DMA_TO_DEVICE);
ctrl = length & TXBUF_FRMLEN_MASK;
- ctrl |= TXBUF_FRAME_END;
+ ctrl |= MACB_BIT(TX_LAST);
if (tx_head == (MACB_TX_RING_SIZE - 1)) {
- ctrl |= TXBUF_WRAP;
+ ctrl |= MACB_BIT(TX_WRAP);
macb->tx_head = 0;
} else {
macb->tx_head++;
@@ -340,7 +341,7 @@
barrier();
macb_invalidate_ring_desc(macb, TX);
ctrl = macb->tx_ring[tx_head].ctrl;
- if (ctrl & TXBUF_USED)
+ if (ctrl & MACB_BIT(TX_USED))
break;
udelay(1);
}
@@ -348,9 +349,9 @@
dma_unmap_single(packet, length, paddr);
if (i <= MACB_TX_TIMEOUT) {
- if (ctrl & TXBUF_UNDERRUN)
+ if (ctrl & MACB_BIT(TX_UNDERRUN))
printf("%s: TX underrun\n", name);
- if (ctrl & TXBUF_EXHAUSTED)
+ if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED))
printf("%s: TX buffers exhausted in mid frame\n", name);
} else {
printf("%s: TX timeout\n", name);
@@ -369,14 +370,14 @@
macb_invalidate_ring_desc(macb, RX);
while (i > new_tail) {
- macb->rx_ring[i].addr &= ~RXADDR_USED;
+ macb->rx_ring[i].addr &= ~MACB_BIT(RX_USED);
i++;
if (i > MACB_RX_RING_SIZE)
i = 0;
}
while (i < new_tail) {
- macb->rx_ring[i].addr &= ~RXADDR_USED;
+ macb->rx_ring[i].addr &= ~MACB_BIT(RX_USED);
i++;
}
@@ -396,26 +397,27 @@
for (;;) {
macb_invalidate_ring_desc(macb, RX);
- if (!(macb->rx_ring[next_rx_tail].addr & RXADDR_USED))
+ if (!(macb->rx_ring[next_rx_tail].addr & MACB_BIT(RX_USED)))
return -EAGAIN;
status = macb->rx_ring[next_rx_tail].ctrl;
- if (status & RXBUF_FRAME_START) {
+ if (status & MACB_BIT(RX_SOF)) {
if (next_rx_tail != macb->rx_tail)
reclaim_rx_buffers(macb, next_rx_tail);
macb->wrapped = false;
}
- if (status & RXBUF_FRAME_END) {
- buffer = macb->rx_buffer + 128 * macb->rx_tail;
+ if (status & MACB_BIT(RX_EOF)) {
+ buffer = macb->rx_buffer +
+ macb->rx_buffer_size * macb->rx_tail;
length = status & RXBUF_FRMLEN_MASK;
macb_invalidate_rx_buffer(macb);
if (macb->wrapped) {
unsigned int headlen, taillen;
- headlen = 128 * (MACB_RX_RING_SIZE
- - macb->rx_tail);
+ headlen = macb->rx_buffer_size *
+ (MACB_RX_RING_SIZE - macb->rx_tail);
taillen = length - headlen;
memcpy((void *)net_rx_packets[0],
buffer, headlen);
@@ -495,21 +497,38 @@
* when operation failed.
*/
#ifdef CONFIG_DM_ETH
+static int macb_sifive_clk_init(struct udevice *dev, ulong rate)
+{
+ fdt_addr_t addr;
+ void *gemgxl_regs;
+
+ addr = dev_read_addr_index(dev, 1);
+ if (addr == FDT_ADDR_T_NONE)
+ return -ENODEV;
+
+ gemgxl_regs = (void __iomem *)addr;
+ if (!gemgxl_regs)
+ return -ENODEV;
+
+ /*
+ * SiFive GEMGXL TX clock operation mode:
+ *
+ * 0 = GMII mode. Use 125 MHz gemgxlclk from PRCI in TX logic
+ * and output clock on GMII output signal GTX_CLK
+ * 1 = MII mode. Use MII input signal TX_CLK in TX logic
+ */
+ writel(rate != 125000000, gemgxl_regs);
+ return 0;
+}
+
int __weak macb_linkspd_cb(struct udevice *dev, unsigned int speed)
{
#ifdef CONFIG_CLK
+ struct macb_device *macb = dev_get_priv(dev);
struct clk tx_clk;
ulong rate;
int ret;
- /*
- * "tx_clk" is an optional clock source for MACB.
- * Ignore if it does not exist in DT.
- */
- ret = clk_get_by_name(dev, "tx_clk", &tx_clk);
- if (ret)
- return 0;
-
switch (speed) {
case _10BASET:
rate = 2500000; /* 2.5 MHz */
@@ -525,6 +544,17 @@
return 0;
}
+ if (macb->config->clk_init)
+ return macb->config->clk_init(dev, rate);
+
+ /*
+ * "tx_clk" is an optional clock source for MACB.
+ * Ignore if it does not exist in DT.
+ */
+ ret = clk_get_by_name(dev, "tx_clk", &tx_clk);
+ if (ret)
+ return 0;
+
if (tx_clk.dev) {
ret = clk_set_rate(&tx_clk, rate);
if (ret)
@@ -699,7 +729,7 @@
if (queue_mask & (1 << i))
num_queues++;
- macb->dummy_desc->ctrl = TXBUF_USED;
+ macb->dummy_desc->ctrl = MACB_BIT(TX_USED);
macb->dummy_desc->addr = 0;
flush_dcache_range(macb->dummy_desc_dma, macb->dummy_desc_dma +
ALIGN(MACB_TX_DUMMY_DMA_DESC_SIZE, PKTALIGN));
@@ -710,6 +740,31 @@
return 0;
}
+static void gmac_configure_dma(struct macb_device *macb)
+{
+ u32 buffer_size;
+ u32 dmacfg;
+
+ buffer_size = macb->rx_buffer_size / RX_BUFFER_MULTIPLE;
+ dmacfg = gem_readl(macb, DMACFG) & ~GEM_BF(RXBS, -1L);
+ dmacfg |= GEM_BF(RXBS, buffer_size);
+
+ if (macb->config->dma_burst_length)
+ dmacfg = GEM_BFINS(FBLDO,
+ macb->config->dma_burst_length, dmacfg);
+
+ dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
+ dmacfg &= ~GEM_BIT(ENDIA_PKT);
+
+ if (macb->is_big_endian)
+ dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */
+ else
+ dmacfg &= ~GEM_BIT(ENDIA_DESC);
+
+ dmacfg &= ~GEM_BIT(ADDR64);
+ gem_writel(macb, DMACFG, dmacfg);
+}
+
#ifdef CONFIG_DM_ETH
static int _macb_init(struct udevice *dev, const char *name)
#else
@@ -732,10 +787,10 @@
paddr = macb->rx_buffer_dma;
for (i = 0; i < MACB_RX_RING_SIZE; i++) {
if (i == (MACB_RX_RING_SIZE - 1))
- paddr |= RXADDR_WRAP;
+ paddr |= MACB_BIT(RX_WRAP);
macb->rx_ring[i].addr = paddr;
macb->rx_ring[i].ctrl = 0;
- paddr += 128;
+ paddr += macb->rx_buffer_size;
}
macb_flush_ring_desc(macb, RX);
macb_flush_rx_buffer(macb);
@@ -743,9 +798,10 @@
for (i = 0; i < MACB_TX_RING_SIZE; i++) {
macb->tx_ring[i].addr = 0;
if (i == (MACB_TX_RING_SIZE - 1))
- macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP;
+ macb->tx_ring[i].ctrl = MACB_BIT(TX_USED) |
+ MACB_BIT(TX_WRAP);
else
- macb->tx_ring[i].ctrl = TXBUF_USED;
+ macb->tx_ring[i].ctrl = MACB_BIT(TX_USED);
}
macb_flush_ring_desc(macb, TX);
@@ -762,6 +818,8 @@
macb_writel(macb, TBQP, macb->tx_ring_dma);
if (macb_is_gem(macb)) {
+ /* Initialize DMA properties */
+ gmac_configure_dma(macb);
/* Check the multi queue and initialize the queue for tx */
gmac_init_multi_queues(macb);
@@ -774,14 +832,21 @@
#ifdef CONFIG_DM_ETH
if ((macb->phy_interface == PHY_INTERFACE_MODE_RMII) ||
(macb->phy_interface == PHY_INTERFACE_MODE_RGMII))
- gem_writel(macb, UR, GEM_BIT(RGMII));
+ gem_writel(macb, USRIO, GEM_BIT(RGMII));
else
- gem_writel(macb, UR, 0);
+ gem_writel(macb, USRIO, 0);
+
+ if (macb->phy_interface == PHY_INTERFACE_MODE_SGMII) {
+ unsigned int ncfgr = macb_readl(macb, NCFGR);
+
+ ncfgr |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
+ macb_writel(macb, NCFGR, ncfgr);
+ }
#else
#if defined(CONFIG_RGMII) || defined(CONFIG_RMII)
- gem_writel(macb, UR, GEM_BIT(RGMII));
+ gem_writel(macb, USRIO, GEM_BIT(RGMII));
#else
- gem_writel(macb, UR, 0);
+ gem_writel(macb, USRIO, 0);
#endif
#endif
} else {
@@ -903,8 +968,12 @@
config = GEM_BF(CLK, GEM_CLK_DIV48);
else if (macb_hz < 160000000)
config = GEM_BF(CLK, GEM_CLK_DIV64);
- else
+ else if (macb_hz < 240000000)
config = GEM_BF(CLK, GEM_CLK_DIV96);
+ else if (macb_hz < 320000000)
+ config = GEM_BF(CLK, GEM_CLK_DIV128);
+ else
+ config = GEM_BF(CLK, GEM_CLK_DIV224);
return config;
}
@@ -932,8 +1001,14 @@
int id = 0; /* This is not used by functions we call */
u32 ncfgr;
+ if (macb_is_gem(macb))
+ macb->rx_buffer_size = GEM_RX_BUFFER_SIZE;
+ else
+ macb->rx_buffer_size = MACB_RX_BUFFER_SIZE;
+
/* TODO: we need check the rx/tx_ring_dma is dcache line aligned */
- macb->rx_buffer = dma_alloc_coherent(MACB_RX_BUFFER_SIZE,
+ macb->rx_buffer = dma_alloc_coherent(macb->rx_buffer_size *
+ MACB_RX_RING_SIZE,
&macb->rx_buffer_dma);
macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE,
&macb->rx_ring_dma);
@@ -1142,12 +1217,17 @@
}
#endif
+static const struct macb_config default_gem_config = {
+ .dma_burst_length = 16,
+ .clk_init = NULL,
+};
+
static int macb_eth_probe(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct macb_device *macb = dev_get_priv(dev);
const char *phy_mode;
- __maybe_unused int ret;
+ int ret;
phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
NULL);
@@ -1160,6 +1240,12 @@
macb->regs = (void *)pdata->iobase;
+ macb->is_big_endian = (cpu_to_be32(0x12345678) == 0x12345678);
+
+ macb->config = (struct macb_config *)dev_get_driver_data(dev);
+ if (!macb->config)
+ macb->config = &default_gem_config;
+
#ifdef CONFIG_CLK
ret = macb_enable_clk(dev);
if (ret)
@@ -1220,13 +1306,25 @@
return macb_late_eth_ofdata_to_platdata(dev);
}
+static const struct macb_config sama5d4_config = {
+ .dma_burst_length = 4,
+ .clk_init = NULL,
+};
+
+static const struct macb_config sifive_config = {
+ .dma_burst_length = 16,
+ .clk_init = macb_sifive_clk_init,
+};
+
static const struct udevice_id macb_eth_ids[] = {
{ .compatible = "cdns,macb" },
{ .compatible = "cdns,at91sam9260-macb" },
{ .compatible = "atmel,sama5d2-gem" },
{ .compatible = "atmel,sama5d3-gem" },
- { .compatible = "atmel,sama5d4-gem" },
+ { .compatible = "atmel,sama5d4-gem", .data = (ulong)&sama5d4_config },
{ .compatible = "cdns,zynq-gem" },
+ { .compatible = "sifive,fu540-c000-gem",
+ .data = (ulong)&sifive_config },
{ }
};
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 3cc27f8..9b16383 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -5,221 +5,410 @@
#ifndef __DRIVERS_MACB_H__
#define __DRIVERS_MACB_H__
+#define MACB_GREGS_NBR 16
+#define MACB_GREGS_VERSION 2
+#define MACB_MAX_QUEUES 8
+
/* MACB register offsets */
-#define MACB_NCR 0x0000
-#define MACB_NCFGR 0x0004
-#define MACB_NSR 0x0008
-#define GEM_UR 0x000c
-#define MACB_DMACFG 0x0010
-#define MACB_TSR 0x0014
-#define MACB_RBQP 0x0018
-#define MACB_TBQP 0x001c
-#define MACB_RSR 0x0020
-#define MACB_ISR 0x0024
-#define MACB_IER 0x0028
-#define MACB_IDR 0x002c
-#define MACB_IMR 0x0030
-#define MACB_MAN 0x0034
-#define MACB_PTR 0x0038
-#define MACB_PFR 0x003c
-#define MACB_FTO 0x0040
-#define MACB_SCF 0x0044
-#define MACB_MCF 0x0048
-#define MACB_FRO 0x004c
-#define MACB_FCSE 0x0050
-#define MACB_ALE 0x0054
-#define MACB_DTF 0x0058
-#define MACB_LCOL 0x005c
-#define MACB_EXCOL 0x0060
-#define MACB_TUND 0x0064
-#define MACB_CSE 0x0068
-#define MACB_RRE 0x006c
-#define MACB_ROVR 0x0070
-#define MACB_RSE 0x0074
-#define MACB_ELE 0x0078
-#define MACB_RJA 0x007c
-#define MACB_USF 0x0080
-#define MACB_STE 0x0084
-#define MACB_RLE 0x0088
-#define MACB_TPF 0x008c
-#define MACB_HRB 0x0090
-#define MACB_HRT 0x0094
-#define MACB_SA1B 0x0098
-#define MACB_SA1T 0x009c
-#define MACB_SA2B 0x00a0
-#define MACB_SA2T 0x00a4
-#define MACB_SA3B 0x00a8
-#define MACB_SA3T 0x00ac
-#define MACB_SA4B 0x00b0
-#define MACB_SA4T 0x00b4
-#define MACB_TID 0x00b8
-#define MACB_TPQ 0x00bc
-#define MACB_USRIO 0x00c0
-#define MACB_WOL 0x00c4
-#define MACB_MID 0x00fc
+#define MACB_NCR 0x0000 /* Network Control */
+#define MACB_NCFGR 0x0004 /* Network Config */
+#define MACB_NSR 0x0008 /* Network Status */
+#define MACB_TAR 0x000c /* AT91RM9200 only */
+#define MACB_TCR 0x0010 /* AT91RM9200 only */
+#define MACB_TSR 0x0014 /* Transmit Status */
+#define MACB_RBQP 0x0018 /* RX Q Base Address */
+#define MACB_TBQP 0x001c /* TX Q Base Address */
+#define MACB_RSR 0x0020 /* Receive Status */
+#define MACB_ISR 0x0024 /* Interrupt Status */
+#define MACB_IER 0x0028 /* Interrupt Enable */
+#define MACB_IDR 0x002c /* Interrupt Disable */
+#define MACB_IMR 0x0030 /* Interrupt Mask */
+#define MACB_MAN 0x0034 /* PHY Maintenance */
+#define MACB_PTR 0x0038
+#define MACB_PFR 0x003c
+#define MACB_FTO 0x0040
+#define MACB_SCF 0x0044
+#define MACB_MCF 0x0048
+#define MACB_FRO 0x004c
+#define MACB_FCSE 0x0050
+#define MACB_ALE 0x0054
+#define MACB_DTF 0x0058
+#define MACB_LCOL 0x005c
+#define MACB_EXCOL 0x0060
+#define MACB_TUND 0x0064
+#define MACB_CSE 0x0068
+#define MACB_RRE 0x006c
+#define MACB_ROVR 0x0070
+#define MACB_RSE 0x0074
+#define MACB_ELE 0x0078
+#define MACB_RJA 0x007c
+#define MACB_USF 0x0080
+#define MACB_STE 0x0084
+#define MACB_RLE 0x0088
+#define MACB_TPF 0x008c
+#define MACB_HRB 0x0090
+#define MACB_HRT 0x0094
+#define MACB_SA1B 0x0098
+#define MACB_SA1T 0x009c
+#define MACB_SA2B 0x00a0
+#define MACB_SA2T 0x00a4
+#define MACB_SA3B 0x00a8
+#define MACB_SA3T 0x00ac
+#define MACB_SA4B 0x00b0
+#define MACB_SA4T 0x00b4
+#define MACB_TID 0x00b8
+#define MACB_TPQ 0x00bc
+#define MACB_USRIO 0x00c0
+#define MACB_WOL 0x00c4
+#define MACB_MID 0x00fc
+#define MACB_TBQPH 0x04C8
+#define MACB_RBQPH 0x04D4
+
+/* GEM register offsets. */
+#define GEM_NCFGR 0x0004 /* Network Config */
+#define GEM_USRIO 0x000c /* User IO */
+#define GEM_DMACFG 0x0010 /* DMA Configuration */
+#define GEM_JML 0x0048 /* Jumbo Max Length */
+#define GEM_HRB 0x0080 /* Hash Bottom */
+#define GEM_HRT 0x0084 /* Hash Top */
+#define GEM_SA1B 0x0088 /* Specific1 Bottom */
+#define GEM_SA1T 0x008C /* Specific1 Top */
+#define GEM_SA2B 0x0090 /* Specific2 Bottom */
+#define GEM_SA2T 0x0094 /* Specific2 Top */
+#define GEM_SA3B 0x0098 /* Specific3 Bottom */
+#define GEM_SA3T 0x009C /* Specific3 Top */
+#define GEM_SA4B 0x00A0 /* Specific4 Bottom */
+#define GEM_SA4T 0x00A4 /* Specific4 Top */
+#define GEM_EFTSH 0x00e8 /* PTP Event Frame Transmitted Seconds Register 47:32 */
+#define GEM_EFRSH 0x00ec /* PTP Event Frame Received Seconds Register 47:32 */
+#define GEM_PEFTSH 0x00f0 /* PTP Peer Event Frame Transmitted Seconds Register 47:32 */
+#define GEM_PEFRSH 0x00f4 /* PTP Peer Event Frame Received Seconds Register 47:32 */
+#define GEM_OTX 0x0100 /* Octets transmitted */
+#define GEM_OCTTXL 0x0100 /* Octets transmitted [31:0] */
+#define GEM_OCTTXH 0x0104 /* Octets transmitted [47:32] */
+#define GEM_TXCNT 0x0108 /* Frames Transmitted counter */
+#define GEM_TXBCCNT 0x010c /* Broadcast Frames counter */
+#define GEM_TXMCCNT 0x0110 /* Multicast Frames counter */
+#define GEM_TXPAUSECNT 0x0114 /* Pause Frames Transmitted Counter */
+#define GEM_TX64CNT 0x0118 /* 64 byte Frames TX counter */
+#define GEM_TX65CNT 0x011c /* 65-127 byte Frames TX counter */
+#define GEM_TX128CNT 0x0120 /* 128-255 byte Frames TX counter */
+#define GEM_TX256CNT 0x0124 /* 256-511 byte Frames TX counter */
+#define GEM_TX512CNT 0x0128 /* 512-1023 byte Frames TX counter */
+#define GEM_TX1024CNT 0x012c /* 1024-1518 byte Frames TX counter */
+#define GEM_TX1519CNT 0x0130 /* 1519+ byte Frames TX counter */
+#define GEM_TXURUNCNT 0x0134 /* TX under run error counter */
+#define GEM_SNGLCOLLCNT 0x0138 /* Single Collision Frame Counter */
+#define GEM_MULTICOLLCNT 0x013c /* Multiple Collision Frame Counter */
+#define GEM_EXCESSCOLLCNT 0x0140 /* Excessive Collision Frame Counter */
+#define GEM_LATECOLLCNT 0x0144 /* Late Collision Frame Counter */
+#define GEM_TXDEFERCNT 0x0148 /* Deferred Transmission Frame Counter */
+#define GEM_TXCSENSECNT 0x014c /* Carrier Sense Error Counter */
+#define GEM_ORX 0x0150 /* Octets received */
+#define GEM_OCTRXL 0x0150 /* Octets received [31:0] */
+#define GEM_OCTRXH 0x0154 /* Octets received [47:32] */
+#define GEM_RXCNT 0x0158 /* Frames Received Counter */
+#define GEM_RXBROADCNT 0x015c /* Broadcast Frames Received Counter */
+#define GEM_RXMULTICNT 0x0160 /* Multicast Frames Received Counter */
+#define GEM_RXPAUSECNT 0x0164 /* Pause Frames Received Counter */
+#define GEM_RX64CNT 0x0168 /* 64 byte Frames RX Counter */
+#define GEM_RX65CNT 0x016c /* 65-127 byte Frames RX Counter */
+#define GEM_RX128CNT 0x0170 /* 128-255 byte Frames RX Counter */
+#define GEM_RX256CNT 0x0174 /* 256-511 byte Frames RX Counter */
+#define GEM_RX512CNT 0x0178 /* 512-1023 byte Frames RX Counter */
+#define GEM_RX1024CNT 0x017c /* 1024-1518 byte Frames RX Counter */
+#define GEM_RX1519CNT 0x0180 /* 1519+ byte Frames RX Counter */
+#define GEM_RXUNDRCNT 0x0184 /* Undersize Frames Received Counter */
+#define GEM_RXOVRCNT 0x0188 /* Oversize Frames Received Counter */
+#define GEM_RXJABCNT 0x018c /* Jabbers Received Counter */
+#define GEM_RXFCSCNT 0x0190 /* Frame Check Sequence Error Counter */
+#define GEM_RXLENGTHCNT 0x0194 /* Length Field Error Counter */
+#define GEM_RXSYMBCNT 0x0198 /* Symbol Error Counter */
+#define GEM_RXALIGNCNT 0x019c /* Alignment Error Counter */
+#define GEM_RXRESERRCNT 0x01a0 /* Receive Resource Error Counter */
+#define GEM_RXORCNT 0x01a4 /* Receive Overrun Counter */
+#define GEM_RXIPCCNT 0x01a8 /* IP header Checksum Error Counter */
+#define GEM_RXTCPCCNT 0x01ac /* TCP Checksum Error Counter */
+#define GEM_RXUDPCCNT 0x01b0 /* UDP Checksum Error Counter */
+#define GEM_TISUBN 0x01bc /* 1588 Timer Increment Sub-ns */
+#define GEM_TSH 0x01c0 /* 1588 Timer Seconds High */
+#define GEM_TSL 0x01d0 /* 1588 Timer Seconds Low */
+#define GEM_TN 0x01d4 /* 1588 Timer Nanoseconds */
+#define GEM_TA 0x01d8 /* 1588 Timer Adjust */
+#define GEM_TI 0x01dc /* 1588 Timer Increment */
+#define GEM_EFTSL 0x01e0 /* PTP Event Frame Tx Seconds Low */
+#define GEM_EFTN 0x01e4 /* PTP Event Frame Tx Nanoseconds */
+#define GEM_EFRSL 0x01e8 /* PTP Event Frame Rx Seconds Low */
+#define GEM_EFRN 0x01ec /* PTP Event Frame Rx Nanoseconds */
+#define GEM_PEFTSL 0x01f0 /* PTP Peer Event Frame Tx Secs Low */
+#define GEM_PEFTN 0x01f4 /* PTP Peer Event Frame Tx Ns */
+#define GEM_PEFRSL 0x01f8 /* PTP Peer Event Frame Rx Sec Low */
+#define GEM_PEFRN 0x01fc /* PTP Peer Event Frame Rx Ns */
+#define GEM_DCFG1 0x0280 /* Design Config 1 */
+#define GEM_DCFG2 0x0284 /* Design Config 2 */
+#define GEM_DCFG3 0x0288 /* Design Config 3 */
+#define GEM_DCFG4 0x028c /* Design Config 4 */
+#define GEM_DCFG5 0x0290 /* Design Config 5 */
+#define GEM_DCFG6 0x0294 /* Design Config 6 */
+#define GEM_DCFG7 0x0298 /* Design Config 7 */
+#define GEM_DCFG8 0x029C /* Design Config 8 */
+#define GEM_DCFG10 0x02A4 /* Design Config 10 */
-/* GEM specific register offsets */
-#define GEM_DCFG1 0x0280
-#define GEM_DCFG6 0x0294
+#define GEM_TXBDCTRL 0x04cc /* TX Buffer Descriptor control register */
+#define GEM_RXBDCTRL 0x04d0 /* RX Buffer Descriptor control register */
-#define MACB_MAX_QUEUES 8
+/* Screener Type 2 match registers */
+#define GEM_SCRT2 0x540
-/* GEM specific multi queues register offset */
-/* hw_q can be 0~7 */
-#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2))
+/* EtherType registers */
+#define GEM_ETHT 0x06E0
+
+/* Type 2 compare registers */
+#define GEM_T2CMPW0 0x0700
+#define GEM_T2CMPW1 0x0704
+#define T2CMP_OFST(t2idx) (t2idx * 2)
+
+/* type 2 compare registers
+ * each location requires 3 compare regs
+ */
+#define GEM_IP4SRC_CMP(idx) (idx * 3)
+#define GEM_IP4DST_CMP(idx) (idx * 3 + 1)
+#define GEM_PORT_CMP(idx) (idx * 3 + 2)
+
+/* Which screening type 2 EtherType register will be used (0 - 7) */
+#define SCRT2_ETHT 0
+
+#define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2))
+#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2))
+#define GEM_TBQPH(hw_q) (0x04C8)
+#define GEM_RBQP(hw_q) (0x0480 + ((hw_q) << 2))
+#define GEM_RBQS(hw_q) (0x04A0 + ((hw_q) << 2))
+#define GEM_RBQPH(hw_q) (0x04D4)
+#define GEM_IER(hw_q) (0x0600 + ((hw_q) << 2))
+#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2))
+#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2))
/* Bitfields in NCR */
-#define MACB_LB_OFFSET 0
-#define MACB_LB_SIZE 1
-#define MACB_LLB_OFFSET 1
-#define MACB_LLB_SIZE 1
-#define MACB_RE_OFFSET 2
-#define MACB_RE_SIZE 1
-#define MACB_TE_OFFSET 3
-#define MACB_TE_SIZE 1
-#define MACB_MPE_OFFSET 4
-#define MACB_MPE_SIZE 1
-#define MACB_CLRSTAT_OFFSET 5
-#define MACB_CLRSTAT_SIZE 1
-#define MACB_INCSTAT_OFFSET 6
-#define MACB_INCSTAT_SIZE 1
-#define MACB_WESTAT_OFFSET 7
-#define MACB_WESTAT_SIZE 1
-#define MACB_BP_OFFSET 8
-#define MACB_BP_SIZE 1
-#define MACB_TSTART_OFFSET 9
-#define MACB_TSTART_SIZE 1
-#define MACB_THALT_OFFSET 10
-#define MACB_THALT_SIZE 1
-#define MACB_NCR_TPF_OFFSET 11
-#define MACB_NCR_TPF_SIZE 1
-#define MACB_TZQ_OFFSET 12
-#define MACB_TZQ_SIZE 1
+#define MACB_LB_OFFSET 0 /* reserved */
+#define MACB_LB_SIZE 1
+#define MACB_LLB_OFFSET 1 /* Loop back local */
+#define MACB_LLB_SIZE 1
+#define MACB_RE_OFFSET 2 /* Receive enable */
+#define MACB_RE_SIZE 1
+#define MACB_TE_OFFSET 3 /* Transmit enable */
+#define MACB_TE_SIZE 1
+#define MACB_MPE_OFFSET 4 /* Management port enable */
+#define MACB_MPE_SIZE 1
+#define MACB_CLRSTAT_OFFSET 5 /* Clear stats regs */
+#define MACB_CLRSTAT_SIZE 1
+#define MACB_INCSTAT_OFFSET 6 /* Incremental stats regs */
+#define MACB_INCSTAT_SIZE 1
+#define MACB_WESTAT_OFFSET 7 /* Write enable stats regs */
+#define MACB_WESTAT_SIZE 1
+#define MACB_BP_OFFSET 8 /* Back pressure */
+#define MACB_BP_SIZE 1
+#define MACB_TSTART_OFFSET 9 /* Start transmission */
+#define MACB_TSTART_SIZE 1
+#define MACB_THALT_OFFSET 10 /* Transmit halt */
+#define MACB_THALT_SIZE 1
+#define MACB_NCR_TPF_OFFSET 11 /* Transmit pause frame */
+#define MACB_NCR_TPF_SIZE 1
+#define MACB_TZQ_OFFSET 12 /* Transmit zero quantum pause frame */
+#define MACB_TZQ_SIZE 1
+#define MACB_SRTSM_OFFSET 15
+#define MACB_OSSMODE_OFFSET 24 /* Enable One Step Synchro Mode */
+#define MACB_OSSMODE_SIZE 1
/* Bitfields in NCFGR */
-#define MACB_SPD_OFFSET 0
-#define MACB_SPD_SIZE 1
-#define MACB_FD_OFFSET 1
-#define MACB_FD_SIZE 1
-#define MACB_BIT_RATE_OFFSET 2
-#define MACB_BIT_RATE_SIZE 1
-#define MACB_JFRAME_OFFSET 3
-#define MACB_JFRAME_SIZE 1
-#define MACB_CAF_OFFSET 4
-#define MACB_CAF_SIZE 1
-#define MACB_NBC_OFFSET 5
-#define MACB_NBC_SIZE 1
-#define MACB_NCFGR_MTI_OFFSET 6
-#define MACB_NCFGR_MTI_SIZE 1
-#define MACB_UNI_OFFSET 7
-#define MACB_UNI_SIZE 1
-#define MACB_BIG_OFFSET 8
-#define MACB_BIG_SIZE 1
-#define MACB_EAE_OFFSET 9
-#define MACB_EAE_SIZE 1
-#define MACB_CLK_OFFSET 10
-#define MACB_CLK_SIZE 2
-#define MACB_RTY_OFFSET 12
-#define MACB_RTY_SIZE 1
-#define MACB_PAE_OFFSET 13
-#define MACB_PAE_SIZE 1
-#define MACB_RBOF_OFFSET 14
-#define MACB_RBOF_SIZE 2
-#define MACB_RLCE_OFFSET 16
-#define MACB_RLCE_SIZE 1
-#define MACB_DRFCS_OFFSET 17
-#define MACB_DRFCS_SIZE 1
-#define MACB_EFRHD_OFFSET 18
-#define MACB_EFRHD_SIZE 1
-#define MACB_IRXFCS_OFFSET 19
-#define MACB_IRXFCS_SIZE 1
+#define MACB_SPD_OFFSET 0 /* Speed */
+#define MACB_SPD_SIZE 1
+#define MACB_FD_OFFSET 1 /* Full duplex */
+#define MACB_FD_SIZE 1
+#define MACB_BIT_RATE_OFFSET 2 /* Discard non-VLAN frames */
+#define MACB_BIT_RATE_SIZE 1
+#define MACB_JFRAME_OFFSET 3 /* reserved */
+#define MACB_JFRAME_SIZE 1
+#define MACB_CAF_OFFSET 4 /* Copy all frames */
+#define MACB_CAF_SIZE 1
+#define MACB_NBC_OFFSET 5 /* No broadcast */
+#define MACB_NBC_SIZE 1
+#define MACB_NCFGR_MTI_OFFSET 6 /* Multicast hash enable */
+#define MACB_NCFGR_MTI_SIZE 1
+#define MACB_UNI_OFFSET 7 /* Unicast hash enable */
+#define MACB_UNI_SIZE 1
+#define MACB_BIG_OFFSET 8 /* Receive 1536 byte frames */
+#define MACB_BIG_SIZE 1
+#define MACB_EAE_OFFSET 9 /* External address match enable */
+#define MACB_EAE_SIZE 1
+#define MACB_CLK_OFFSET 10
+#define MACB_CLK_SIZE 2
+#define MACB_RTY_OFFSET 12 /* Retry test */
+#define MACB_RTY_SIZE 1
+#define MACB_PAE_OFFSET 13 /* Pause enable */
+#define MACB_PAE_SIZE 1
+#define MACB_RM9200_RMII_OFFSET 13 /* AT91RM9200 only */
+#define MACB_RM9200_RMII_SIZE 1 /* AT91RM9200 only */
+#define MACB_RBOF_OFFSET 14 /* Receive buffer offset */
+#define MACB_RBOF_SIZE 2
+#define MACB_RLCE_OFFSET 16 /* Length field error frame discard */
+#define MACB_RLCE_SIZE 1
+#define MACB_DRFCS_OFFSET 17 /* FCS remove */
+#define MACB_DRFCS_SIZE 1
+#define MACB_EFRHD_OFFSET 18
+#define MACB_EFRHD_SIZE 1
+#define MACB_IRXFCS_OFFSET 19
+#define MACB_IRXFCS_SIZE 1
-#define GEM_GBE_OFFSET 10
-#define GEM_GBE_SIZE 1
-#define GEM_CLK_OFFSET 18
-#define GEM_CLK_SIZE 3
-#define GEM_DBW_OFFSET 21
-#define GEM_DBW_SIZE 2
+/* GEM specific NCFGR bitfields. */
+#define GEM_GBE_OFFSET 10 /* Gigabit mode enable */
+#define GEM_GBE_SIZE 1
+#define GEM_PCSSEL_OFFSET 11
+#define GEM_PCSSEL_SIZE 1
+#define GEM_CLK_OFFSET 18 /* MDC clock division */
+#define GEM_CLK_SIZE 3
+#define GEM_DBW_OFFSET 21 /* Data bus width */
+#define GEM_DBW_SIZE 2
+#define GEM_RXCOEN_OFFSET 24
+#define GEM_RXCOEN_SIZE 1
+#define GEM_SGMIIEN_OFFSET 27
+#define GEM_SGMIIEN_SIZE 1
-/* Bitfields in NSR */
-#define MACB_NSR_LINK_OFFSET 0
-#define MACB_NSR_LINK_SIZE 1
-#define MACB_MDIO_OFFSET 1
-#define MACB_MDIO_SIZE 1
-#define MACB_IDLE_OFFSET 2
-#define MACB_IDLE_SIZE 1
-/* Bitfields in UR */
-#define GEM_RGMII_OFFSET 0
-#define GEM_RGMII_SIZE 1
+/* Constants for data bus width. */
+#define GEM_DBW32 0 /* 32 bit AMBA AHB data bus width */
+#define GEM_DBW64 1 /* 64 bit AMBA AHB data bus width */
+#define GEM_DBW128 2 /* 128 bit AMBA AHB data bus width */
+
+/* Bitfields in DMACFG. */
+#define GEM_FBLDO_OFFSET 0 /* fixed burst length for DMA */
+#define GEM_FBLDO_SIZE 5
+#define GEM_ENDIA_DESC_OFFSET 6 /* endian swap mode for management descriptor access */
+#define GEM_ENDIA_DESC_SIZE 1
+#define GEM_ENDIA_PKT_OFFSET 7 /* endian swap mode for packet data access */
+#define GEM_ENDIA_PKT_SIZE 1
+#define GEM_RXBMS_OFFSET 8 /* RX packet buffer memory size select */
+#define GEM_RXBMS_SIZE 2
+#define GEM_TXPBMS_OFFSET 10 /* TX packet buffer memory size select */
+#define GEM_TXPBMS_SIZE 1
+#define GEM_TXCOEN_OFFSET 11 /* TX IP/TCP/UDP checksum gen offload */
+#define GEM_TXCOEN_SIZE 1
+#define GEM_RXBS_OFFSET 16 /* DMA receive buffer size */
+#define GEM_RXBS_SIZE 8
+#define GEM_DDRP_OFFSET 24 /* disc_when_no_ahb */
+#define GEM_DDRP_SIZE 1
+#define GEM_RXEXT_OFFSET 28 /* RX extended Buffer Descriptor mode */
+#define GEM_RXEXT_SIZE 1
+#define GEM_TXEXT_OFFSET 29 /* TX extended Buffer Descriptor mode */
+#define GEM_TXEXT_SIZE 1
+#define GEM_ADDR64_OFFSET 30 /* Address bus width - 64b or 32b */
+#define GEM_ADDR64_SIZE 1
+
+
+/* Bitfields in NSR */
+#define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */
+#define MACB_NSR_LINK_SIZE 1
+#define MACB_MDIO_OFFSET 1 /* status of the mdio_in pin */
+#define MACB_MDIO_SIZE 1
+#define MACB_IDLE_OFFSET 2 /* The PHY management logic is idle */
+#define MACB_IDLE_SIZE 1
/* Bitfields in TSR */
-#define MACB_UBR_OFFSET 0
-#define MACB_UBR_SIZE 1
-#define MACB_COL_OFFSET 1
-#define MACB_COL_SIZE 1
-#define MACB_TSR_RLE_OFFSET 2
-#define MACB_TSR_RLE_SIZE 1
-#define MACB_TGO_OFFSET 3
-#define MACB_TGO_SIZE 1
-#define MACB_BEX_OFFSET 4
-#define MACB_BEX_SIZE 1
-#define MACB_COMP_OFFSET 5
-#define MACB_COMP_SIZE 1
-#define MACB_UND_OFFSET 6
-#define MACB_UND_SIZE 1
+#define MACB_UBR_OFFSET 0 /* Used bit read */
+#define MACB_UBR_SIZE 1
+#define MACB_COL_OFFSET 1 /* Collision occurred */
+#define MACB_COL_SIZE 1
+#define MACB_TSR_RLE_OFFSET 2 /* Retry limit exceeded */
+#define MACB_TSR_RLE_SIZE 1
+#define MACB_TGO_OFFSET 3 /* Transmit go */
+#define MACB_TGO_SIZE 1
+#define MACB_BEX_OFFSET 4 /* TX frame corruption due to AHB error */
+#define MACB_BEX_SIZE 1
+#define MACB_RM9200_BNQ_OFFSET 4 /* AT91RM9200 only */
+#define MACB_RM9200_BNQ_SIZE 1 /* AT91RM9200 only */
+#define MACB_COMP_OFFSET 5 /* Trnasmit complete */
+#define MACB_COMP_SIZE 1
+#define MACB_UND_OFFSET 6 /* Trnasmit under run */
+#define MACB_UND_SIZE 1
/* Bitfields in RSR */
-#define MACB_BNA_OFFSET 0
-#define MACB_BNA_SIZE 1
-#define MACB_REC_OFFSET 1
-#define MACB_REC_SIZE 1
-#define MACB_OVR_OFFSET 2
-#define MACB_OVR_SIZE 1
+#define MACB_BNA_OFFSET 0 /* Buffer not available */
+#define MACB_BNA_SIZE 1
+#define MACB_REC_OFFSET 1 /* Frame received */
+#define MACB_REC_SIZE 1
+#define MACB_OVR_OFFSET 2 /* Receive overrun */
+#define MACB_OVR_SIZE 1
/* Bitfields in ISR/IER/IDR/IMR */
-#define MACB_MFD_OFFSET 0
-#define MACB_MFD_SIZE 1
-#define MACB_RCOMP_OFFSET 1
-#define MACB_RCOMP_SIZE 1
-#define MACB_RXUBR_OFFSET 2
-#define MACB_RXUBR_SIZE 1
-#define MACB_TXUBR_OFFSET 3
-#define MACB_TXUBR_SIZE 1
-#define MACB_ISR_TUND_OFFSET 4
-#define MACB_ISR_TUND_SIZE 1
-#define MACB_ISR_RLE_OFFSET 5
-#define MACB_ISR_RLE_SIZE 1
-#define MACB_TXERR_OFFSET 6
-#define MACB_TXERR_SIZE 1
-#define MACB_TCOMP_OFFSET 7
-#define MACB_TCOMP_SIZE 1
-#define MACB_ISR_LINK_OFFSET 9
-#define MACB_ISR_LINK_SIZE 1
-#define MACB_ISR_ROVR_OFFSET 10
-#define MACB_ISR_ROVR_SIZE 1
-#define MACB_HRESP_OFFSET 11
-#define MACB_HRESP_SIZE 1
-#define MACB_PFR_OFFSET 12
-#define MACB_PFR_SIZE 1
-#define MACB_PTZ_OFFSET 13
-#define MACB_PTZ_SIZE 1
+#define MACB_MFD_OFFSET 0 /* Management frame sent */
+#define MACB_MFD_SIZE 1
+#define MACB_RCOMP_OFFSET 1 /* Receive complete */
+#define MACB_RCOMP_SIZE 1
+#define MACB_RXUBR_OFFSET 2 /* RX used bit read */
+#define MACB_RXUBR_SIZE 1
+#define MACB_TXUBR_OFFSET 3 /* TX used bit read */
+#define MACB_TXUBR_SIZE 1
+#define MACB_ISR_TUND_OFFSET 4 /* Enable TX buffer under run interrupt */
+#define MACB_ISR_TUND_SIZE 1
+#define MACB_ISR_RLE_OFFSET 5 /* EN retry exceeded/late coll interrupt */
+#define MACB_ISR_RLE_SIZE 1
+#define MACB_TXERR_OFFSET 6 /* EN TX frame corrupt from error interrupt */
+#define MACB_TXERR_SIZE 1
+#define MACB_TCOMP_OFFSET 7 /* Enable transmit complete interrupt */
+#define MACB_TCOMP_SIZE 1
+#define MACB_ISR_LINK_OFFSET 9 /* Enable link change interrupt */
+#define MACB_ISR_LINK_SIZE 1
+#define MACB_ISR_ROVR_OFFSET 10 /* Enable receive overrun interrupt */
+#define MACB_ISR_ROVR_SIZE 1
+#define MACB_HRESP_OFFSET 11 /* Enable hrsep not OK interrupt */
+#define MACB_HRESP_SIZE 1
+#define MACB_PFR_OFFSET 12 /* Enable pause frame w/ quantum interrupt */
+#define MACB_PFR_SIZE 1
+#define MACB_PTZ_OFFSET 13 /* Enable pause time zero interrupt */
+#define MACB_PTZ_SIZE 1
+#define MACB_WOL_OFFSET 14 /* Enable wake-on-lan interrupt */
+#define MACB_WOL_SIZE 1
+#define MACB_DRQFR_OFFSET 18 /* PTP Delay Request Frame Received */
+#define MACB_DRQFR_SIZE 1
+#define MACB_SFR_OFFSET 19 /* PTP Sync Frame Received */
+#define MACB_SFR_SIZE 1
+#define MACB_DRQFT_OFFSET 20 /* PTP Delay Request Frame Transmitted */
+#define MACB_DRQFT_SIZE 1
+#define MACB_SFT_OFFSET 21 /* PTP Sync Frame Transmitted */
+#define MACB_SFT_SIZE 1
+#define MACB_PDRQFR_OFFSET 22 /* PDelay Request Frame Received */
+#define MACB_PDRQFR_SIZE 1
+#define MACB_PDRSFR_OFFSET 23 /* PDelay Response Frame Received */
+#define MACB_PDRSFR_SIZE 1
+#define MACB_PDRQFT_OFFSET 24 /* PDelay Request Frame Transmitted */
+#define MACB_PDRQFT_SIZE 1
+#define MACB_PDRSFT_OFFSET 25 /* PDelay Response Frame Transmitted */
+#define MACB_PDRSFT_SIZE 1
+#define MACB_SRI_OFFSET 26 /* TSU Seconds Register Increment */
+#define MACB_SRI_SIZE 1
+
+/* Timer increment fields */
+#define MACB_TI_CNS_OFFSET 0
+#define MACB_TI_CNS_SIZE 8
+#define MACB_TI_ACNS_OFFSET 8
+#define MACB_TI_ACNS_SIZE 8
+#define MACB_TI_NIT_OFFSET 16
+#define MACB_TI_NIT_SIZE 8
/* Bitfields in MAN */
-#define MACB_DATA_OFFSET 0
-#define MACB_DATA_SIZE 16
-#define MACB_CODE_OFFSET 16
-#define MACB_CODE_SIZE 2
-#define MACB_REGA_OFFSET 18
-#define MACB_REGA_SIZE 5
-#define MACB_PHYA_OFFSET 23
-#define MACB_PHYA_SIZE 5
-#define MACB_RW_OFFSET 28
-#define MACB_RW_SIZE 2
-#define MACB_SOF_OFFSET 30
-#define MACB_SOF_SIZE 2
+#define MACB_DATA_OFFSET 0 /* data */
+#define MACB_DATA_SIZE 16
+#define MACB_CODE_OFFSET 16 /* Must be written to 10 */
+#define MACB_CODE_SIZE 2
+#define MACB_REGA_OFFSET 18 /* Register address */
+#define MACB_REGA_SIZE 5
+#define MACB_PHYA_OFFSET 23 /* PHY address */
+#define MACB_PHYA_SIZE 5
+#define MACB_RW_OFFSET 28 /* Operation. 10 is read. 01 is write. */
+#define MACB_RW_SIZE 2
+#define MACB_SOF_OFFSET 30 /* Must be written to 1 for Clause 22 */
+#define MACB_SOF_SIZE 2
-/* Bitfields in USRIO */
+/* Bitfields in USRIO (AVR32) */
#define MACB_MII_OFFSET 0
#define MACB_MII_SIZE 1
#define MACB_EAM_OFFSET 1
@@ -232,6 +421,8 @@
/* Bitfields in USRIO (AT91) */
#define MACB_RMII_OFFSET 0
#define MACB_RMII_SIZE 1
+#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */
+#define GEM_RGMII_SIZE 1
#define MACB_CLKEN_OFFSET 1
#define MACB_CLKEN_SIZE 1
@@ -249,17 +440,166 @@
/* Bitfields in MID */
#define MACB_IDNUM_OFFSET 16
-#define MACB_IDNUM_SIZE 16
+#define MACB_IDNUM_SIZE 12
+#define MACB_REV_OFFSET 0
+#define MACB_REV_SIZE 16
-/* Bitfields in DCFG1 */
+/* Bitfields in DCFG1. */
+#define GEM_IRQCOR_OFFSET 23
+#define GEM_IRQCOR_SIZE 1
#define GEM_DBWDEF_OFFSET 25
#define GEM_DBWDEF_SIZE 3
+/* Bitfields in DCFG2. */
+#define GEM_RX_PKT_BUFF_OFFSET 20
+#define GEM_RX_PKT_BUFF_SIZE 1
+#define GEM_TX_PKT_BUFF_OFFSET 21
+#define GEM_TX_PKT_BUFF_SIZE 1
+
+
+/* Bitfields in DCFG5. */
+#define GEM_TSU_OFFSET 8
+#define GEM_TSU_SIZE 1
+
+/* Bitfields in DCFG6. */
+#define GEM_PBUF_LSO_OFFSET 27
+#define GEM_PBUF_LSO_SIZE 1
+#define GEM_DAW64_OFFSET 23
+#define GEM_DAW64_SIZE 1
+
+/* Bitfields in DCFG8. */
+#define GEM_T1SCR_OFFSET 24
+#define GEM_T1SCR_SIZE 8
+#define GEM_T2SCR_OFFSET 16
+#define GEM_T2SCR_SIZE 8
+#define GEM_SCR2ETH_OFFSET 8
+#define GEM_SCR2ETH_SIZE 8
+#define GEM_SCR2CMP_OFFSET 0
+#define GEM_SCR2CMP_SIZE 8
+
-/* constants for data bus width */
-#define GEM_DBW32 0
-#define GEM_DBW64 1
-#define GEM_DBW128 2
+/* Bitfields in DCFG10 */
+#define GEM_TXBD_RDBUFF_OFFSET 12
+#define GEM_TXBD_RDBUFF_SIZE 4
+#define GEM_RXBD_RDBUFF_OFFSET 8
+#define GEM_RXBD_RDBUFF_SIZE 4
+/* Bitfields in TISUBN */
+#define GEM_SUBNSINCR_OFFSET 0
+#define GEM_SUBNSINCR_SIZE 16
+
+/* Bitfields in TI */
+#define GEM_NSINCR_OFFSET 0
+#define GEM_NSINCR_SIZE 8
+
+/* Bitfields in TSH */
+#define GEM_TSH_OFFSET 0 /* TSU timer value (s). MSB [47:32] of seconds timer count */
+#define GEM_TSH_SIZE 16
+
+/* Bitfields in TSL */
+#define GEM_TSL_OFFSET 0 /* TSU timer value (s). LSB [31:0] of seconds timer count */
+#define GEM_TSL_SIZE 32
+
+/* Bitfields in TN */
+#define GEM_TN_OFFSET 0 /* TSU timer value (ns) */
+#define GEM_TN_SIZE 30
+
+/* Bitfields in TXBDCTRL */
+#define GEM_TXTSMODE_OFFSET 4 /* TX Descriptor Timestamp Insertion mode */
+#define GEM_TXTSMODE_SIZE 2
+
+/* Bitfields in RXBDCTRL */
+#define GEM_RXTSMODE_OFFSET 4 /* RX Descriptor Timestamp Insertion mode */
+#define GEM_RXTSMODE_SIZE 2
+
+/* Bitfields in SCRT2 */
+#define GEM_QUEUE_OFFSET 0 /* Queue Number */
+#define GEM_QUEUE_SIZE 4
+#define GEM_VLANPR_OFFSET 4 /* VLAN Priority */
+#define GEM_VLANPR_SIZE 3
+#define GEM_VLANEN_OFFSET 8 /* VLAN Enable */
+#define GEM_VLANEN_SIZE 1
+#define GEM_ETHT2IDX_OFFSET 9 /* Index to screener type 2 EtherType register */
+#define GEM_ETHT2IDX_SIZE 3
+#define GEM_ETHTEN_OFFSET 12 /* EtherType Enable */
+#define GEM_ETHTEN_SIZE 1
+#define GEM_CMPA_OFFSET 13 /* Compare A - Index to screener type 2 Compare register */
+#define GEM_CMPA_SIZE 5
+#define GEM_CMPAEN_OFFSET 18 /* Compare A Enable */
+#define GEM_CMPAEN_SIZE 1
+#define GEM_CMPB_OFFSET 19 /* Compare B - Index to screener type 2 Compare register */
+#define GEM_CMPB_SIZE 5
+#define GEM_CMPBEN_OFFSET 24 /* Compare B Enable */
+#define GEM_CMPBEN_SIZE 1
+#define GEM_CMPC_OFFSET 25 /* Compare C - Index to screener type 2 Compare register */
+#define GEM_CMPC_SIZE 5
+#define GEM_CMPCEN_OFFSET 30 /* Compare C Enable */
+#define GEM_CMPCEN_SIZE 1
+
+/* Bitfields in ETHT */
+#define GEM_ETHTCMP_OFFSET 0 /* EtherType compare value */
+#define GEM_ETHTCMP_SIZE 16
+
+/* Bitfields in T2CMPW0 */
+#define GEM_T2CMP_OFFSET 16 /* 0xFFFF0000 compare value */
+#define GEM_T2CMP_SIZE 16
+#define GEM_T2MASK_OFFSET 0 /* 0x0000FFFF compare value or mask */
+#define GEM_T2MASK_SIZE 16
+
+/* Bitfields in T2CMPW1 */
+#define GEM_T2DISMSK_OFFSET 9 /* disable mask */
+#define GEM_T2DISMSK_SIZE 1
+#define GEM_T2CMPOFST_OFFSET 7 /* compare offset */
+#define GEM_T2CMPOFST_SIZE 2
+#define GEM_T2OFST_OFFSET 0 /* offset value */
+#define GEM_T2OFST_SIZE 7
+
+/* Offset for screener type 2 compare values (T2CMPOFST).
+ * Note the offset is applied after the specified point,
+ * e.g. GEM_T2COMPOFST_ETYPE denotes the EtherType field, so an offset
+ * of 12 bytes from this would be the source IP address in an IP header
+ */
+#define GEM_T2COMPOFST_SOF 0
+#define GEM_T2COMPOFST_ETYPE 1
+#define GEM_T2COMPOFST_IPHDR 2
+#define GEM_T2COMPOFST_TCPUDP 3
+
+/* offset from EtherType to IP address */
+#define ETYPE_SRCIP_OFFSET 12
+#define ETYPE_DSTIP_OFFSET 16
+
+/* offset from IP header to port */
+#define IPHDR_SRCPORT_OFFSET 0
+#define IPHDR_DSTPORT_OFFSET 2
+
+/* Transmit DMA buffer descriptor Word 1 */
+#define GEM_DMA_TXVALID_OFFSET 23 /* timestamp has been captured in the Buffer Descriptor */
+#define GEM_DMA_TXVALID_SIZE 1
+
+/* Receive DMA buffer descriptor Word 0 */
+#define GEM_DMA_RXVALID_OFFSET 2 /* indicates a valid timestamp in the Buffer Descriptor */
+#define GEM_DMA_RXVALID_SIZE 1
+
+/* DMA buffer descriptor Word 2 (32 bit addressing) or Word 4 (64 bit addressing) */
+#define GEM_DMA_SECL_OFFSET 30 /* Timestamp seconds[1:0] */
+#define GEM_DMA_SECL_SIZE 2
+#define GEM_DMA_NSEC_OFFSET 0 /* Timestamp nanosecs [29:0] */
+#define GEM_DMA_NSEC_SIZE 30
+
+/* DMA buffer descriptor Word 3 (32 bit addressing) or Word 5 (64 bit addressing) */
+
+/* New hardware supports 12 bit precision of timestamp in DMA buffer descriptor.
+ * Old hardware supports only 6 bit precision but it is enough for PTP.
+ * Less accuracy is used always instead of checking hardware version.
+ */
+#define GEM_DMA_SECH_OFFSET 0 /* Timestamp seconds[5:2] */
+#define GEM_DMA_SECH_SIZE 4
+#define GEM_DMA_SEC_WIDTH (GEM_DMA_SECH_SIZE + GEM_DMA_SECL_SIZE)
+#define GEM_DMA_SEC_TOP (1 << GEM_DMA_SEC_WIDTH)
+#define GEM_DMA_SEC_MASK (GEM_DMA_SEC_TOP - 1)
+
+/* Bitfields in ADJ */
+#define GEM_ADDSUB_OFFSET 31
+#define GEM_ADDSUB_SIZE 1
/* Constants for CLK */
#define MACB_CLK_DIV8 0
#define MACB_CLK_DIV16 1
@@ -273,6 +613,8 @@
#define GEM_CLK_DIV48 3
#define GEM_CLK_DIV64 4
#define GEM_CLK_DIV96 5
+#define GEM_CLK_DIV128 6
+#define GEM_CLK_DIV224 7
/* Constants for MAN register */
#define MACB_MAN_SOF 1
@@ -280,19 +622,38 @@
#define MACB_MAN_READ 2
#define MACB_MAN_CODE 2
+/* Capability mask bits */
+#define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x00000001
+#define MACB_CAPS_USRIO_HAS_CLKEN 0x00000002
+#define MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII 0x00000004
+#define MACB_CAPS_NO_GIGABIT_HALF 0x00000008
+#define MACB_CAPS_USRIO_DISABLED 0x00000010
+#define MACB_CAPS_JUMBO 0x00000020
+#define MACB_CAPS_GEM_HAS_PTP 0x00000040
+#define MACB_CAPS_BD_RD_PREFETCH 0x00000080
+#define MACB_CAPS_NEEDS_RSTONUBR 0x00000100
+#define MACB_CAPS_FIFO_MODE 0x10000000
+#define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000
+#define MACB_CAPS_SG_DISABLED 0x40000000
+#define MACB_CAPS_MACB_IS_GEM 0x80000000
+
+/* LSO settings */
+#define MACB_LSO_UFO_ENABLE 0x01
+#define MACB_LSO_TSO_ENABLE 0x02
+
/* Bit manipulation macros */
#define MACB_BIT(name) \
(1 << MACB_##name##_OFFSET)
-#define MACB_BF(name, value) \
+#define MACB_BF(name,value) \
(((value) & ((1 << MACB_##name##_SIZE) - 1)) \
<< MACB_##name##_OFFSET)
-#define MACB_BFEXT(name, value)\
+#define MACB_BFEXT(name,value)\
(((value) >> MACB_##name##_OFFSET) \
& ((1 << MACB_##name##_SIZE) - 1))
-#define MACB_BFINS(name, value, old) \
+#define MACB_BFINS(name,value,old) \
(((old) & ~(((1 << MACB_##name##_SIZE) - 1) \
<< MACB_##name##_OFFSET)) \
- | MACB_BF(name, value))
+ | MACB_BF(name,value))
#define GEM_BIT(name) \
(1 << GEM_##name##_OFFSET)
@@ -316,6 +677,95 @@
readl((port)->regs + GEM_##reg)
#define gem_writel(port, reg, value) \
writel((value), (port)->regs + GEM_##reg)
+
+/* DMA descriptor bitfields */
+#define MACB_RX_USED_OFFSET 0
+#define MACB_RX_USED_SIZE 1
+#define MACB_RX_WRAP_OFFSET 1
+#define MACB_RX_WRAP_SIZE 1
+#define MACB_RX_WADDR_OFFSET 2
+#define MACB_RX_WADDR_SIZE 30
+
+#define MACB_RX_FRMLEN_OFFSET 0
+#define MACB_RX_FRMLEN_SIZE 12
+#define MACB_RX_OFFSET_OFFSET 12
+#define MACB_RX_OFFSET_SIZE 2
+#define MACB_RX_SOF_OFFSET 14
+#define MACB_RX_SOF_SIZE 1
+#define MACB_RX_EOF_OFFSET 15
+#define MACB_RX_EOF_SIZE 1
+#define MACB_RX_CFI_OFFSET 16
+#define MACB_RX_CFI_SIZE 1
+#define MACB_RX_VLAN_PRI_OFFSET 17
+#define MACB_RX_VLAN_PRI_SIZE 3
+#define MACB_RX_PRI_TAG_OFFSET 20
+#define MACB_RX_PRI_TAG_SIZE 1
+#define MACB_RX_VLAN_TAG_OFFSET 21
+#define MACB_RX_VLAN_TAG_SIZE 1
+#define MACB_RX_TYPEID_MATCH_OFFSET 22
+#define MACB_RX_TYPEID_MATCH_SIZE 1
+#define MACB_RX_SA4_MATCH_OFFSET 23
+#define MACB_RX_SA4_MATCH_SIZE 1
+#define MACB_RX_SA3_MATCH_OFFSET 24
+#define MACB_RX_SA3_MATCH_SIZE 1
+#define MACB_RX_SA2_MATCH_OFFSET 25
+#define MACB_RX_SA2_MATCH_SIZE 1
+#define MACB_RX_SA1_MATCH_OFFSET 26
+#define MACB_RX_SA1_MATCH_SIZE 1
+#define MACB_RX_EXT_MATCH_OFFSET 28
+#define MACB_RX_EXT_MATCH_SIZE 1
+#define MACB_RX_UHASH_MATCH_OFFSET 29
+#define MACB_RX_UHASH_MATCH_SIZE 1
+#define MACB_RX_MHASH_MATCH_OFFSET 30
+#define MACB_RX_MHASH_MATCH_SIZE 1
+#define MACB_RX_BROADCAST_OFFSET 31
+#define MACB_RX_BROADCAST_SIZE 1
+
+#define MACB_RX_FRMLEN_MASK 0xFFF
+#define MACB_RX_JFRMLEN_MASK 0x3FFF
+
+/* RX checksum offload disabled: bit 24 clear in NCFGR */
+#define GEM_RX_TYPEID_MATCH_OFFSET 22
+#define GEM_RX_TYPEID_MATCH_SIZE 2
+
+/* RX checksum offload enabled: bit 24 set in NCFGR */
+#define GEM_RX_CSUM_OFFSET 22
+#define GEM_RX_CSUM_SIZE 2
+
+#define MACB_TX_FRMLEN_OFFSET 0
+#define MACB_TX_FRMLEN_SIZE 11
+#define MACB_TX_LAST_OFFSET 15
+#define MACB_TX_LAST_SIZE 1
+#define MACB_TX_NOCRC_OFFSET 16
+#define MACB_TX_NOCRC_SIZE 1
+#define MACB_MSS_MFS_OFFSET 16
+#define MACB_MSS_MFS_SIZE 14
+#define MACB_TX_LSO_OFFSET 17
+#define MACB_TX_LSO_SIZE 2
+#define MACB_TX_TCP_SEQ_SRC_OFFSET 19
+#define MACB_TX_TCP_SEQ_SRC_SIZE 1
+#define MACB_TX_BUF_EXHAUSTED_OFFSET 27
+#define MACB_TX_BUF_EXHAUSTED_SIZE 1
+#define MACB_TX_UNDERRUN_OFFSET 28
+#define MACB_TX_UNDERRUN_SIZE 1
+#define MACB_TX_ERROR_OFFSET 29
+#define MACB_TX_ERROR_SIZE 1
+#define MACB_TX_WRAP_OFFSET 30
+#define MACB_TX_WRAP_SIZE 1
+#define MACB_TX_USED_OFFSET 31
+#define MACB_TX_USED_SIZE 1
+
+#define GEM_TX_FRMLEN_OFFSET 0
+#define GEM_TX_FRMLEN_SIZE 14
+
+/* Buffer descriptor constants */
+#define GEM_RX_CSUM_NONE 0
+#define GEM_RX_CSUM_IP_ONLY 1
+#define GEM_RX_CSUM_IP_TCP 2
+#define GEM_RX_CSUM_IP_UDP 3
+
+/* limit RX checksum offload to TCP and UDP packets */
+#define GEM_RX_CSUM_CHECKED_MASK 2
#define gem_writel_queue_TBQP(port, value, queue_num) \
writel((value), (port)->regs + GEM_TBQP(queue_num))
diff --git a/drivers/net/mdio_mux_sandbox.c b/drivers/net/mdio_mux_sandbox.c
new file mode 100644
index 0000000..3dba4d1
--- /dev/null
+++ b/drivers/net/mdio_mux_sandbox.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019
+ * Alex Marginean, NXP
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <miiphy.h>
+
+/* macros copied over from mdio_sandbox.c */
+#define SANDBOX_PHY_ADDR 5
+#define SANDBOX_PHY_REG_CNT 2
+
+struct mdio_mux_sandbox_priv {
+ int enabled;
+ int sel;
+};
+
+static int mdio_mux_sandbox_mark_selection(struct udevice *dev, int sel)
+{
+ struct udevice *mdio;
+ struct mdio_ops *ops;
+ int err;
+
+ /*
+ * find the sandbox parent mdio and write a register on the PHY there
+ * so the mux test can verify selection.
+ */
+ err = uclass_get_device_by_name(UCLASS_MDIO, "mdio-test", &mdio);
+ if (err)
+ return err;
+ ops = mdio_get_ops(mdio);
+ return ops->write(mdio, SANDBOX_PHY_ADDR, MDIO_DEVAD_NONE,
+ SANDBOX_PHY_REG_CNT - 1, (u16)sel);
+}
+
+static int mdio_mux_sandbox_select(struct udevice *dev, int cur, int sel)
+{
+ struct mdio_mux_sandbox_priv *priv = dev_get_priv(dev);
+
+ if (!priv->enabled)
+ return -ENODEV;
+
+ if (cur != priv->sel)
+ return -EINVAL;
+
+ priv->sel = sel;
+ mdio_mux_sandbox_mark_selection(dev, priv->sel);
+
+ return 0;
+}
+
+static int mdio_mux_sandbox_deselect(struct udevice *dev, int sel)
+{
+ struct mdio_mux_sandbox_priv *priv = dev_get_priv(dev);
+
+ if (!priv->enabled)
+ return -ENODEV;
+
+ if (sel != priv->sel)
+ return -EINVAL;
+
+ priv->sel = -1;
+ mdio_mux_sandbox_mark_selection(dev, priv->sel);
+
+ return 0;
+}
+
+static const struct mdio_mux_ops mdio_mux_sandbox_ops = {
+ .select = mdio_mux_sandbox_select,
+ .deselect = mdio_mux_sandbox_deselect,
+};
+
+static int mdio_mux_sandbox_probe(struct udevice *dev)
+{
+ struct mdio_mux_sandbox_priv *priv = dev_get_priv(dev);
+
+ priv->enabled = 1;
+ priv->sel = -1;
+
+ return 0;
+}
+
+static const struct udevice_id mdio_mux_sandbox_ids[] = {
+ { .compatible = "sandbox,mdio-mux" },
+ { }
+};
+
+U_BOOT_DRIVER(mdio_mux_sandbox) = {
+ .name = "mdio_mux_sandbox",
+ .id = UCLASS_MDIO_MUX,
+ .of_match = mdio_mux_sandbox_ids,
+ .probe = mdio_mux_sandbox_probe,
+ .ops = &mdio_mux_sandbox_ops,
+ .priv_auto_alloc_size = sizeof(struct mdio_mux_sandbox_priv),
+};
diff --git a/drivers/net/mdio_sandbox.c b/drivers/net/mdio_sandbox.c
index 07515e0..df053f5 100644
--- a/drivers/net/mdio_sandbox.c
+++ b/drivers/net/mdio_sandbox.c
@@ -9,11 +9,11 @@
#include <miiphy.h>
#define SANDBOX_PHY_ADDR 5
-#define SANDBOX_PHY_REG 0
+#define SANDBOX_PHY_REG_CNT 2
struct mdio_sandbox_priv {
int enabled;
- u16 reg;
+ u16 reg[SANDBOX_PHY_REG_CNT];
};
static int mdio_sandbox_read(struct udevice *dev, int addr, int devad, int reg)
@@ -27,10 +27,10 @@
return -ENODEV;
if (devad != MDIO_DEVAD_NONE)
return -ENODEV;
- if (reg != SANDBOX_PHY_REG)
+ if (reg < 0 || reg > SANDBOX_PHY_REG_CNT)
return -ENODEV;
- return priv->reg;
+ return priv->reg[reg];
}
static int mdio_sandbox_write(struct udevice *dev, int addr, int devad, int reg,
@@ -45,10 +45,10 @@
return -ENODEV;
if (devad != MDIO_DEVAD_NONE)
return -ENODEV;
- if (reg != SANDBOX_PHY_REG)
+ if (reg < 0 || reg > SANDBOX_PHY_REG_CNT)
return -ENODEV;
- priv->reg = val;
+ priv->reg[reg] = val;
return 0;
}
@@ -56,8 +56,10 @@
static int mdio_sandbox_reset(struct udevice *dev)
{
struct mdio_sandbox_priv *priv = dev_get_priv(dev);
+ int i;
- priv->reg = 0;
+ for (i = 0; i < SANDBOX_PHY_REG_CNT; i++)
+ priv->reg[i] = 0;
return 0;
}
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index 5c3298d..465ec2d 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -461,6 +461,19 @@
.shutdown = &gen10g_shutdown,
};
+struct phy_driver aqr112_driver = {
+ .name = "Aquantia AQR112",
+ .uid = 0x3a1b660,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS |
+ MDIO_MMD_PHYXS | MDIO_MMD_AN |
+ MDIO_MMD_VEND1),
+ .config = &aquantia_config,
+ .startup = &aquantia_startup,
+ .shutdown = &gen10g_shutdown,
+};
+
struct phy_driver aqr405_driver = {
.name = "Aquantia AQR405",
.uid = 0x3a1b4b2,
@@ -474,6 +487,19 @@
.shutdown = &gen10g_shutdown,
};
+struct phy_driver aqr412_driver = {
+ .name = "Aquantia AQR412",
+ .uid = 0x3a1b710,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS |
+ MDIO_MMD_PHYXS | MDIO_MMD_AN |
+ MDIO_MMD_VEND1),
+ .config = &aquantia_config,
+ .startup = &aquantia_startup,
+ .shutdown = &gen10g_shutdown,
+};
+
int phy_aquantia_init(void)
{
phy_register(&aq1202_driver);
@@ -481,7 +507,9 @@
phy_register(&aqr105_driver);
phy_register(&aqr106_driver);
phy_register(&aqr107_driver);
+ phy_register(&aqr112_driver);
phy_register(&aqr405_driver);
+ phy_register(&aqr412_driver);
return 0;
}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index c1c1af9..ae37dd6 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -727,12 +727,23 @@
while (phy_mask) {
int addr = ffs(phy_mask) - 1;
int r = get_phy_id(bus, addr, devad, &phy_id);
+
+ /*
+ * If the PHY ID is flat 0 we ignore it. There are C45 PHYs
+ * that return all 0s for C22 reads (like Aquantia AQR112) and
+ * there are C22 PHYs that return all 0s for C45 reads (like
+ * Atheros AR8035).
+ */
+ if (r == 0 && phy_id == 0)
+ goto next;
+
/* If the PHY ID is mostly f's, we didn't find anything */
if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff) {
is_c45 = (devad == MDIO_DEVAD_NONE) ? false : true;
return phy_device_create(bus, addr, phy_id, is_c45,
interface);
}
+next:
phy_mask &= ~(1 << addr);
}
return NULL;
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index c0a4408..0629b16 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -846,31 +846,44 @@
static int sun8i_get_ephy_nodes(struct emac_eth_dev *priv)
{
- int node, ret;
+ int emac_node, ephy_node, ret, ephy_handle;
+
+ emac_node = fdt_path_offset(gd->fdt_blob,
+ "/soc/ethernet@1c30000");
+ if (emac_node < 0) {
+ debug("failed to get emac node\n");
+ return emac_node;
+ }
+ ephy_handle = fdtdec_lookup_phandle(gd->fdt_blob,
+ emac_node, "phy-handle");
/* look for mdio-mux node for internal PHY node */
- node = fdt_path_offset(gd->fdt_blob,
- "/soc/ethernet@1c30000/mdio-mux/mdio@1/ethernet-phy@1");
- if (node < 0) {
+ ephy_node = fdt_path_offset(gd->fdt_blob,
+ "/soc/ethernet@1c30000/mdio-mux/mdio@1/ethernet-phy@1");
+ if (ephy_node < 0) {
debug("failed to get mdio-mux with internal PHY\n");
- return node;
+ return ephy_node;
}
- ret = fdt_node_check_compatible(gd->fdt_blob, node,
+ /* This is not the phy we are looking for */
+ if (ephy_node != ephy_handle)
+ return 0;
+
+ ret = fdt_node_check_compatible(gd->fdt_blob, ephy_node,
"allwinner,sun8i-h3-mdio-internal");
if (ret < 0) {
debug("failed to find mdio-internal node\n");
return ret;
}
- ret = clk_get_by_index_nodev(offset_to_ofnode(node), 0,
+ ret = clk_get_by_index_nodev(offset_to_ofnode(ephy_node), 0,
&priv->ephy_clk);
if (ret) {
dev_err(dev, "failed to get EPHY TX clock\n");
return ret;
}
- ret = reset_get_by_index_nodev(offset_to_ofnode(node), 0,
+ ret = reset_get_by_index_nodev(offset_to_ofnode(ephy_node), 0,
&priv->ephy_rst);
if (ret) {
dev_err(dev, "failed to get EPHY TX reset\n");
diff --git a/drivers/net/ti/davinci_emac.c b/drivers/net/ti/davinci_emac.c
index 9d53984..2bd9c51 100644
--- a/drivers/net/ti/davinci_emac.c
+++ b/drivers/net/ti/davinci_emac.c
@@ -26,7 +26,6 @@
#include <net.h>
#include <miiphy.h>
#include <malloc.h>
-#include <netdev.h>
#include <linux/compiler.h>
#include <asm/arch/emac_defs.h>
#include <asm/io.h>
@@ -107,8 +106,9 @@
phy_t phy[CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT];
-static int davinci_eth_set_mac_addr(struct eth_device *dev)
+static int davinci_emac_write_hwaddr(struct udevice *dev)
{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
unsigned long mac_hi;
unsigned long mac_lo;
@@ -118,12 +118,12 @@
* Using channel 0 only - other channels are disabled
* */
writel(0, &adap_emac->MACINDEX);
- mac_hi = (dev->enetaddr[3] << 24) |
- (dev->enetaddr[2] << 16) |
- (dev->enetaddr[1] << 8) |
- (dev->enetaddr[0]);
- mac_lo = (dev->enetaddr[5] << 8) |
- (dev->enetaddr[4]);
+ mac_hi = (pdata->enetaddr[3] << 24) |
+ (pdata->enetaddr[2] << 16) |
+ (pdata->enetaddr[1] << 8) |
+ (pdata->enetaddr[0]);
+ mac_lo = (pdata->enetaddr[5] << 8) |
+ (pdata->enetaddr[4]);
writel(mac_hi, &adap_emac->MACADDRHI);
#if defined(DAVINCI_EMAC_VERSION2)
@@ -411,7 +411,7 @@
}
/* Eth device open */
-static int davinci_eth_open(struct eth_device *dev, bd_t *bis)
+static int davinci_emac_start(struct udevice *dev)
{
dv_reg_p addr;
u_int32_t clkdiv, cnt, mac_control;
@@ -447,7 +447,7 @@
writel(1, &adap_emac->TXCONTROL);
writel(1, &adap_emac->RXCONTROL);
- davinci_eth_set_mac_addr(dev);
+ davinci_emac_write_hwaddr(dev);
/* Set DMA 8 TX / 8 RX Head pointers to 0 */
addr = &adap_emac->TX0HDP;
@@ -588,7 +588,7 @@
}
/* Eth device close */
-static void davinci_eth_close(struct eth_device *dev)
+static void davinci_emac_stop(struct udevice *dev)
{
debug_emac("+ emac_close\n");
@@ -619,8 +619,8 @@
* This function sends a single packet on the network and returns
* positive number (number of bytes transmitted) or negative for error
*/
-static int davinci_eth_send_packet (struct eth_device *dev,
- void *packet, int length)
+static int davinci_emac_send(struct udevice *dev,
+ void *packet, int length)
{
int ret_status = -1;
int index;
@@ -672,7 +672,7 @@
/*
* This function handles receipt of a packet from the network
*/
-static int davinci_eth_rcv_packet (struct eth_device *dev)
+static int davinci_emac_recv(struct udevice *dev, int flags, uchar **packetp)
{
volatile emac_desc *rx_curr_desc;
volatile emac_desc *curr_desc;
@@ -682,6 +682,7 @@
rx_curr_desc = emac_rx_active_head;
if (!rx_curr_desc)
return 0;
+ *packetp = rx_curr_desc->buffer;
status = rx_curr_desc->pkt_flag_len;
if ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0) {
if (status & EMAC_CPPI_RX_ERROR_FRAME) {
@@ -693,7 +694,6 @@
rx_curr_desc->buff_off_len & 0xffff;
invalidate_dcache_range(tmp, tmp + ALIGN(len, PKTALIGN));
- net_process_received_packet(rx_curr_desc->buffer, len);
ret = len;
}
@@ -742,6 +742,7 @@
}
return (ret);
}
+
return (0);
}
@@ -750,30 +751,12 @@
* EMAC modules power or pin multiplexors, that is done by board_init()
* much earlier in bootup process. Returns 1 on success, 0 otherwise.
*/
-int davinci_emac_initialize(void)
+static int davinci_emac_probe(struct udevice *dev)
{
u_int32_t phy_id;
u_int16_t tmp;
int i;
int ret;
- struct eth_device *dev;
-
- dev = malloc(sizeof *dev);
-
- if (dev == NULL)
- return -1;
-
- memset(dev, 0, sizeof *dev);
- strcpy(dev->name, "DaVinci-EMAC");
-
- dev->iobase = 0;
- dev->init = davinci_eth_open;
- dev->halt = davinci_eth_close;
- dev->send = davinci_eth_send_packet;
- dev->recv = davinci_eth_rcv_packet;
- dev->write_hwaddr = davinci_eth_set_mac_addr;
-
- eth_register(dev);
davinci_eth_mdio_enable();
@@ -854,5 +837,29 @@
phy[i].auto_negotiate(i);
}
#endif
- return(1);
+ return 0;
}
+
+static const struct eth_ops davinci_emac_ops = {
+ .start = davinci_emac_start,
+ .send = davinci_emac_send,
+ .recv = davinci_emac_recv,
+ .stop = davinci_emac_stop,
+ .write_hwaddr = davinci_emac_write_hwaddr,
+};
+
+static const struct udevice_id davinci_emac_ids[] = {
+ { .compatible = "ti,davinci-dm6467-emac" },
+ { .compatible = "ti,am3517-emac", },
+ { .compatible = "ti,dm816-emac", },
+ { }
+};
+
+U_BOOT_DRIVER(davinci_emac) = {
+ .name = "davinci_emac",
+ .id = UCLASS_ETH,
+ .of_match = davinci_emac_ids,
+ .probe = davinci_emac_probe,
+ .ops = &davinci_emac_ops,
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 06a9b4f..f85cdcb 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -259,8 +259,8 @@
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
- u16 status;
int result = 0;
+ u16 status;
int i;
/* Find an empty buffer descriptor */
@@ -268,7 +268,7 @@
in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
i++) {
if (i >= TOUT_LOOP) {
- debug("%s: tsec: tx buffers full\n", dev->name);
+ printf("%s: tsec: tx buffers full\n", dev->name);
return result;
}
}
@@ -287,7 +287,7 @@
in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
i++) {
if (i >= TOUT_LOOP) {
- debug("%s: tsec: tx error\n", dev->name);
+ printf("%s: tsec: tx error\n", dev->name);
return result;
}
}
@@ -560,6 +560,8 @@
struct tsec_private *priv = (struct tsec_private *)dev->priv;
#ifdef CONFIG_DM_ETH
struct eth_pdata *pdata = dev_get_platdata(dev);
+#else
+ struct eth_device *pdata = dev;
#endif
struct tsec __iomem *regs = priv->regs;
u32 tempval;
@@ -580,21 +582,12 @@
* order (BE), MACnADDR1 is set to 0xCDAB7856 and
* MACnADDR2 is set to 0x34120000.
*/
-#ifndef CONFIG_DM_ETH
- tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) |
- (dev->enetaddr[3] << 8) | dev->enetaddr[2];
-#else
tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) |
(pdata->enetaddr[3] << 8) | pdata->enetaddr[2];
-#endif
out_be32(®s->macstnaddr1, tempval);
-#ifndef CONFIG_DM_ETH
- tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16);
-#else
tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16);
-#endif
out_be32(®s->macstnaddr2, tempval);
@@ -708,9 +701,9 @@
*/
static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
{
+ struct tsec_private *priv;
struct eth_device *dev;
int i;
- struct tsec_private *priv;
dev = (struct eth_device *)malloc(sizeof(*dev));
@@ -794,12 +787,14 @@
#else /* CONFIG_DM_ETH */
int tsec_probe(struct udevice *dev)
{
- struct tsec_private *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
- struct fsl_pq_mdio_info mdio_info;
+ struct tsec_private *priv = dev_get_priv(dev);
struct ofnode_phandle_args phandle_args;
- ofnode parent;
+ u32 tbiaddr = CONFIG_SYS_TBIPA_VALUE;
+ struct fsl_pq_mdio_info mdio_info;
const char *phy_mode;
+ fdt_addr_t reg;
+ ofnode parent;
int ret;
pdata->iobase = (phys_addr_t)dev_read_addr(dev);
@@ -807,7 +802,7 @@
if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
&phandle_args)) {
- debug("phy-handle does not exist under tsec %s\n", dev->name);
+ printf("phy-handle does not exist under tsec %s\n", dev->name);
return -ENOENT;
} else {
int reg = ofnode_read_u32_default(phandle_args.node, "reg", 0);
@@ -816,29 +811,27 @@
}
parent = ofnode_get_parent(phandle_args.node);
- if (ofnode_valid(parent)) {
- int reg = ofnode_get_addr_index(parent, 0);
-
- priv->phyregs_sgmii = (struct tsec_mii_mng *)reg;
- } else {
- debug("No parent node for PHY?\n");
+ if (!ofnode_valid(parent)) {
+ printf("No parent node for PHY?\n");
return -ENOENT;
}
- if (dev_read_phandle_with_args(dev, "tbi-handle", NULL, 0, 0,
- &phandle_args)) {
- priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
- } else {
- int reg = ofnode_read_u32_default(phandle_args.node, "reg",
- CONFIG_SYS_TBIPA_VALUE);
- priv->tbiaddr = reg;
- }
+ reg = ofnode_get_addr_index(parent, 0);
+ priv->phyregs_sgmii = (struct tsec_mii_mng *)
+ (reg + TSEC_MDIO_REGS_OFFSET);
+
+ ret = dev_read_phandle_with_args(dev, "tbi-handle", NULL, 0, 0,
+ &phandle_args);
+ if (ret == 0)
+ ofnode_read_u32(phandle_args.node, "reg", &tbiaddr);
+
+ priv->tbiaddr = tbiaddr;
phy_mode = dev_read_prop(dev, "phy-connection-type", NULL);
if (phy_mode)
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
if (pdata->phy_interface == -1) {
- debug("Invalid PHY interface '%s'\n", phy_mode);
+ printf("Invalid PHY interface '%s'\n", phy_mode);
return -EINVAL;
}
priv->interface = pdata->phy_interface;
@@ -887,7 +880,7 @@
};
static const struct udevice_id tsec_ids[] = {
- { .compatible = "fsl,tsec" },
+ { .compatible = "fsl,etsec2" },
{ }
};
diff --git a/drivers/pci_endpoint/sandbox-pci_ep.c b/drivers/pci_endpoint/sandbox-pci_ep.c
index 0258433..8e05d5b 100644
--- a/drivers/pci_endpoint/sandbox-pci_ep.c
+++ b/drivers/pci_endpoint/sandbox-pci_ep.c
@@ -83,14 +83,11 @@
struct pci_bar *ep_bar, enum pci_barno barno)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
- int bar_idx;
if (fn > 0)
return -ENODEV;
- bar_idx = ep_bar->barno;
-
- memcpy(ep_bar, &priv->bars[bar_idx], sizeof(*ep_bar));
+ memcpy(ep_bar, &priv->bars[barno], sizeof(*ep_bar));
return 0;
}
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 147e68d..337e9e7 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -92,9 +92,18 @@
or switching the mode is not supported by this driver (at
this time).
+config DM_REGULATOR_COMMON
+ bool
+ depends on DM_REGULATOR
+
+config SPL_DM_REGULATOR_COMMON
+ bool
+ depends on DM_REGULATOR
+
config DM_REGULATOR_FIXED
bool "Enable Driver Model for REGULATOR Fixed value"
depends on DM_REGULATOR
+ select DM_REGULATOR_COMMON
---help---
This config enables implementation of driver-model regulator uclass
features for fixed value regulators. The driver implements get/set api
@@ -103,6 +112,7 @@
config SPL_DM_REGULATOR_FIXED
bool "Enable Driver Model for REGULATOR Fixed value in SPL"
depends on DM_REGULATOR_FIXED
+ select SPL_DM_REGULATOR_COMMON
---help---
This config enables implementation of driver-model regulator uclass
features for fixed value regulators in SPL.
@@ -110,6 +120,7 @@
config DM_REGULATOR_GPIO
bool "Enable Driver Model for GPIO REGULATOR"
depends on DM_REGULATOR && DM_GPIO
+ select DM_REGULATOR_COMMON
---help---
This config enables implementation of driver-model regulator uclass
features for gpio regulators. The driver implements get/set for
@@ -118,6 +129,7 @@
config SPL_DM_REGULATOR_GPIO
bool "Enable Driver Model for GPIO REGULATOR in SPL"
depends on DM_REGULATOR_GPIO && SPL_GPIO_SUPPORT
+ select SPL_DM_REGULATOR_COMMON
---help---
This config enables implementation of driver-model regulator uclass
features for gpio regulators in SPL.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index 8c1506c..e728b73 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -11,6 +11,7 @@
obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
obj-$(CONFIG_$(SPL_)REGULATOR_PWM) += pwm_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_COMMON) += regulator_common.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_RK8XX) += rk8xx.o
diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c
index a99aa78..763e671 100644
--- a/drivers/power/regulator/fixed.c
+++ b/drivers/power/regulator/fixed.c
@@ -5,56 +5,26 @@
* Przemyslaw Marczak <p.marczak@samsung.com>
*/
+#include "regulator_common.h"
#include <common.h>
#include <errno.h>
#include <dm.h>
-#include <i2c.h>
-#include <asm/gpio.h>
#include <power/pmic.h>
#include <power/regulator.h>
-struct fixed_regulator_platdata {
- struct gpio_desc gpio; /* GPIO for regulator enable control */
- unsigned int startup_delay_us;
- unsigned int off_on_delay_us;
-};
-
static int fixed_regulator_ofdata_to_platdata(struct udevice *dev)
{
struct dm_regulator_uclass_platdata *uc_pdata;
- struct fixed_regulator_platdata *dev_pdata;
- struct gpio_desc *gpio;
- int flags = GPIOD_IS_OUT;
- int ret;
+ struct regulator_common_platdata *dev_pdata;
dev_pdata = dev_get_platdata(dev);
uc_pdata = dev_get_uclass_platdata(dev);
if (!uc_pdata)
return -ENXIO;
- /* Set type to fixed */
uc_pdata->type = REGULATOR_TYPE_FIXED;
- if (dev_read_bool(dev, "enable-active-high"))
- flags |= GPIOD_IS_OUT_ACTIVE;
-
- /* Get fixed regulator optional enable GPIO desc */
- gpio = &dev_pdata->gpio;
- ret = gpio_request_by_name(dev, "gpio", 0, gpio, flags);
- if (ret) {
- debug("Fixed regulator optional enable GPIO - not found! Error: %d\n",
- ret);
- if (ret != -ENOENT)
- return ret;
- }
-
- /* Get optional ramp up delay */
- dev_pdata->startup_delay_us = dev_read_u32_default(dev,
- "startup-delay-us", 0);
- dev_pdata->off_on_delay_us =
- dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0);
-
- return 0;
+ return regulator_common_ofdata_to_platdata(dev, dev_pdata, "gpio");
}
static int fixed_regulator_get_value(struct udevice *dev)
@@ -91,45 +61,12 @@
static int fixed_regulator_get_enable(struct udevice *dev)
{
- struct fixed_regulator_platdata *dev_pdata = dev_get_platdata(dev);
-
- /* Enable GPIO is optional */
- if (!dev_pdata->gpio.dev)
- return true;
-
- return dm_gpio_get_value(&dev_pdata->gpio);
+ return regulator_common_get_enable(dev, dev_get_platdata(dev));
}
static int fixed_regulator_set_enable(struct udevice *dev, bool enable)
{
- struct fixed_regulator_platdata *dev_pdata = dev_get_platdata(dev);
- int ret;
-
- debug("%s: dev='%s', enable=%d, delay=%d, has_gpio=%d\n", __func__,
- dev->name, enable, dev_pdata->startup_delay_us,
- dm_gpio_is_valid(&dev_pdata->gpio));
- /* Enable GPIO is optional */
- if (!dm_gpio_is_valid(&dev_pdata->gpio)) {
- if (!enable)
- return -ENOSYS;
- return 0;
- }
-
- ret = dm_gpio_set_value(&dev_pdata->gpio, enable);
- if (ret) {
- pr_err("Can't set regulator : %s gpio to: %d\n", dev->name,
- enable);
- return ret;
- }
-
- if (enable && dev_pdata->startup_delay_us)
- udelay(dev_pdata->startup_delay_us);
- debug("%s: done\n", __func__);
-
- if (!enable && dev_pdata->off_on_delay_us)
- udelay(dev_pdata->off_on_delay_us);
-
- return 0;
+ return regulator_common_set_enable(dev, dev_get_platdata(dev), enable);
}
static const struct dm_regulator_ops fixed_regulator_ops = {
@@ -150,5 +87,5 @@
.ops = &fixed_regulator_ops,
.of_match = fixed_regulator_ids,
.ofdata_to_platdata = fixed_regulator_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct fixed_regulator_platdata),
+ .platdata_auto_alloc_size = sizeof(struct regulator_common_platdata),
};
diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c
index d18e5d8..ec1dcb6 100644
--- a/drivers/power/regulator/gpio-regulator.c
+++ b/drivers/power/regulator/gpio-regulator.c
@@ -4,6 +4,7 @@
* Keerthy <j-keerthy@ti.com>
*/
+#include "regulator_common.h"
#include <common.h>
#include <fdtdec.h>
#include <errno.h>
@@ -18,6 +19,7 @@
DECLARE_GLOBAL_DATA_PTR;
struct gpio_regulator_platdata {
+ struct regulator_common_platdata common;
struct gpio_desc gpio; /* GPIO for regulator voltage control */
int states[GPIO_REGULATOR_MAX_STATES];
int voltages[GPIO_REGULATOR_MAX_STATES];
@@ -65,7 +67,7 @@
j++;
}
- return 0;
+ return regulator_common_ofdata_to_platdata(dev, &dev_pdata->common, "enable-gpios");
}
static int gpio_regulator_get_value(struct udevice *dev)
@@ -116,9 +118,23 @@
return 0;
}
+static int gpio_regulator_get_enable(struct udevice *dev)
+{
+ struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev);
+ return regulator_common_get_enable(dev, &dev_pdata->common);
+}
+
+static int gpio_regulator_set_enable(struct udevice *dev, bool enable)
+{
+ struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev);
+ return regulator_common_set_enable(dev, &dev_pdata->common, enable);
+}
+
static const struct dm_regulator_ops gpio_regulator_ops = {
.get_value = gpio_regulator_get_value,
.set_value = gpio_regulator_set_value,
+ .get_enable = gpio_regulator_get_enable,
+ .set_enable = gpio_regulator_set_enable,
};
static const struct udevice_id gpio_regulator_ids[] = {
diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c
new file mode 100644
index 0000000..3dabbe2
--- /dev/null
+++ b/drivers/power/regulator/regulator_common.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Disruptive Technologies Research AS
+ * Sven Schwermer <sven.svenschwermer@disruptive-technologies.com>
+ */
+
+#include "regulator_common.h"
+#include <common.h>
+#include <power/regulator.h>
+
+int regulator_common_ofdata_to_platdata(struct udevice *dev,
+ struct regulator_common_platdata *dev_pdata, const char *enable_gpio_name)
+{
+ struct gpio_desc *gpio;
+ int flags = GPIOD_IS_OUT;
+ int ret;
+
+ if (dev_read_bool(dev, "enable-active-high"))
+ flags |= GPIOD_IS_OUT_ACTIVE;
+
+ /* Get optional enable GPIO desc */
+ gpio = &dev_pdata->gpio;
+ ret = gpio_request_by_name(dev, enable_gpio_name, 0, gpio, flags);
+ if (ret) {
+ debug("Regulator '%s' optional enable GPIO - not found! Error: %d\n",
+ dev->name, ret);
+ if (ret != -ENOENT)
+ return ret;
+ }
+
+ /* Get optional ramp up delay */
+ dev_pdata->startup_delay_us = dev_read_u32_default(dev,
+ "startup-delay-us", 0);
+ dev_pdata->off_on_delay_us =
+ dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0);
+
+ return 0;
+}
+
+int regulator_common_get_enable(const struct udevice *dev,
+ struct regulator_common_platdata *dev_pdata)
+{
+ /* Enable GPIO is optional */
+ if (!dev_pdata->gpio.dev)
+ return true;
+
+ return dm_gpio_get_value(&dev_pdata->gpio);
+}
+
+int regulator_common_set_enable(const struct udevice *dev,
+ struct regulator_common_platdata *dev_pdata, bool enable)
+{
+ int ret;
+
+ debug("%s: dev='%s', enable=%d, delay=%d, has_gpio=%d\n", __func__,
+ dev->name, enable, dev_pdata->startup_delay_us,
+ dm_gpio_is_valid(&dev_pdata->gpio));
+ /* Enable GPIO is optional */
+ if (!dm_gpio_is_valid(&dev_pdata->gpio)) {
+ if (!enable)
+ return -ENOSYS;
+ return 0;
+ }
+
+ ret = dm_gpio_set_value(&dev_pdata->gpio, enable);
+ if (ret) {
+ pr_err("Can't set regulator : %s gpio to: %d\n", dev->name,
+ enable);
+ return ret;
+ }
+
+ if (enable && dev_pdata->startup_delay_us)
+ udelay(dev_pdata->startup_delay_us);
+ debug("%s: done\n", __func__);
+
+ if (!enable && dev_pdata->off_on_delay_us)
+ udelay(dev_pdata->off_on_delay_us);
+
+ return 0;
+}
diff --git a/drivers/power/regulator/regulator_common.h b/drivers/power/regulator/regulator_common.h
new file mode 100644
index 0000000..18a5258
--- /dev/null
+++ b/drivers/power/regulator/regulator_common.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Disruptive Technologies Research AS
+ * Sven Schwermer <sven.svenschwermer@disruptive-technologies.com>
+ */
+
+#ifndef _REGULATOR_COMMON_H
+#define _REGULATOR_COMMON_H
+
+#include <common.h>
+#include <asm/gpio.h>
+#include <dm.h>
+
+struct regulator_common_platdata {
+ struct gpio_desc gpio; /* GPIO for regulator enable control */
+ unsigned int startup_delay_us;
+ unsigned int off_on_delay_us;
+};
+
+int regulator_common_ofdata_to_platdata(struct udevice *dev,
+ struct regulator_common_platdata *dev_pdata, const char *enable_gpio_name);
+int regulator_common_get_enable(const struct udevice *dev,
+ struct regulator_common_platdata *dev_pdata);
+int regulator_common_set_enable(const struct udevice *dev,
+ struct regulator_common_platdata *dev_pdata, bool enable);
+
+#endif /* _REGULATOR_COMMON_H */
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
index fbf7d7b..568d8f2 100644
--- a/drivers/ram/Kconfig
+++ b/drivers/ram/Kconfig
@@ -54,4 +54,5 @@
config add support for the initialization of the external
SDRAM devices connected to DDR subsystem.
+source "drivers/ram/rockchip/Kconfig"
source "drivers/ram/stm32mp1/Kconfig"
diff --git a/drivers/ram/rockchip/Kconfig b/drivers/ram/rockchip/Kconfig
new file mode 100644
index 0000000..4f274e0
--- /dev/null
+++ b/drivers/ram/rockchip/Kconfig
@@ -0,0 +1,33 @@
+config RAM_ROCKCHIP
+ bool "Ram drivers support for Rockchip SoCs"
+ depends on RAM && ARCH_ROCKCHIP
+ default y
+ help
+ This enables support for ram drivers Rockchip SoCs.
+
+if RAM_ROCKCHIP
+
+config RAM_ROCKCHIP_DEBUG
+ bool "Rockchip ram drivers debugging"
+ help
+ This enables debugging ram driver API's for the platforms
+ based on Rockchip SoCs.
+
+ This is an option for developers to understand the ram drivers
+ initialization, configurations and etc.
+
+config RAM_RK3399
+ bool "Ram driver for Rockchip RK3399"
+ default ROCKCHIP_RK3399
+ help
+ This enables ram drivers support for the platforms based on
+ Rockchip RK3399 SoC.
+
+config RAM_RK3399_LPDDR4
+ bool "LPDDR4 support for Rockchip RK3399"
+ depends on RAM_RK3399
+ help
+ This enables LPDDR4 sdram code support for the platforms based
+ on Rockchip RK3399 SoC.
+
+endif # RAM_ROCKCHIP
diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile
index 5df1960..feb1f82 100644
--- a/drivers/ram/rockchip/Makefile
+++ b/drivers/ram/rockchip/Makefile
@@ -3,10 +3,11 @@
# Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
#
+obj-$(CONFIG_RAM_ROCKCHIP_DEBUG) += sdram_debug.o
obj-$(CONFIG_ROCKCHIP_RK3368) = dmc-rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3128) = sdram_rk3128.o
obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o
obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o
obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk3288.o
obj-$(CONFIG_ROCKCHIP_RK3328) = sdram_rk3328.o
-obj-$(CONFIG_ROCKCHIP_RK3399) = sdram_rk3399.o
+obj-$(CONFIG_RAM_RK3399) += sdram_rk3399.o
diff --git a/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc b/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc
new file mode 100644
index 0000000..c50a03d
--- /dev/null
+++ b/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc
@@ -0,0 +1,1570 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd.
+ * (C) Copyright 2019 Amarula Solutions
+ */
+
+{
+ {
+ {
+ {
+ .rank = 0x2,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x1,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF,
+ .ddrconfig = 1,
+ },
+ {
+ .ddrtiminga0 = 0x80241d22,
+ .ddrtimingb0 = 0x15050f08,
+ .ddrtimingc0 = {
+ 0x00000602,
+ },
+ .devtodev0 = 0x00002122,
+ .ddrmode = {
+ 0x0000004c,
+ },
+ .agingx0 = 0x00000000,
+ }
+ },
+ {
+ {
+ .rank = 0x2,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x1,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF,
+ .ddrconfig = 1,
+ },
+ {
+ .ddrtiminga0 = 0x80241d22,
+ .ddrtimingb0 = 0x15050f08,
+ .ddrtimingc0 = {
+ 0x00000602,
+ },
+ .devtodev0 = 0x00002122,
+ .ddrmode = {
+ 0x0000004c,
+ },
+ .agingx0 = 0x00000000,
+ }
+ }
+ },
+ {
+ .ddr_freq = 400 * MHz,
+ .dramtype = LPDDR4,
+ .num_channels = 2,
+ .stride = 13,
+ .odt = 1,
+ },
+ {
+ {
+ 0x00000b00, /* DENALI_CTL_00_DATA */
+ 0x00000000, /* DENALI_CTL_01_DATA */
+ 0x00000000, /* DENALI_CTL_02_DATA */
+ 0x00000000, /* DENALI_CTL_03_DATA */
+ 0x00000000, /* DENALI_CTL_04_DATA */
+ 0x00013880, /* DENALI_CTL_05_DATA */
+ 0x000c3500, /* DENALI_CTL_06_DATA */
+ 0x00000005, /* DENALI_CTL_07_DATA */
+ 0x00000320, /* DENALI_CTL_08_DATA */
+ 0x00027100, /* DENALI_CTL_09_DATA */
+ 0x00186a00, /* DENALI_CTL_10_DATA */
+ 0x00000005, /* DENALI_CTL_11_DATA */
+ 0x00000640, /* DENALI_CTL_12_DATA */
+ 0x00002710, /* DENALI_CTL_13_DATA */
+ 0x000186a0, /* DENALI_CTL_14_DATA */
+ 0x00000005, /* DENALI_CTL_15_DATA */
+ 0x01000064, /* DENALI_CTL_16_DATA */
+ 0x00000000, /* DENALI_CTL_17_DATA */
+ 0x02020101, /* DENALI_CTL_18_DATA */
+ 0x00000102, /* DENALI_CTL_19_DATA */
+ 0x00000050, /* DENALI_CTL_20_DATA */
+ 0x000000c8, /* DENALI_CTL_21_DATA */
+ 0x00000000, /* DENALI_CTL_22_DATA */
+ 0x06140000, /* DENALI_CTL_23_DATA */
+ 0x00081c00, /* DENALI_CTL_24_DATA */
+ 0x0400040c, /* DENALI_CTL_25_DATA */
+ 0x19042008, /* DENALI_CTL_26_DATA */
+ 0x10080a11, /* DENALI_CTL_27_DATA */
+ 0x22310800, /* DENALI_CTL_28_DATA */
+ 0x00200f0a, /* DENALI_CTL_29_DATA */
+ 0x0a030704, /* DENALI_CTL_30_DATA */
+ 0x08000204, /* DENALI_CTL_31_DATA */
+ 0x00000a0a, /* DENALI_CTL_32_DATA */
+ 0x04006db0, /* DENALI_CTL_33_DATA */
+ 0x0a0a0804, /* DENALI_CTL_34_DATA */
+ 0x0600db60, /* DENALI_CTL_35_DATA */
+ 0x0a0a0806, /* DENALI_CTL_36_DATA */
+ 0x04000db6, /* DENALI_CTL_37_DATA */
+ 0x02030404, /* DENALI_CTL_38_DATA */
+ 0x0f0a0800, /* DENALI_CTL_39_DATA */
+ 0x08040411, /* DENALI_CTL_40_DATA */
+ 0x1400640a, /* DENALI_CTL_41_DATA */
+ 0x02010a0a, /* DENALI_CTL_42_DATA */
+ 0x00010001, /* DENALI_CTL_43_DATA */
+ 0x04082012, /* DENALI_CTL_44_DATA */
+ 0x00041109, /* DENALI_CTL_45_DATA */
+ 0x00000000, /* DENALI_CTL_46_DATA */
+ 0x03010000, /* DENALI_CTL_47_DATA */
+ 0x06100034, /* DENALI_CTL_48_DATA */
+ 0x0c280068, /* DENALI_CTL_49_DATA */
+ 0x00bb0007, /* DENALI_CTL_50_DATA */
+ 0x00000000, /* DENALI_CTL_51_DATA */
+ 0x00060003, /* DENALI_CTL_52_DATA */
+ 0x000a0003, /* DENALI_CTL_53_DATA */
+ 0x000a0014, /* DENALI_CTL_54_DATA */
+ 0x01000000, /* DENALI_CTL_55_DATA */
+ 0x030a0000, /* DENALI_CTL_56_DATA */
+ 0x0c000002, /* DENALI_CTL_57_DATA */
+ 0x00000103, /* DENALI_CTL_58_DATA */
+ 0x0003030a, /* DENALI_CTL_59_DATA */
+ 0x00060037, /* DENALI_CTL_60_DATA */
+ 0x0003006e, /* DENALI_CTL_61_DATA */
+ 0x05050007, /* DENALI_CTL_62_DATA */
+ 0x03020605, /* DENALI_CTL_63_DATA */
+ 0x06050301, /* DENALI_CTL_64_DATA */
+ 0x06020c05, /* DENALI_CTL_65_DATA */
+ 0x05050302, /* DENALI_CTL_66_DATA */
+ 0x03020305, /* DENALI_CTL_67_DATA */
+ 0x00000301, /* DENALI_CTL_68_DATA */
+ 0x00000301, /* DENALI_CTL_69_DATA */
+ 0x00000001, /* DENALI_CTL_70_DATA */
+ 0x00000000, /* DENALI_CTL_71_DATA */
+ 0x00000000, /* DENALI_CTL_72_DATA */
+ 0x01000000, /* DENALI_CTL_73_DATA */
+ 0x80104002, /* DENALI_CTL_74_DATA */
+ 0x00040003, /* DENALI_CTL_75_DATA */
+ 0x00040005, /* DENALI_CTL_76_DATA */
+ 0x00030000, /* DENALI_CTL_77_DATA */
+ 0x00050004, /* DENALI_CTL_78_DATA */
+ 0x00000004, /* DENALI_CTL_79_DATA */
+ 0x00040003, /* DENALI_CTL_80_DATA */
+ 0x00040005, /* DENALI_CTL_81_DATA */
+ 0x18400000, /* DENALI_CTL_82_DATA */
+ 0x00000c20, /* DENALI_CTL_83_DATA */
+ 0x185030a0, /* DENALI_CTL_84_DATA */
+ 0x02ec0000, /* DENALI_CTL_85_DATA */
+ 0x00000176, /* DENALI_CTL_86_DATA */
+ 0x00000000, /* DENALI_CTL_87_DATA */
+ 0x00000000, /* DENALI_CTL_88_DATA */
+ 0x00000000, /* DENALI_CTL_89_DATA */
+ 0x00000000, /* DENALI_CTL_90_DATA */
+ 0x00000000, /* DENALI_CTL_91_DATA */
+ 0x06030300, /* DENALI_CTL_92_DATA */
+ 0x00030303, /* DENALI_CTL_93_DATA */
+ 0x02030200, /* DENALI_CTL_94_DATA */
+ 0x00040703, /* DENALI_CTL_95_DATA */
+ 0x03020302, /* DENALI_CTL_96_DATA */
+ 0x02000407, /* DENALI_CTL_97_DATA */
+ 0x07030203, /* DENALI_CTL_98_DATA */
+ 0x00030f04, /* DENALI_CTL_99_DATA */
+ 0x00070004, /* DENALI_CTL_100_DATA */
+ 0x00000000, /* DENALI_CTL_101_DATA */
+ 0x00000000, /* DENALI_CTL_102_DATA */
+ 0x00000000, /* DENALI_CTL_103_DATA */
+ 0x00000000, /* DENALI_CTL_104_DATA */
+ 0x00000000, /* DENALI_CTL_105_DATA */
+ 0x00000000, /* DENALI_CTL_106_DATA */
+ 0x00000000, /* DENALI_CTL_107_DATA */
+ 0x00010000, /* DENALI_CTL_108_DATA */
+ 0x20040020, /* DENALI_CTL_109_DATA */
+ 0x00200400, /* DENALI_CTL_110_DATA */
+ 0x01000400, /* DENALI_CTL_111_DATA */
+ 0x00000b80, /* DENALI_CTL_112_DATA */
+ 0x00000000, /* DENALI_CTL_113_DATA */
+ 0x00000001, /* DENALI_CTL_114_DATA */
+ 0x00000002, /* DENALI_CTL_115_DATA */
+ 0x0000000e, /* DENALI_CTL_116_DATA */
+ 0x00000000, /* DENALI_CTL_117_DATA */
+ 0x00000000, /* DENALI_CTL_118_DATA */
+ 0x00000000, /* DENALI_CTL_119_DATA */
+ 0x00000000, /* DENALI_CTL_120_DATA */
+ 0x00000000, /* DENALI_CTL_121_DATA */
+ 0x00500000, /* DENALI_CTL_122_DATA */
+ 0x00640028, /* DENALI_CTL_123_DATA */
+ 0x00640404, /* DENALI_CTL_124_DATA */
+ 0x005000a0, /* DENALI_CTL_125_DATA */
+ 0x060600c8, /* DENALI_CTL_126_DATA */
+ 0x000a00c8, /* DENALI_CTL_127_DATA */
+ 0x000d0005, /* DENALI_CTL_128_DATA */
+ 0x000d0404, /* DENALI_CTL_129_DATA */
+ 0x00000000, /* DENALI_CTL_130_DATA */
+ 0x00000000, /* DENALI_CTL_131_DATA */
+ 0x00000000, /* DENALI_CTL_132_DATA */
+ 0x001400a3, /* DENALI_CTL_133_DATA */
+ 0x00e30009, /* DENALI_CTL_134_DATA */
+ 0x00120024, /* DENALI_CTL_135_DATA */
+ 0x00040063, /* DENALI_CTL_136_DATA */
+ 0x00000000, /* DENALI_CTL_137_DATA */
+ 0x00310031, /* DENALI_CTL_138_DATA */
+ 0x00000031, /* DENALI_CTL_139_DATA */
+ 0x004d0000, /* DENALI_CTL_140_DATA */
+ 0x004d004d, /* DENALI_CTL_141_DATA */
+ 0x004d0000, /* DENALI_CTL_142_DATA */
+ 0x004d004d, /* DENALI_CTL_143_DATA */
+ 0x00010101, /* DENALI_CTL_144_DATA */
+ 0x00000000, /* DENALI_CTL_145_DATA */
+ 0x00000000, /* DENALI_CTL_146_DATA */
+ 0x001400a3, /* DENALI_CTL_147_DATA */
+ 0x00e30009, /* DENALI_CTL_148_DATA */
+ 0x00120024, /* DENALI_CTL_149_DATA */
+ 0x00040063, /* DENALI_CTL_150_DATA */
+ 0x00000000, /* DENALI_CTL_151_DATA */
+ 0x00310031, /* DENALI_CTL_152_DATA */
+ 0x00000031, /* DENALI_CTL_153_DATA */
+ 0x004d0000, /* DENALI_CTL_154_DATA */
+ 0x004d004d, /* DENALI_CTL_155_DATA */
+ 0x004d0000, /* DENALI_CTL_156_DATA */
+ 0x004d004d, /* DENALI_CTL_157_DATA */
+ 0x00010101, /* DENALI_CTL_158_DATA */
+ 0x00000000, /* DENALI_CTL_159_DATA */
+ 0x00000000, /* DENALI_CTL_160_DATA */
+ 0x00000000, /* DENALI_CTL_161_DATA */
+ 0x00000001, /* DENALI_CTL_162_DATA */
+ 0x00000000, /* DENALI_CTL_163_DATA */
+ 0x18151100, /* DENALI_CTL_164_DATA */
+ 0x0000000c, /* DENALI_CTL_165_DATA */
+ 0x00000000, /* DENALI_CTL_166_DATA */
+ 0x00000000, /* DENALI_CTL_167_DATA */
+ 0x00000000, /* DENALI_CTL_168_DATA */
+ 0x00000000, /* DENALI_CTL_169_DATA */
+ 0x00000000, /* DENALI_CTL_170_DATA */
+ 0x00000000, /* DENALI_CTL_171_DATA */
+ 0x00000000, /* DENALI_CTL_172_DATA */
+ 0x00000000, /* DENALI_CTL_173_DATA */
+ 0x00000000, /* DENALI_CTL_174_DATA */
+ 0x00000000, /* DENALI_CTL_175_DATA */
+ 0x00000000, /* DENALI_CTL_176_DATA */
+ 0x00000000, /* DENALI_CTL_177_DATA */
+ 0x00000000, /* DENALI_CTL_178_DATA */
+ 0x00020003, /* DENALI_CTL_179_DATA */
+ 0x00400100, /* DENALI_CTL_180_DATA */
+ 0x000c0190, /* DENALI_CTL_181_DATA */
+ 0x01000200, /* DENALI_CTL_182_DATA */
+ 0x03200040, /* DENALI_CTL_183_DATA */
+ 0x00020018, /* DENALI_CTL_184_DATA */
+ 0x00400100, /* DENALI_CTL_185_DATA */
+ 0x00080032, /* DENALI_CTL_186_DATA */
+ 0x00140000, /* DENALI_CTL_187_DATA */
+ 0x00030028, /* DENALI_CTL_188_DATA */
+ 0x01010100, /* DENALI_CTL_189_DATA */
+ 0x02000202, /* DENALI_CTL_190_DATA */
+ 0x0b000002, /* DENALI_CTL_191_DATA */
+ 0x01000f0f, /* DENALI_CTL_192_DATA */
+ 0x00000000, /* DENALI_CTL_193_DATA */
+ 0x00000000, /* DENALI_CTL_194_DATA */
+ 0x00010003, /* DENALI_CTL_195_DATA */
+ 0x00000c03, /* DENALI_CTL_196_DATA */
+ 0x00040101, /* DENALI_CTL_197_DATA */
+ 0x04010100, /* DENALI_CTL_198_DATA */
+ 0x01000000, /* DENALI_CTL_199_DATA */
+ 0x02010000, /* DENALI_CTL_200_DATA */
+ 0x00000001, /* DENALI_CTL_201_DATA */
+ 0x00000000, /* DENALI_CTL_202_DATA */
+ 0x00000000, /* DENALI_CTL_203_DATA */
+ 0x00000000, /* DENALI_CTL_204_DATA */
+ 0x00000000, /* DENALI_CTL_205_DATA */
+ 0x00000000, /* DENALI_CTL_206_DATA */
+ 0x00000000, /* DENALI_CTL_207_DATA */
+ 0x00000000, /* DENALI_CTL_208_DATA */
+ 0x00000000, /* DENALI_CTL_209_DATA */
+ 0x00000000, /* DENALI_CTL_210_DATA */
+ 0x00010000, /* DENALI_CTL_211_DATA */
+ 0x00000001, /* DENALI_CTL_212_DATA */
+ 0x01010001, /* DENALI_CTL_213_DATA */
+ 0x05040001, /* DENALI_CTL_214_DATA */
+ 0x040a0703, /* DENALI_CTL_215_DATA */
+ 0x02080808, /* DENALI_CTL_216_DATA */
+ 0x020e000a, /* DENALI_CTL_217_DATA */
+ 0x020f010b, /* DENALI_CTL_218_DATA */
+ 0x000d0008, /* DENALI_CTL_219_DATA */
+ 0x00080b0a, /* DENALI_CTL_220_DATA */
+ 0x03000200, /* DENALI_CTL_221_DATA */
+ 0x00000100, /* DENALI_CTL_222_DATA */
+ 0x00000000, /* DENALI_CTL_223_DATA */
+ 0x00000000, /* DENALI_CTL_224_DATA */
+ 0x0d000001, /* DENALI_CTL_225_DATA */
+ 0x00000028, /* DENALI_CTL_226_DATA */
+ 0x00010000, /* DENALI_CTL_227_DATA */
+ 0x00000003, /* DENALI_CTL_228_DATA */
+ 0x00000000, /* DENALI_CTL_229_DATA */
+ 0x00000000, /* DENALI_CTL_230_DATA */
+ 0x00000000, /* DENALI_CTL_231_DATA */
+ 0x00000000, /* DENALI_CTL_232_DATA */
+ 0x00000000, /* DENALI_CTL_233_DATA */
+ 0x00000000, /* DENALI_CTL_234_DATA */
+ 0x00000000, /* DENALI_CTL_235_DATA */
+ 0x00000000, /* DENALI_CTL_236_DATA */
+ 0x00010100, /* DENALI_CTL_237_DATA */
+ 0x01000000, /* DENALI_CTL_238_DATA */
+ 0x00000001, /* DENALI_CTL_239_DATA */
+ 0x00000303, /* DENALI_CTL_240_DATA */
+ 0x00000000, /* DENALI_CTL_241_DATA */
+ 0x00000000, /* DENALI_CTL_242_DATA */
+ 0x00000000, /* DENALI_CTL_243_DATA */
+ 0x00000000, /* DENALI_CTL_244_DATA */
+ 0x00000000, /* DENALI_CTL_245_DATA */
+ 0x00000000, /* DENALI_CTL_246_DATA */
+ 0x00000000, /* DENALI_CTL_247_DATA */
+ 0x00000000, /* DENALI_CTL_248_DATA */
+ 0x00000000, /* DENALI_CTL_249_DATA */
+ 0x00000000, /* DENALI_CTL_250_DATA */
+ 0x00000000, /* DENALI_CTL_251_DATA */
+ 0x00000000, /* DENALI_CTL_252_DATA */
+ 0x00000000, /* DENALI_CTL_253_DATA */
+ 0x00000000, /* DENALI_CTL_254_DATA */
+ 0x00000000, /* DENALI_CTL_255_DATA */
+ 0x000556aa, /* DENALI_CTL_256_DATA */
+ 0x000aaaaa, /* DENALI_CTL_257_DATA */
+ 0x000aa955, /* DENALI_CTL_258_DATA */
+ 0x00055555, /* DENALI_CTL_259_DATA */
+ 0x000b3133, /* DENALI_CTL_260_DATA */
+ 0x0004cd33, /* DENALI_CTL_261_DATA */
+ 0x0004cecc, /* DENALI_CTL_262_DATA */
+ 0x000b32cc, /* DENALI_CTL_263_DATA */
+ 0x00010300, /* DENALI_CTL_264_DATA */
+ 0x03000100, /* DENALI_CTL_265_DATA */
+ 0x00000000, /* DENALI_CTL_266_DATA */
+ 0x00000000, /* DENALI_CTL_267_DATA */
+ 0x00000000, /* DENALI_CTL_268_DATA */
+ 0x00000000, /* DENALI_CTL_269_DATA */
+ 0x00000000, /* DENALI_CTL_270_DATA */
+ 0x00000000, /* DENALI_CTL_271_DATA */
+ 0x00000000, /* DENALI_CTL_272_DATA */
+ 0x00000000, /* DENALI_CTL_273_DATA */
+ 0x00ffff00, /* DENALI_CTL_274_DATA */
+ 0x1a160000, /* DENALI_CTL_275_DATA */
+ 0x08000012, /* DENALI_CTL_276_DATA */
+ 0x00000c20, /* DENALI_CTL_277_DATA */
+ 0x00000200, /* DENALI_CTL_278_DATA */
+ 0x00000200, /* DENALI_CTL_279_DATA */
+ 0x00000200, /* DENALI_CTL_280_DATA */
+ 0x00000200, /* DENALI_CTL_281_DATA */
+ 0x00000c20, /* DENALI_CTL_282_DATA */
+ 0x00007940, /* DENALI_CTL_283_DATA */
+ 0x18500409, /* DENALI_CTL_284_DATA */
+ 0x00000200, /* DENALI_CTL_285_DATA */
+ 0x00000200, /* DENALI_CTL_286_DATA */
+ 0x00000200, /* DENALI_CTL_287_DATA */
+ 0x00000200, /* DENALI_CTL_288_DATA */
+ 0x00001850, /* DENALI_CTL_289_DATA */
+ 0x0000f320, /* DENALI_CTL_290_DATA */
+ 0x0176060c, /* DENALI_CTL_291_DATA */
+ 0x00000200, /* DENALI_CTL_292_DATA */
+ 0x00000200, /* DENALI_CTL_293_DATA */
+ 0x00000200, /* DENALI_CTL_294_DATA */
+ 0x00000200, /* DENALI_CTL_295_DATA */
+ 0x00000176, /* DENALI_CTL_296_DATA */
+ 0x00000e9c, /* DENALI_CTL_297_DATA */
+ 0x02020205, /* DENALI_CTL_298_DATA */
+ 0x03030202, /* DENALI_CTL_299_DATA */
+ 0x00000018, /* DENALI_CTL_300_DATA */
+ 0x00000000, /* DENALI_CTL_301_DATA */
+ 0x00000000, /* DENALI_CTL_302_DATA */
+ 0x00001403, /* DENALI_CTL_303_DATA */
+ 0x00000000, /* DENALI_CTL_304_DATA */
+ 0x00000000, /* DENALI_CTL_305_DATA */
+ 0x00000000, /* DENALI_CTL_306_DATA */
+ 0x00030000, /* DENALI_CTL_307_DATA */
+ 0x000a001c, /* DENALI_CTL_308_DATA */
+ 0x000e0020, /* DENALI_CTL_309_DATA */
+ 0x00060018, /* DENALI_CTL_310_DATA */
+ 0x00000000, /* DENALI_CTL_311_DATA */
+ 0x00000000, /* DENALI_CTL_312_DATA */
+ 0x02000000, /* DENALI_CTL_313_DATA */
+ 0x00090305, /* DENALI_CTL_314_DATA */
+ 0x00050101, /* DENALI_CTL_315_DATA */
+ 0x00000000, /* DENALI_CTL_316_DATA */
+ 0x00000000, /* DENALI_CTL_317_DATA */
+ 0x00000000, /* DENALI_CTL_318_DATA */
+ 0x00000000, /* DENALI_CTL_319_DATA */
+ 0x00000000, /* DENALI_CTL_320_DATA */
+ 0x00000000, /* DENALI_CTL_321_DATA */
+ 0x00000000, /* DENALI_CTL_322_DATA */
+ 0x00000000, /* DENALI_CTL_323_DATA */
+ 0x01000001, /* DENALI_CTL_324_DATA */
+ 0x01010101, /* DENALI_CTL_325_DATA */
+ 0x01000101, /* DENALI_CTL_326_DATA */
+ 0x01000100, /* DENALI_CTL_327_DATA */
+ 0x00010001, /* DENALI_CTL_328_DATA */
+ 0x00010002, /* DENALI_CTL_329_DATA */
+ 0x00020100, /* DENALI_CTL_330_DATA */
+ 0x00000002 /* DENALI_CTL_331_DATA */
+ }
+ },
+ {
+ {
+ 0x00000b00, /* DENALI_PI_00_DATA */
+ 0x00000000, /* DENALI_PI_01_DATA */
+ 0x000002ec, /* DENALI_PI_02_DATA */
+ 0x00000176, /* DENALI_PI_03_DATA */
+ 0x000030a0, /* DENALI_PI_04_DATA */
+ 0x00001850, /* DENALI_PI_05_DATA */
+ 0x00001840, /* DENALI_PI_06_DATA */
+ 0x01760c20, /* DENALI_PI_07_DATA */
+ 0x00000200, /* DENALI_PI_08_DATA */
+ 0x00000200, /* DENALI_PI_09_DATA */
+ 0x00000200, /* DENALI_PI_10_DATA */
+ 0x00000200, /* DENALI_PI_11_DATA */
+ 0x00001850, /* DENALI_PI_12_DATA */
+ 0x00000200, /* DENALI_PI_13_DATA */
+ 0x00000200, /* DENALI_PI_14_DATA */
+ 0x00000200, /* DENALI_PI_15_DATA */
+ 0x00000200, /* DENALI_PI_16_DATA */
+ 0x00000c20, /* DENALI_PI_17_DATA */
+ 0x00000200, /* DENALI_PI_18_DATA */
+ 0x00000200, /* DENALI_PI_19_DATA */
+ 0x00000200, /* DENALI_PI_20_DATA */
+ 0x00000200, /* DENALI_PI_21_DATA */
+ 0x00010000, /* DENALI_PI_22_DATA */
+ 0x00000007, /* DENALI_PI_23_DATA */
+ 0x01000001, /* DENALI_PI_24_DATA */
+ 0x00000000, /* DENALI_PI_25_DATA */
+ 0x3fffffff, /* DENALI_PI_26_DATA */
+ 0x00000000, /* DENALI_PI_27_DATA */
+ 0x00000000, /* DENALI_PI_28_DATA */
+ 0x00000000, /* DENALI_PI_29_DATA */
+ 0x00000000, /* DENALI_PI_30_DATA */
+ 0x00000000, /* DENALI_PI_31_DATA */
+ 0x00000000, /* DENALI_PI_32_DATA */
+ 0x00000000, /* DENALI_PI_33_DATA */
+ 0x00000000, /* DENALI_PI_34_DATA */
+ 0x00000000, /* DENALI_PI_35_DATA */
+ 0x00000000, /* DENALI_PI_36_DATA */
+ 0x00000000, /* DENALI_PI_37_DATA */
+ 0x00000000, /* DENALI_PI_38_DATA */
+ 0x00000000, /* DENALI_PI_39_DATA */
+ 0x00000000, /* DENALI_PI_40_DATA */
+ 0x0f000101, /* DENALI_PI_41_DATA */
+ 0x082b3223, /* DENALI_PI_42_DATA */
+ 0x080c0004, /* DENALI_PI_43_DATA */
+ 0x00061c00, /* DENALI_PI_44_DATA */
+ 0x00000214, /* DENALI_PI_45_DATA */
+ 0x00bb0007, /* DENALI_PI_46_DATA */
+ 0x0c280068, /* DENALI_PI_47_DATA */
+ 0x06100034, /* DENALI_PI_48_DATA */
+ 0x00000500, /* DENALI_PI_49_DATA */
+ 0x00000000, /* DENALI_PI_50_DATA */
+ 0x00000000, /* DENALI_PI_51_DATA */
+ 0x00000000, /* DENALI_PI_52_DATA */
+ 0x00000000, /* DENALI_PI_53_DATA */
+ 0x00000000, /* DENALI_PI_54_DATA */
+ 0x00000000, /* DENALI_PI_55_DATA */
+ 0x00000000, /* DENALI_PI_56_DATA */
+ 0x00000000, /* DENALI_PI_57_DATA */
+ 0x04040100, /* DENALI_PI_58_DATA */
+ 0x0a000004, /* DENALI_PI_59_DATA */
+ 0x00000128, /* DENALI_PI_60_DATA */
+ 0x00000000, /* DENALI_PI_61_DATA */
+ 0x0003000f, /* DENALI_PI_62_DATA */
+ 0x00000018, /* DENALI_PI_63_DATA */
+ 0x00000000, /* DENALI_PI_64_DATA */
+ 0x00000000, /* DENALI_PI_65_DATA */
+ 0x00060002, /* DENALI_PI_66_DATA */
+ 0x00010001, /* DENALI_PI_67_DATA */
+ 0x00000101, /* DENALI_PI_68_DATA */
+ 0x00020001, /* DENALI_PI_69_DATA */
+ 0x00080004, /* DENALI_PI_70_DATA */
+ 0x00000000, /* DENALI_PI_71_DATA */
+ 0x05030000, /* DENALI_PI_72_DATA */
+ 0x070a0404, /* DENALI_PI_73_DATA */
+ 0x00000000, /* DENALI_PI_74_DATA */
+ 0x00000000, /* DENALI_PI_75_DATA */
+ 0x00000000, /* DENALI_PI_76_DATA */
+ 0x000f0f00, /* DENALI_PI_77_DATA */
+ 0x0000001e, /* DENALI_PI_78_DATA */
+ 0x00000000, /* DENALI_PI_79_DATA */
+ 0x01010300, /* DENALI_PI_80_DATA */
+ 0x00000000, /* DENALI_PI_81_DATA */
+ 0x00000000, /* DENALI_PI_82_DATA */
+ 0x01000000, /* DENALI_PI_83_DATA */
+ 0x00000101, /* DENALI_PI_84_DATA */
+ 0x55555a5a, /* DENALI_PI_85_DATA */
+ 0x55555a5a, /* DENALI_PI_86_DATA */
+ 0x55555a5a, /* DENALI_PI_87_DATA */
+ 0x55555a5a, /* DENALI_PI_88_DATA */
+ 0x0c050001, /* DENALI_PI_89_DATA */
+ 0x06020009, /* DENALI_PI_90_DATA */
+ 0x00010004, /* DENALI_PI_91_DATA */
+ 0x00000203, /* DENALI_PI_92_DATA */
+ 0x00030000, /* DENALI_PI_93_DATA */
+ 0x170f0000, /* DENALI_PI_94_DATA */
+ 0x00060018, /* DENALI_PI_95_DATA */
+ 0x000e0020, /* DENALI_PI_96_DATA */
+ 0x000a001c, /* DENALI_PI_97_DATA */
+ 0x00000000, /* DENALI_PI_98_DATA */
+ 0x00000000, /* DENALI_PI_99_DATA */
+ 0x00000100, /* DENALI_PI_100_DATA */
+ 0x140a0000, /* DENALI_PI_101_DATA */
+ 0x000d010a, /* DENALI_PI_102_DATA */
+ 0x0100c802, /* DENALI_PI_103_DATA */
+ 0x010a0064, /* DENALI_PI_104_DATA */
+ 0x000e0100, /* DENALI_PI_105_DATA */
+ 0x0100000e, /* DENALI_PI_106_DATA */
+ 0x00c900c9, /* DENALI_PI_107_DATA */
+ 0x00650100, /* DENALI_PI_108_DATA */
+ 0x1e1a0065, /* DENALI_PI_109_DATA */
+ 0x10010204, /* DENALI_PI_110_DATA */
+ 0x06070605, /* DENALI_PI_111_DATA */
+ 0x20000202, /* DENALI_PI_112_DATA */
+ 0x00201000, /* DENALI_PI_113_DATA */
+ 0x00201000, /* DENALI_PI_114_DATA */
+ 0x04041000, /* DENALI_PI_115_DATA */
+ 0x10020100, /* DENALI_PI_116_DATA */
+ 0x0003010c, /* DENALI_PI_117_DATA */
+ 0x004b004a, /* DENALI_PI_118_DATA */
+ 0x1a0f0000, /* DENALI_PI_119_DATA */
+ 0x0102041e, /* DENALI_PI_120_DATA */
+ 0x34000000, /* DENALI_PI_121_DATA */
+ 0x00000000, /* DENALI_PI_122_DATA */
+ 0x00000000, /* DENALI_PI_123_DATA */
+ 0x00010000, /* DENALI_PI_124_DATA */
+ 0x00000400, /* DENALI_PI_125_DATA */
+ 0x00310000, /* DENALI_PI_126_DATA */
+ 0x004d4d00, /* DENALI_PI_127_DATA */
+ 0x00120024, /* DENALI_PI_128_DATA */
+ 0x4d000031, /* DENALI_PI_129_DATA */
+ 0x0000144d, /* DENALI_PI_130_DATA */
+ 0x00310009, /* DENALI_PI_131_DATA */
+ 0x004d4d00, /* DENALI_PI_132_DATA */
+ 0x00000004, /* DENALI_PI_133_DATA */
+ 0x4d000031, /* DENALI_PI_134_DATA */
+ 0x0000244d, /* DENALI_PI_135_DATA */
+ 0x00310012, /* DENALI_PI_136_DATA */
+ 0x004d4d00, /* DENALI_PI_137_DATA */
+ 0x00090014, /* DENALI_PI_138_DATA */
+ 0x4d000031, /* DENALI_PI_139_DATA */
+ 0x0004004d, /* DENALI_PI_140_DATA */
+ 0x00310000, /* DENALI_PI_141_DATA */
+ 0x004d4d00, /* DENALI_PI_142_DATA */
+ 0x00120024, /* DENALI_PI_143_DATA */
+ 0x4d000031, /* DENALI_PI_144_DATA */
+ 0x0000144d, /* DENALI_PI_145_DATA */
+ 0x00310009, /* DENALI_PI_146_DATA */
+ 0x004d4d00, /* DENALI_PI_147_DATA */
+ 0x00000004, /* DENALI_PI_148_DATA */
+ 0x4d000031, /* DENALI_PI_149_DATA */
+ 0x0000244d, /* DENALI_PI_150_DATA */
+ 0x00310012, /* DENALI_PI_151_DATA */
+ 0x004d4d00, /* DENALI_PI_152_DATA */
+ 0x00090014, /* DENALI_PI_153_DATA */
+ 0x4d000031, /* DENALI_PI_154_DATA */
+ 0x0200004d, /* DENALI_PI_155_DATA */
+ 0x00c8000d, /* DENALI_PI_156_DATA */
+ 0x08080064, /* DENALI_PI_157_DATA */
+ 0x040a0404, /* DENALI_PI_158_DATA */
+ 0x03000d92, /* DENALI_PI_159_DATA */
+ 0x010a2001, /* DENALI_PI_160_DATA */
+ 0x0f11080a, /* DENALI_PI_161_DATA */
+ 0x0000110a, /* DENALI_PI_162_DATA */
+ 0x2200d92e, /* DENALI_PI_163_DATA */
+ 0x080c2003, /* DENALI_PI_164_DATA */
+ 0x0809080a, /* DENALI_PI_165_DATA */
+ 0x00000a0a, /* DENALI_PI_166_DATA */
+ 0x11006c97, /* DENALI_PI_167_DATA */
+ 0x040a2002, /* DENALI_PI_168_DATA */
+ 0x0200020a, /* DENALI_PI_169_DATA */
+ 0x02000200, /* DENALI_PI_170_DATA */
+ 0x02000200, /* DENALI_PI_171_DATA */
+ 0x02000200, /* DENALI_PI_172_DATA */
+ 0x02000200, /* DENALI_PI_173_DATA */
+ 0x00000000, /* DENALI_PI_174_DATA */
+ 0x00000000, /* DENALI_PI_175_DATA */
+ 0x00000000, /* DENALI_PI_176_DATA */
+ 0x00000000, /* DENALI_PI_177_DATA */
+ 0x00000000, /* DENALI_PI_178_DATA */
+ 0x00000000, /* DENALI_PI_179_DATA */
+ 0x00000000, /* DENALI_PI_180_DATA */
+ 0x00000000, /* DENALI_PI_181_DATA */
+ 0x00000000, /* DENALI_PI_182_DATA */
+ 0x00000000, /* DENALI_PI_183_DATA */
+ 0x00000000, /* DENALI_PI_184_DATA */
+ 0x00000000, /* DENALI_PI_185_DATA */
+ 0x01000400, /* DENALI_PI_186_DATA */
+ 0x00017600, /* DENALI_PI_187_DATA */
+ 0x00000e9c, /* DENALI_PI_188_DATA */
+ 0x00001850, /* DENALI_PI_189_DATA */
+ 0x0000f320, /* DENALI_PI_190_DATA */
+ 0x00000c20, /* DENALI_PI_191_DATA */
+ 0x00007940, /* DENALI_PI_192_DATA */
+ 0x08000000, /* DENALI_PI_193_DATA */
+ 0x00000100, /* DENALI_PI_194_DATA */
+ 0x00000000, /* DENALI_PI_195_DATA */
+ 0x00000000, /* DENALI_PI_196_DATA */
+ 0x00000000, /* DENALI_PI_197_DATA */
+ 0x00000000, /* DENALI_PI_198_DATA */
+ 0x00000002 /* DENALI_PI_199_DATA */
+ }
+ },
+ {
+ {
+ 0x76543210, /* DENALI_PHY_00_DATA */
+ 0x0004f008, /* DENALI_PHY_01_DATA */
+ 0x00020119, /* DENALI_PHY_02_DATA */
+ 0x00000000, /* DENALI_PHY_03_DATA */
+ 0x00000000, /* DENALI_PHY_04_DATA */
+ 0x00010000, /* DENALI_PHY_05_DATA */
+ 0x01665555, /* DENALI_PHY_06_DATA */
+ 0x03665555, /* DENALI_PHY_07_DATA */
+ 0x00010f00, /* DENALI_PHY_08_DATA */
+ 0x04000100, /* DENALI_PHY_09_DATA */
+ 0x00000001, /* DENALI_PHY_10_DATA */
+ 0x00170180, /* DENALI_PHY_11_DATA */
+ 0x00cc0201, /* DENALI_PHY_12_DATA */
+ 0x00030066, /* DENALI_PHY_13_DATA */
+ 0x00000000, /* DENALI_PHY_14_DATA */
+ 0x00000000, /* DENALI_PHY_15_DATA */
+ 0x00000000, /* DENALI_PHY_16_DATA */
+ 0x00000000, /* DENALI_PHY_17_DATA */
+ 0x00000000, /* DENALI_PHY_18_DATA */
+ 0x00000000, /* DENALI_PHY_19_DATA */
+ 0x00000000, /* DENALI_PHY_20_DATA */
+ 0x00000000, /* DENALI_PHY_21_DATA */
+ 0x04080000, /* DENALI_PHY_22_DATA */
+ 0x04080400, /* DENALI_PHY_23_DATA */
+ 0x30000000, /* DENALI_PHY_24_DATA */
+ 0x0c00c007, /* DENALI_PHY_25_DATA */
+ 0x00000100, /* DENALI_PHY_26_DATA */
+ 0x00000000, /* DENALI_PHY_27_DATA */
+ 0xfd02fe01, /* DENALI_PHY_28_DATA */
+ 0xf708fb04, /* DENALI_PHY_29_DATA */
+ 0xdf20ef10, /* DENALI_PHY_30_DATA */
+ 0x7f80bf40, /* DENALI_PHY_31_DATA */
+ 0x0001aaaa, /* DENALI_PHY_32_DATA */
+ 0x00000000, /* DENALI_PHY_33_DATA */
+ 0x00000000, /* DENALI_PHY_34_DATA */
+ 0x00000000, /* DENALI_PHY_35_DATA */
+ 0x00000000, /* DENALI_PHY_36_DATA */
+ 0x00000000, /* DENALI_PHY_37_DATA */
+ 0x00000000, /* DENALI_PHY_38_DATA */
+ 0x00000000, /* DENALI_PHY_39_DATA */
+ 0x00000000, /* DENALI_PHY_40_DATA */
+ 0x00000000, /* DENALI_PHY_41_DATA */
+ 0x00000000, /* DENALI_PHY_42_DATA */
+ 0x00000000, /* DENALI_PHY_43_DATA */
+ 0x00000000, /* DENALI_PHY_44_DATA */
+ 0x00000000, /* DENALI_PHY_45_DATA */
+ 0x00000000, /* DENALI_PHY_46_DATA */
+ 0x00000000, /* DENALI_PHY_47_DATA */
+ 0x00000000, /* DENALI_PHY_48_DATA */
+ 0x00000000, /* DENALI_PHY_49_DATA */
+ 0x00000000, /* DENALI_PHY_50_DATA */
+ 0x00000000, /* DENALI_PHY_51_DATA */
+ 0x00200000, /* DENALI_PHY_52_DATA */
+ 0x00000000, /* DENALI_PHY_53_DATA */
+ 0x00000000, /* DENALI_PHY_54_DATA */
+ 0x00000000, /* DENALI_PHY_55_DATA */
+ 0x00000000, /* DENALI_PHY_56_DATA */
+ 0x00000000, /* DENALI_PHY_57_DATA */
+ 0x00000000, /* DENALI_PHY_58_DATA */
+ 0x02800280, /* DENALI_PHY_59_DATA */
+ 0x02800280, /* DENALI_PHY_60_DATA */
+ 0x02800280, /* DENALI_PHY_61_DATA */
+ 0x02800280, /* DENALI_PHY_62_DATA */
+ 0x00000280, /* DENALI_PHY_63_DATA */
+ 0x00000000, /* DENALI_PHY_64_DATA */
+ 0x00000000, /* DENALI_PHY_65_DATA */
+ 0x00000000, /* DENALI_PHY_66_DATA */
+ 0x00000000, /* DENALI_PHY_67_DATA */
+ 0x00800000, /* DENALI_PHY_68_DATA */
+ 0x00800080, /* DENALI_PHY_69_DATA */
+ 0x00800080, /* DENALI_PHY_70_DATA */
+ 0x00800080, /* DENALI_PHY_71_DATA */
+ 0x00800080, /* DENALI_PHY_72_DATA */
+ 0x00800080, /* DENALI_PHY_73_DATA */
+ 0x00800080, /* DENALI_PHY_74_DATA */
+ 0x00800080, /* DENALI_PHY_75_DATA */
+ 0x00800080, /* DENALI_PHY_76_DATA */
+ 0x01190080, /* DENALI_PHY_77_DATA */
+ 0x00000001, /* DENALI_PHY_78_DATA */
+ 0x00000000, /* DENALI_PHY_79_DATA */
+ 0x00000000, /* DENALI_PHY_80_DATA */
+ 0x00000200, /* DENALI_PHY_81_DATA */
+ 0x00000000, /* DENALI_PHY_82_DATA */
+ 0x51315152, /* DENALI_PHY_83_DATA */
+ 0xc0003150, /* DENALI_PHY_84_DATA */
+ 0x010000c0, /* DENALI_PHY_85_DATA */
+ 0x00100000, /* DENALI_PHY_86_DATA */
+ 0x07044204, /* DENALI_PHY_87_DATA */
+ 0x000f0c18, /* DENALI_PHY_88_DATA */
+ 0x01000140, /* DENALI_PHY_89_DATA */
+ 0x00000c10, /* DENALI_PHY_90_DATA */
+ 0x00000000, /* DENALI_PHY_91_DATA */
+ 0x00000000, /* DENALI_PHY_92_DATA */
+ 0x00000000, /* DENALI_PHY_93_DATA */
+ 0x00000000, /* DENALI_PHY_94_DATA */
+ 0x00000000, /* DENALI_PHY_95_DATA */
+ 0x00000000, /* DENALI_PHY_96_DATA */
+ 0x00000000, /* DENALI_PHY_97_DATA */
+ 0x00000000, /* DENALI_PHY_98_DATA */
+ 0x00000000, /* DENALI_PHY_99_DATA */
+ 0x00000000, /* DENALI_PHY_100_DATA */
+ 0x00000000, /* DENALI_PHY_101_DATA */
+ 0x00000000, /* DENALI_PHY_102_DATA */
+ 0x00000000, /* DENALI_PHY_103_DATA */
+ 0x00000000, /* DENALI_PHY_104_DATA */
+ 0x00000000, /* DENALI_PHY_105_DATA */
+ 0x00000000, /* DENALI_PHY_106_DATA */
+ 0x00000000, /* DENALI_PHY_107_DATA */
+ 0x00000000, /* DENALI_PHY_108_DATA */
+ 0x00000000, /* DENALI_PHY_109_DATA */
+ 0x00000000, /* DENALI_PHY_110_DATA */
+ 0x00000000, /* DENALI_PHY_111_DATA */
+ 0x00000000, /* DENALI_PHY_112_DATA */
+ 0x00000000, /* DENALI_PHY_113_DATA */
+ 0x00000000, /* DENALI_PHY_114_DATA */
+ 0x00000000, /* DENALI_PHY_115_DATA */
+ 0x00000000, /* DENALI_PHY_116_DATA */
+ 0x00000000, /* DENALI_PHY_117_DATA */
+ 0x00000000, /* DENALI_PHY_118_DATA */
+ 0x00000000, /* DENALI_PHY_119_DATA */
+ 0x00000000, /* DENALI_PHY_120_DATA */
+ 0x00000000, /* DENALI_PHY_121_DATA */
+ 0x00000000, /* DENALI_PHY_122_DATA */
+ 0x00000000, /* DENALI_PHY_123_DATA */
+ 0x00000000, /* DENALI_PHY_124_DATA */
+ 0x00000000, /* DENALI_PHY_125_DATA */
+ 0x00000000, /* DENALI_PHY_126_DATA */
+ 0x00000000, /* DENALI_PHY_127_DATA */
+ 0x76543210, /* DENALI_PHY_128_DATA */
+ 0x0004f008, /* DENALI_PHY_129_DATA */
+ 0x00020119, /* DENALI_PHY_130_DATA */
+ 0x00000000, /* DENALI_PHY_131_DATA */
+ 0x00000000, /* DENALI_PHY_132_DATA */
+ 0x00010000, /* DENALI_PHY_133_DATA */
+ 0x01665555, /* DENALI_PHY_134_DATA */
+ 0x03665555, /* DENALI_PHY_135_DATA */
+ 0x00010f00, /* DENALI_PHY_136_DATA */
+ 0x04000100, /* DENALI_PHY_137_DATA */
+ 0x00000001, /* DENALI_PHY_138_DATA */
+ 0x00170180, /* DENALI_PHY_139_DATA */
+ 0x00cc0201, /* DENALI_PHY_140_DATA */
+ 0x00030066, /* DENALI_PHY_141_DATA */
+ 0x00000000, /* DENALI_PHY_142_DATA */
+ 0x00000000, /* DENALI_PHY_143_DATA */
+ 0x00000000, /* DENALI_PHY_144_DATA */
+ 0x00000000, /* DENALI_PHY_145_DATA */
+ 0x00000000, /* DENALI_PHY_146_DATA */
+ 0x00000000, /* DENALI_PHY_147_DATA */
+ 0x00000000, /* DENALI_PHY_148_DATA */
+ 0x00000000, /* DENALI_PHY_149_DATA */
+ 0x04080000, /* DENALI_PHY_150_DATA */
+ 0x04080400, /* DENALI_PHY_151_DATA */
+ 0x30000000, /* DENALI_PHY_152_DATA */
+ 0x0c00c007, /* DENALI_PHY_153_DATA */
+ 0x00000100, /* DENALI_PHY_154_DATA */
+ 0x00000000, /* DENALI_PHY_155_DATA */
+ 0xfd02fe01, /* DENALI_PHY_156_DATA */
+ 0xf708fb04, /* DENALI_PHY_157_DATA */
+ 0xdf20ef10, /* DENALI_PHY_158_DATA */
+ 0x7f80bf40, /* DENALI_PHY_159_DATA */
+ 0x0000aaaa, /* DENALI_PHY_160_DATA */
+ 0x00000000, /* DENALI_PHY_161_DATA */
+ 0x00000000, /* DENALI_PHY_162_DATA */
+ 0x00000000, /* DENALI_PHY_163_DATA */
+ 0x00000000, /* DENALI_PHY_164_DATA */
+ 0x00000000, /* DENALI_PHY_165_DATA */
+ 0x00000000, /* DENALI_PHY_166_DATA */
+ 0x00000000, /* DENALI_PHY_167_DATA */
+ 0x00000000, /* DENALI_PHY_168_DATA */
+ 0x00000000, /* DENALI_PHY_169_DATA */
+ 0x00000000, /* DENALI_PHY_170_DATA */
+ 0x00000000, /* DENALI_PHY_171_DATA */
+ 0x00000000, /* DENALI_PHY_172_DATA */
+ 0x00000000, /* DENALI_PHY_173_DATA */
+ 0x00000000, /* DENALI_PHY_174_DATA */
+ 0x00000000, /* DENALI_PHY_175_DATA */
+ 0x00000000, /* DENALI_PHY_176_DATA */
+ 0x00000000, /* DENALI_PHY_177_DATA */
+ 0x00000000, /* DENALI_PHY_178_DATA */
+ 0x00000000, /* DENALI_PHY_179_DATA */
+ 0x00200000, /* DENALI_PHY_180_DATA */
+ 0x00000000, /* DENALI_PHY_181_DATA */
+ 0x00000000, /* DENALI_PHY_182_DATA */
+ 0x00000000, /* DENALI_PHY_183_DATA */
+ 0x00000000, /* DENALI_PHY_184_DATA */
+ 0x00000000, /* DENALI_PHY_185_DATA */
+ 0x00000000, /* DENALI_PHY_186_DATA */
+ 0x02800280, /* DENALI_PHY_187_DATA */
+ 0x02800280, /* DENALI_PHY_188_DATA */
+ 0x02800280, /* DENALI_PHY_189_DATA */
+ 0x02800280, /* DENALI_PHY_190_DATA */
+ 0x00000280, /* DENALI_PHY_191_DATA */
+ 0x00000000, /* DENALI_PHY_192_DATA */
+ 0x00000000, /* DENALI_PHY_193_DATA */
+ 0x00000000, /* DENALI_PHY_194_DATA */
+ 0x00000000, /* DENALI_PHY_195_DATA */
+ 0x00800000, /* DENALI_PHY_196_DATA */
+ 0x00800080, /* DENALI_PHY_197_DATA */
+ 0x00800080, /* DENALI_PHY_198_DATA */
+ 0x00800080, /* DENALI_PHY_199_DATA */
+ 0x00800080, /* DENALI_PHY_200_DATA */
+ 0x00800080, /* DENALI_PHY_201_DATA */
+ 0x00800080, /* DENALI_PHY_202_DATA */
+ 0x00800080, /* DENALI_PHY_203_DATA */
+ 0x00800080, /* DENALI_PHY_204_DATA */
+ 0x01190080, /* DENALI_PHY_205_DATA */
+ 0x00000001, /* DENALI_PHY_206_DATA */
+ 0x00000000, /* DENALI_PHY_207_DATA */
+ 0x00000000, /* DENALI_PHY_208_DATA */
+ 0x00000200, /* DENALI_PHY_209_DATA */
+ 0x00000000, /* DENALI_PHY_210_DATA */
+ 0x51315152, /* DENALI_PHY_211_DATA */
+ 0xc0003150, /* DENALI_PHY_212_DATA */
+ 0x010000c0, /* DENALI_PHY_213_DATA */
+ 0x00100000, /* DENALI_PHY_214_DATA */
+ 0x07044204, /* DENALI_PHY_215_DATA */
+ 0x000f0c18, /* DENALI_PHY_216_DATA */
+ 0x01000140, /* DENALI_PHY_217_DATA */
+ 0x00000c10, /* DENALI_PHY_218_DATA */
+ 0x00000000, /* DENALI_PHY_219_DATA */
+ 0x00000000, /* DENALI_PHY_220_DATA */
+ 0x00000000, /* DENALI_PHY_221_DATA */
+ 0x00000000, /* DENALI_PHY_222_DATA */
+ 0x00000000, /* DENALI_PHY_223_DATA */
+ 0x00000000, /* DENALI_PHY_224_DATA */
+ 0x00000000, /* DENALI_PHY_225_DATA */
+ 0x00000000, /* DENALI_PHY_226_DATA */
+ 0x00000000, /* DENALI_PHY_227_DATA */
+ 0x00000000, /* DENALI_PHY_228_DATA */
+ 0x00000000, /* DENALI_PHY_229_DATA */
+ 0x00000000, /* DENALI_PHY_230_DATA */
+ 0x00000000, /* DENALI_PHY_231_DATA */
+ 0x00000000, /* DENALI_PHY_232_DATA */
+ 0x00000000, /* DENALI_PHY_233_DATA */
+ 0x00000000, /* DENALI_PHY_234_DATA */
+ 0x00000000, /* DENALI_PHY_235_DATA */
+ 0x00000000, /* DENALI_PHY_236_DATA */
+ 0x00000000, /* DENALI_PHY_237_DATA */
+ 0x00000000, /* DENALI_PHY_238_DATA */
+ 0x00000000, /* DENALI_PHY_239_DATA */
+ 0x00000000, /* DENALI_PHY_240_DATA */
+ 0x00000000, /* DENALI_PHY_241_DATA */
+ 0x00000000, /* DENALI_PHY_242_DATA */
+ 0x00000000, /* DENALI_PHY_243_DATA */
+ 0x00000000, /* DENALI_PHY_244_DATA */
+ 0x00000000, /* DENALI_PHY_245_DATA */
+ 0x00000000, /* DENALI_PHY_246_DATA */
+ 0x00000000, /* DENALI_PHY_247_DATA */
+ 0x00000000, /* DENALI_PHY_248_DATA */
+ 0x00000000, /* DENALI_PHY_249_DATA */
+ 0x00000000, /* DENALI_PHY_250_DATA */
+ 0x00000000, /* DENALI_PHY_251_DATA */
+ 0x00000000, /* DENALI_PHY_252_DATA */
+ 0x00000000, /* DENALI_PHY_253_DATA */
+ 0x00000000, /* DENALI_PHY_254_DATA */
+ 0x00000000, /* DENALI_PHY_255_DATA */
+ 0x76543210, /* DENALI_PHY_256_DATA */
+ 0x0004f008, /* DENALI_PHY_257_DATA */
+ 0x00020119, /* DENALI_PHY_258_DATA */
+ 0x00000000, /* DENALI_PHY_259_DATA */
+ 0x00000000, /* DENALI_PHY_260_DATA */
+ 0x00010000, /* DENALI_PHY_261_DATA */
+ 0x01665555, /* DENALI_PHY_262_DATA */
+ 0x03665555, /* DENALI_PHY_263_DATA */
+ 0x00010f00, /* DENALI_PHY_264_DATA */
+ 0x04000100, /* DENALI_PHY_265_DATA */
+ 0x00000001, /* DENALI_PHY_266_DATA */
+ 0x00170180, /* DENALI_PHY_267_DATA */
+ 0x00cc0201, /* DENALI_PHY_268_DATA */
+ 0x00030066, /* DENALI_PHY_269_DATA */
+ 0x00000000, /* DENALI_PHY_270_DATA */
+ 0x00000000, /* DENALI_PHY_271_DATA */
+ 0x00000000, /* DENALI_PHY_272_DATA */
+ 0x00000000, /* DENALI_PHY_273_DATA */
+ 0x00000000, /* DENALI_PHY_274_DATA */
+ 0x00000000, /* DENALI_PHY_275_DATA */
+ 0x00000000, /* DENALI_PHY_276_DATA */
+ 0x00000000, /* DENALI_PHY_277_DATA */
+ 0x04080000, /* DENALI_PHY_278_DATA */
+ 0x04080400, /* DENALI_PHY_279_DATA */
+ 0x30000000, /* DENALI_PHY_280_DATA */
+ 0x0c00c007, /* DENALI_PHY_281_DATA */
+ 0x00000100, /* DENALI_PHY_282_DATA */
+ 0x00000000, /* DENALI_PHY_283_DATA */
+ 0xfd02fe01, /* DENALI_PHY_284_DATA */
+ 0xf708fb04, /* DENALI_PHY_285_DATA */
+ 0xdf20ef10, /* DENALI_PHY_286_DATA */
+ 0x7f80bf40, /* DENALI_PHY_287_DATA */
+ 0x0001aaaa, /* DENALI_PHY_288_DATA */
+ 0x00000000, /* DENALI_PHY_289_DATA */
+ 0x00000000, /* DENALI_PHY_290_DATA */
+ 0x00000000, /* DENALI_PHY_291_DATA */
+ 0x00000000, /* DENALI_PHY_292_DATA */
+ 0x00000000, /* DENALI_PHY_293_DATA */
+ 0x00000000, /* DENALI_PHY_294_DATA */
+ 0x00000000, /* DENALI_PHY_295_DATA */
+ 0x00000000, /* DENALI_PHY_296_DATA */
+ 0x00000000, /* DENALI_PHY_297_DATA */
+ 0x00000000, /* DENALI_PHY_298_DATA */
+ 0x00000000, /* DENALI_PHY_299_DATA */
+ 0x00000000, /* DENALI_PHY_300_DATA */
+ 0x00000000, /* DENALI_PHY_301_DATA */
+ 0x00000000, /* DENALI_PHY_302_DATA */
+ 0x00000000, /* DENALI_PHY_303_DATA */
+ 0x00000000, /* DENALI_PHY_304_DATA */
+ 0x00000000, /* DENALI_PHY_305_DATA */
+ 0x00000000, /* DENALI_PHY_306_DATA */
+ 0x00000000, /* DENALI_PHY_307_DATA */
+ 0x00200000, /* DENALI_PHY_308_DATA */
+ 0x00000000, /* DENALI_PHY_309_DATA */
+ 0x00000000, /* DENALI_PHY_310_DATA */
+ 0x00000000, /* DENALI_PHY_311_DATA */
+ 0x00000000, /* DENALI_PHY_312_DATA */
+ 0x00000000, /* DENALI_PHY_313_DATA */
+ 0x00000000, /* DENALI_PHY_314_DATA */
+ 0x02800280, /* DENALI_PHY_315_DATA */
+ 0x02800280, /* DENALI_PHY_316_DATA */
+ 0x02800280, /* DENALI_PHY_317_DATA */
+ 0x02800280, /* DENALI_PHY_318_DATA */
+ 0x00000280, /* DENALI_PHY_319_DATA */
+ 0x00000000, /* DENALI_PHY_320_DATA */
+ 0x00000000, /* DENALI_PHY_321_DATA */
+ 0x00000000, /* DENALI_PHY_322_DATA */
+ 0x00000000, /* DENALI_PHY_323_DATA */
+ 0x00800000, /* DENALI_PHY_324_DATA */
+ 0x00800080, /* DENALI_PHY_325_DATA */
+ 0x00800080, /* DENALI_PHY_326_DATA */
+ 0x00800080, /* DENALI_PHY_327_DATA */
+ 0x00800080, /* DENALI_PHY_328_DATA */
+ 0x00800080, /* DENALI_PHY_329_DATA */
+ 0x00800080, /* DENALI_PHY_330_DATA */
+ 0x00800080, /* DENALI_PHY_331_DATA */
+ 0x00800080, /* DENALI_PHY_332_DATA */
+ 0x01190080, /* DENALI_PHY_333_DATA */
+ 0x00000001, /* DENALI_PHY_334_DATA */
+ 0x00000000, /* DENALI_PHY_335_DATA */
+ 0x00000000, /* DENALI_PHY_336_DATA */
+ 0x00000200, /* DENALI_PHY_337_DATA */
+ 0x00000000, /* DENALI_PHY_338_DATA */
+ 0x51315152, /* DENALI_PHY_339_DATA */
+ 0xc0003150, /* DENALI_PHY_340_DATA */
+ 0x010000c0, /* DENALI_PHY_341_DATA */
+ 0x00100000, /* DENALI_PHY_342_DATA */
+ 0x07044204, /* DENALI_PHY_343_DATA */
+ 0x000f0c18, /* DENALI_PHY_344_DATA */
+ 0x01000140, /* DENALI_PHY_345_DATA */
+ 0x00000c10, /* DENALI_PHY_346_DATA */
+ 0x00000000, /* DENALI_PHY_347_DATA */
+ 0x00000000, /* DENALI_PHY_348_DATA */
+ 0x00000000, /* DENALI_PHY_349_DATA */
+ 0x00000000, /* DENALI_PHY_350_DATA */
+ 0x00000000, /* DENALI_PHY_351_DATA */
+ 0x00000000, /* DENALI_PHY_352_DATA */
+ 0x00000000, /* DENALI_PHY_353_DATA */
+ 0x00000000, /* DENALI_PHY_354_DATA */
+ 0x00000000, /* DENALI_PHY_355_DATA */
+ 0x00000000, /* DENALI_PHY_356_DATA */
+ 0x00000000, /* DENALI_PHY_357_DATA */
+ 0x00000000, /* DENALI_PHY_358_DATA */
+ 0x00000000, /* DENALI_PHY_359_DATA */
+ 0x00000000, /* DENALI_PHY_360_DATA */
+ 0x00000000, /* DENALI_PHY_361_DATA */
+ 0x00000000, /* DENALI_PHY_362_DATA */
+ 0x00000000, /* DENALI_PHY_363_DATA */
+ 0x00000000, /* DENALI_PHY_364_DATA */
+ 0x00000000, /* DENALI_PHY_365_DATA */
+ 0x00000000, /* DENALI_PHY_366_DATA */
+ 0x00000000, /* DENALI_PHY_367_DATA */
+ 0x00000000, /* DENALI_PHY_368_DATA */
+ 0x00000000, /* DENALI_PHY_369_DATA */
+ 0x00000000, /* DENALI_PHY_370_DATA */
+ 0x00000000, /* DENALI_PHY_371_DATA */
+ 0x00000000, /* DENALI_PHY_372_DATA */
+ 0x00000000, /* DENALI_PHY_373_DATA */
+ 0x00000000, /* DENALI_PHY_374_DATA */
+ 0x00000000, /* DENALI_PHY_375_DATA */
+ 0x00000000, /* DENALI_PHY_376_DATA */
+ 0x00000000, /* DENALI_PHY_377_DATA */
+ 0x00000000, /* DENALI_PHY_378_DATA */
+ 0x00000000, /* DENALI_PHY_379_DATA */
+ 0x00000000, /* DENALI_PHY_380_DATA */
+ 0x00000000, /* DENALI_PHY_381_DATA */
+ 0x00000000, /* DENALI_PHY_382_DATA */
+ 0x00000000, /* DENALI_PHY_383_DATA */
+ 0x76543210, /* DENALI_PHY_384_DATA */
+ 0x0004f008, /* DENALI_PHY_385_DATA */
+ 0x00020119, /* DENALI_PHY_386_DATA */
+ 0x00000000, /* DENALI_PHY_387_DATA */
+ 0x00000000, /* DENALI_PHY_388_DATA */
+ 0x00010000, /* DENALI_PHY_389_DATA */
+ 0x01665555, /* DENALI_PHY_390_DATA */
+ 0x03665555, /* DENALI_PHY_391_DATA */
+ 0x00010f00, /* DENALI_PHY_392_DATA */
+ 0x04000100, /* DENALI_PHY_393_DATA */
+ 0x00000001, /* DENALI_PHY_394_DATA */
+ 0x00170180, /* DENALI_PHY_395_DATA */
+ 0x00cc0201, /* DENALI_PHY_396_DATA */
+ 0x00030066, /* DENALI_PHY_397_DATA */
+ 0x00000000, /* DENALI_PHY_398_DATA */
+ 0x00000000, /* DENALI_PHY_399_DATA */
+ 0x00000000, /* DENALI_PHY_400_DATA */
+ 0x00000000, /* DENALI_PHY_401_DATA */
+ 0x00000000, /* DENALI_PHY_402_DATA */
+ 0x00000000, /* DENALI_PHY_403_DATA */
+ 0x00000000, /* DENALI_PHY_404_DATA */
+ 0x00000000, /* DENALI_PHY_405_DATA */
+ 0x04080000, /* DENALI_PHY_406_DATA */
+ 0x04080400, /* DENALI_PHY_407_DATA */
+ 0x30000000, /* DENALI_PHY_408_DATA */
+ 0x0c00c007, /* DENALI_PHY_409_DATA */
+ 0x00000100, /* DENALI_PHY_410_DATA */
+ 0x00000000, /* DENALI_PHY_411_DATA */
+ 0xfd02fe01, /* DENALI_PHY_412_DATA */
+ 0xf708fb04, /* DENALI_PHY_413_DATA */
+ 0xdf20ef10, /* DENALI_PHY_414_DATA */
+ 0x7f80bf40, /* DENALI_PHY_415_DATA */
+ 0x0000aaaa, /* DENALI_PHY_416_DATA */
+ 0x00000000, /* DENALI_PHY_417_DATA */
+ 0x00000000, /* DENALI_PHY_418_DATA */
+ 0x00000000, /* DENALI_PHY_419_DATA */
+ 0x00000000, /* DENALI_PHY_420_DATA */
+ 0x00000000, /* DENALI_PHY_421_DATA */
+ 0x00000000, /* DENALI_PHY_422_DATA */
+ 0x00000000, /* DENALI_PHY_423_DATA */
+ 0x00000000, /* DENALI_PHY_424_DATA */
+ 0x00000000, /* DENALI_PHY_425_DATA */
+ 0x00000000, /* DENALI_PHY_426_DATA */
+ 0x00000000, /* DENALI_PHY_427_DATA */
+ 0x00000000, /* DENALI_PHY_428_DATA */
+ 0x00000000, /* DENALI_PHY_429_DATA */
+ 0x00000000, /* DENALI_PHY_430_DATA */
+ 0x00000000, /* DENALI_PHY_431_DATA */
+ 0x00000000, /* DENALI_PHY_432_DATA */
+ 0x00000000, /* DENALI_PHY_433_DATA */
+ 0x00000000, /* DENALI_PHY_434_DATA */
+ 0x00000000, /* DENALI_PHY_435_DATA */
+ 0x00200000, /* DENALI_PHY_436_DATA */
+ 0x00000000, /* DENALI_PHY_437_DATA */
+ 0x00000000, /* DENALI_PHY_438_DATA */
+ 0x00000000, /* DENALI_PHY_439_DATA */
+ 0x00000000, /* DENALI_PHY_440_DATA */
+ 0x00000000, /* DENALI_PHY_441_DATA */
+ 0x00000000, /* DENALI_PHY_442_DATA */
+ 0x02800280, /* DENALI_PHY_443_DATA */
+ 0x02800280, /* DENALI_PHY_444_DATA */
+ 0x02800280, /* DENALI_PHY_445_DATA */
+ 0x02800280, /* DENALI_PHY_446_DATA */
+ 0x00000280, /* DENALI_PHY_447_DATA */
+ 0x00000000, /* DENALI_PHY_448_DATA */
+ 0x00000000, /* DENALI_PHY_449_DATA */
+ 0x00000000, /* DENALI_PHY_450_DATA */
+ 0x00000000, /* DENALI_PHY_451_DATA */
+ 0x00800000, /* DENALI_PHY_452_DATA */
+ 0x00800080, /* DENALI_PHY_453_DATA */
+ 0x00800080, /* DENALI_PHY_454_DATA */
+ 0x00800080, /* DENALI_PHY_455_DATA */
+ 0x00800080, /* DENALI_PHY_456_DATA */
+ 0x00800080, /* DENALI_PHY_457_DATA */
+ 0x00800080, /* DENALI_PHY_458_DATA */
+ 0x00800080, /* DENALI_PHY_459_DATA */
+ 0x00800080, /* DENALI_PHY_460_DATA */
+ 0x01190080, /* DENALI_PHY_461_DATA */
+ 0x00000001, /* DENALI_PHY_462_DATA */
+ 0x00000000, /* DENALI_PHY_463_DATA */
+ 0x00000000, /* DENALI_PHY_464_DATA */
+ 0x00000200, /* DENALI_PHY_465_DATA */
+ 0x00000000, /* DENALI_PHY_466_DATA */
+ 0x51315152, /* DENALI_PHY_467_DATA */
+ 0xc0003150, /* DENALI_PHY_468_DATA */
+ 0x010000c0, /* DENALI_PHY_469_DATA */
+ 0x00100000, /* DENALI_PHY_470_DATA */
+ 0x07044204, /* DENALI_PHY_471_DATA */
+ 0x000f0c18, /* DENALI_PHY_472_DATA */
+ 0x01000140, /* DENALI_PHY_473_DATA */
+ 0x00000c10, /* DENALI_PHY_474_DATA */
+ 0x00000000, /* DENALI_PHY_475_DATA */
+ 0x00000000, /* DENALI_PHY_476_DATA */
+ 0x00000000, /* DENALI_PHY_477_DATA */
+ 0x00000000, /* DENALI_PHY_478_DATA */
+ 0x00000000, /* DENALI_PHY_479_DATA */
+ 0x00000000, /* DENALI_PHY_480_DATA */
+ 0x00000000, /* DENALI_PHY_481_DATA */
+ 0x00000000, /* DENALI_PHY_482_DATA */
+ 0x00000000, /* DENALI_PHY_483_DATA */
+ 0x00000000, /* DENALI_PHY_484_DATA */
+ 0x00000000, /* DENALI_PHY_485_DATA */
+ 0x00000000, /* DENALI_PHY_486_DATA */
+ 0x00000000, /* DENALI_PHY_487_DATA */
+ 0x00000000, /* DENALI_PHY_488_DATA */
+ 0x00000000, /* DENALI_PHY_489_DATA */
+ 0x00000000, /* DENALI_PHY_490_DATA */
+ 0x00000000, /* DENALI_PHY_491_DATA */
+ 0x00000000, /* DENALI_PHY_492_DATA */
+ 0x00000000, /* DENALI_PHY_493_DATA */
+ 0x00000000, /* DENALI_PHY_494_DATA */
+ 0x00000000, /* DENALI_PHY_495_DATA */
+ 0x00000000, /* DENALI_PHY_496_DATA */
+ 0x00000000, /* DENALI_PHY_497_DATA */
+ 0x00000000, /* DENALI_PHY_498_DATA */
+ 0x00000000, /* DENALI_PHY_499_DATA */
+ 0x00000000, /* DENALI_PHY_500_DATA */
+ 0x00000000, /* DENALI_PHY_501_DATA */
+ 0x00000000, /* DENALI_PHY_502_DATA */
+ 0x00000000, /* DENALI_PHY_503_DATA */
+ 0x00000000, /* DENALI_PHY_504_DATA */
+ 0x00000000, /* DENALI_PHY_505_DATA */
+ 0x00000000, /* DENALI_PHY_506_DATA */
+ 0x00000000, /* DENALI_PHY_507_DATA */
+ 0x00000000, /* DENALI_PHY_508_DATA */
+ 0x00000000, /* DENALI_PHY_509_DATA */
+ 0x00000000, /* DENALI_PHY_510_DATA */
+ 0x00000000, /* DENALI_PHY_511_DATA */
+ 0x00000000, /* DENALI_PHY_512_DATA */
+ 0x00000000, /* DENALI_PHY_513_DATA */
+ 0x00000000, /* DENALI_PHY_514_DATA */
+ 0x00000000, /* DENALI_PHY_515_DATA */
+ 0x00000000, /* DENALI_PHY_516_DATA */
+ 0x00000000, /* DENALI_PHY_517_DATA */
+ 0x00000000, /* DENALI_PHY_518_DATA */
+ 0x00000002, /* DENALI_PHY_519_DATA */
+ 0x00000000, /* DENALI_PHY_520_DATA */
+ 0x00000000, /* DENALI_PHY_521_DATA */
+ 0x00000000, /* DENALI_PHY_522_DATA */
+ 0x00400320, /* DENALI_PHY_523_DATA */
+ 0x00000040, /* DENALI_PHY_524_DATA */
+ 0x00dcba98, /* DENALI_PHY_525_DATA */
+ 0x00000000, /* DENALI_PHY_526_DATA */
+ 0x00dcba98, /* DENALI_PHY_527_DATA */
+ 0x01000000, /* DENALI_PHY_528_DATA */
+ 0x00020003, /* DENALI_PHY_529_DATA */
+ 0x00000000, /* DENALI_PHY_530_DATA */
+ 0x00000000, /* DENALI_PHY_531_DATA */
+ 0x00000000, /* DENALI_PHY_532_DATA */
+ 0x0000002a, /* DENALI_PHY_533_DATA */
+ 0x00000015, /* DENALI_PHY_534_DATA */
+ 0x00000015, /* DENALI_PHY_535_DATA */
+ 0x0000002a, /* DENALI_PHY_536_DATA */
+ 0x00000033, /* DENALI_PHY_537_DATA */
+ 0x0000000c, /* DENALI_PHY_538_DATA */
+ 0x0000000c, /* DENALI_PHY_539_DATA */
+ 0x00000033, /* DENALI_PHY_540_DATA */
+ 0x0a418820, /* DENALI_PHY_541_DATA */
+ 0x003f0000, /* DENALI_PHY_542_DATA */
+ 0x0000003f, /* DENALI_PHY_543_DATA */
+ 0x00030055, /* DENALI_PHY_544_DATA */
+ 0x03000300, /* DENALI_PHY_545_DATA */
+ 0x03000300, /* DENALI_PHY_546_DATA */
+ 0x00000300, /* DENALI_PHY_547_DATA */
+ 0x42080010, /* DENALI_PHY_548_DATA */
+ 0x00000003, /* DENALI_PHY_549_DATA */
+ 0x00000000, /* DENALI_PHY_550_DATA */
+ 0x00000000, /* DENALI_PHY_551_DATA */
+ 0x00000000, /* DENALI_PHY_552_DATA */
+ 0x00000000, /* DENALI_PHY_553_DATA */
+ 0x00000000, /* DENALI_PHY_554_DATA */
+ 0x00000000, /* DENALI_PHY_555_DATA */
+ 0x00000000, /* DENALI_PHY_556_DATA */
+ 0x00000000, /* DENALI_PHY_557_DATA */
+ 0x00000000, /* DENALI_PHY_558_DATA */
+ 0x00000000, /* DENALI_PHY_559_DATA */
+ 0x00000000, /* DENALI_PHY_560_DATA */
+ 0x00000000, /* DENALI_PHY_561_DATA */
+ 0x00000000, /* DENALI_PHY_562_DATA */
+ 0x00000000, /* DENALI_PHY_563_DATA */
+ 0x00000000, /* DENALI_PHY_564_DATA */
+ 0x00000000, /* DENALI_PHY_565_DATA */
+ 0x00000000, /* DENALI_PHY_566_DATA */
+ 0x00000000, /* DENALI_PHY_567_DATA */
+ 0x00000000, /* DENALI_PHY_568_DATA */
+ 0x00000000, /* DENALI_PHY_569_DATA */
+ 0x00000000, /* DENALI_PHY_570_DATA */
+ 0x00000000, /* DENALI_PHY_571_DATA */
+ 0x00000000, /* DENALI_PHY_572_DATA */
+ 0x00000000, /* DENALI_PHY_573_DATA */
+ 0x00000000, /* DENALI_PHY_574_DATA */
+ 0x00000000, /* DENALI_PHY_575_DATA */
+ 0x00000000, /* DENALI_PHY_576_DATA */
+ 0x00000000, /* DENALI_PHY_577_DATA */
+ 0x00000000, /* DENALI_PHY_578_DATA */
+ 0x00000000, /* DENALI_PHY_579_DATA */
+ 0x00000000, /* DENALI_PHY_580_DATA */
+ 0x00000000, /* DENALI_PHY_581_DATA */
+ 0x00000000, /* DENALI_PHY_582_DATA */
+ 0x00000000, /* DENALI_PHY_583_DATA */
+ 0x00000000, /* DENALI_PHY_584_DATA */
+ 0x00000000, /* DENALI_PHY_585_DATA */
+ 0x00000000, /* DENALI_PHY_586_DATA */
+ 0x00000000, /* DENALI_PHY_587_DATA */
+ 0x00000000, /* DENALI_PHY_588_DATA */
+ 0x00000000, /* DENALI_PHY_589_DATA */
+ 0x00000000, /* DENALI_PHY_590_DATA */
+ 0x00000000, /* DENALI_PHY_591_DATA */
+ 0x00000000, /* DENALI_PHY_592_DATA */
+ 0x00000000, /* DENALI_PHY_593_DATA */
+ 0x00000000, /* DENALI_PHY_594_DATA */
+ 0x00000000, /* DENALI_PHY_595_DATA */
+ 0x00000000, /* DENALI_PHY_596_DATA */
+ 0x00000000, /* DENALI_PHY_597_DATA */
+ 0x00000000, /* DENALI_PHY_598_DATA */
+ 0x00000000, /* DENALI_PHY_599_DATA */
+ 0x00000000, /* DENALI_PHY_600_DATA */
+ 0x00000000, /* DENALI_PHY_601_DATA */
+ 0x00000000, /* DENALI_PHY_602_DATA */
+ 0x00000000, /* DENALI_PHY_603_DATA */
+ 0x00000000, /* DENALI_PHY_604_DATA */
+ 0x00000000, /* DENALI_PHY_605_DATA */
+ 0x00000000, /* DENALI_PHY_606_DATA */
+ 0x00000000, /* DENALI_PHY_607_DATA */
+ 0x00000000, /* DENALI_PHY_608_DATA */
+ 0x00000000, /* DENALI_PHY_609_DATA */
+ 0x00000000, /* DENALI_PHY_610_DATA */
+ 0x00000000, /* DENALI_PHY_611_DATA */
+ 0x00000000, /* DENALI_PHY_612_DATA */
+ 0x00000000, /* DENALI_PHY_613_DATA */
+ 0x00000000, /* DENALI_PHY_614_DATA */
+ 0x00000000, /* DENALI_PHY_615_DATA */
+ 0x00000000, /* DENALI_PHY_616_DATA */
+ 0x00000000, /* DENALI_PHY_617_DATA */
+ 0x00000000, /* DENALI_PHY_618_DATA */
+ 0x00000000, /* DENALI_PHY_619_DATA */
+ 0x00000000, /* DENALI_PHY_620_DATA */
+ 0x00000000, /* DENALI_PHY_621_DATA */
+ 0x00000000, /* DENALI_PHY_622_DATA */
+ 0x00000000, /* DENALI_PHY_623_DATA */
+ 0x00000000, /* DENALI_PHY_624_DATA */
+ 0x00000000, /* DENALI_PHY_625_DATA */
+ 0x00000000, /* DENALI_PHY_626_DATA */
+ 0x00000000, /* DENALI_PHY_627_DATA */
+ 0x00000000, /* DENALI_PHY_628_DATA */
+ 0x00000000, /* DENALI_PHY_629_DATA */
+ 0x00000000, /* DENALI_PHY_630_DATA */
+ 0x00000000, /* DENALI_PHY_631_DATA */
+ 0x00000000, /* DENALI_PHY_632_DATA */
+ 0x00000000, /* DENALI_PHY_633_DATA */
+ 0x00000000, /* DENALI_PHY_634_DATA */
+ 0x00000000, /* DENALI_PHY_635_DATA */
+ 0x00000000, /* DENALI_PHY_636_DATA */
+ 0x00000000, /* DENALI_PHY_637_DATA */
+ 0x00000000, /* DENALI_PHY_638_DATA */
+ 0x00000000, /* DENALI_PHY_639_DATA */
+ 0x00000000, /* DENALI_PHY_640_DATA */
+ 0x00000000, /* DENALI_PHY_641_DATA */
+ 0x00000000, /* DENALI_PHY_642_DATA */
+ 0x00000000, /* DENALI_PHY_643_DATA */
+ 0x00000000, /* DENALI_PHY_644_DATA */
+ 0x00000000, /* DENALI_PHY_645_DATA */
+ 0x00000000, /* DENALI_PHY_646_DATA */
+ 0x00000002, /* DENALI_PHY_647_DATA */
+ 0x00000000, /* DENALI_PHY_648_DATA */
+ 0x00000000, /* DENALI_PHY_649_DATA */
+ 0x00000000, /* DENALI_PHY_650_DATA */
+ 0x00400320, /* DENALI_PHY_651_DATA */
+ 0x00000040, /* DENALI_PHY_652_DATA */
+ 0x00000000, /* DENALI_PHY_653_DATA */
+ 0x00000000, /* DENALI_PHY_654_DATA */
+ 0x00000000, /* DENALI_PHY_655_DATA */
+ 0x01000000, /* DENALI_PHY_656_DATA */
+ 0x00020003, /* DENALI_PHY_657_DATA */
+ 0x00000000, /* DENALI_PHY_658_DATA */
+ 0x00000000, /* DENALI_PHY_659_DATA */
+ 0x00000000, /* DENALI_PHY_660_DATA */
+ 0x0000002a, /* DENALI_PHY_661_DATA */
+ 0x00000015, /* DENALI_PHY_662_DATA */
+ 0x00000015, /* DENALI_PHY_663_DATA */
+ 0x0000002a, /* DENALI_PHY_664_DATA */
+ 0x00000033, /* DENALI_PHY_665_DATA */
+ 0x0000000c, /* DENALI_PHY_666_DATA */
+ 0x0000000c, /* DENALI_PHY_667_DATA */
+ 0x00000033, /* DENALI_PHY_668_DATA */
+ 0x00000000, /* DENALI_PHY_669_DATA */
+ 0x00000000, /* DENALI_PHY_670_DATA */
+ 0x00000000, /* DENALI_PHY_671_DATA */
+ 0x00030055, /* DENALI_PHY_672_DATA */
+ 0x03000300, /* DENALI_PHY_673_DATA */
+ 0x03000300, /* DENALI_PHY_674_DATA */
+ 0x00000300, /* DENALI_PHY_675_DATA */
+ 0x42080010, /* DENALI_PHY_676_DATA */
+ 0x00000003, /* DENALI_PHY_677_DATA */
+ 0x00000000, /* DENALI_PHY_678_DATA */
+ 0x00000000, /* DENALI_PHY_679_DATA */
+ 0x00000000, /* DENALI_PHY_680_DATA */
+ 0x00000000, /* DENALI_PHY_681_DATA */
+ 0x00000000, /* DENALI_PHY_682_DATA */
+ 0x00000000, /* DENALI_PHY_683_DATA */
+ 0x00000000, /* DENALI_PHY_684_DATA */
+ 0x00000000, /* DENALI_PHY_685_DATA */
+ 0x00000000, /* DENALI_PHY_686_DATA */
+ 0x00000000, /* DENALI_PHY_687_DATA */
+ 0x00000000, /* DENALI_PHY_688_DATA */
+ 0x00000000, /* DENALI_PHY_689_DATA */
+ 0x00000000, /* DENALI_PHY_690_DATA */
+ 0x00000000, /* DENALI_PHY_691_DATA */
+ 0x00000000, /* DENALI_PHY_692_DATA */
+ 0x00000000, /* DENALI_PHY_693_DATA */
+ 0x00000000, /* DENALI_PHY_694_DATA */
+ 0x00000000, /* DENALI_PHY_695_DATA */
+ 0x00000000, /* DENALI_PHY_696_DATA */
+ 0x00000000, /* DENALI_PHY_697_DATA */
+ 0x00000000, /* DENALI_PHY_698_DATA */
+ 0x00000000, /* DENALI_PHY_699_DATA */
+ 0x00000000, /* DENALI_PHY_700_DATA */
+ 0x00000000, /* DENALI_PHY_701_DATA */
+ 0x00000000, /* DENALI_PHY_702_DATA */
+ 0x00000000, /* DENALI_PHY_703_DATA */
+ 0x00000000, /* DENALI_PHY_704_DATA */
+ 0x00000000, /* DENALI_PHY_705_DATA */
+ 0x00000000, /* DENALI_PHY_706_DATA */
+ 0x00000000, /* DENALI_PHY_707_DATA */
+ 0x00000000, /* DENALI_PHY_708_DATA */
+ 0x00000000, /* DENALI_PHY_709_DATA */
+ 0x00000000, /* DENALI_PHY_710_DATA */
+ 0x00000000, /* DENALI_PHY_711_DATA */
+ 0x00000000, /* DENALI_PHY_712_DATA */
+ 0x00000000, /* DENALI_PHY_713_DATA */
+ 0x00000000, /* DENALI_PHY_714_DATA */
+ 0x00000000, /* DENALI_PHY_715_DATA */
+ 0x00000000, /* DENALI_PHY_716_DATA */
+ 0x00000000, /* DENALI_PHY_717_DATA */
+ 0x00000000, /* DENALI_PHY_718_DATA */
+ 0x00000000, /* DENALI_PHY_719_DATA */
+ 0x00000000, /* DENALI_PHY_720_DATA */
+ 0x00000000, /* DENALI_PHY_721_DATA */
+ 0x00000000, /* DENALI_PHY_722_DATA */
+ 0x00000000, /* DENALI_PHY_723_DATA */
+ 0x00000000, /* DENALI_PHY_724_DATA */
+ 0x00000000, /* DENALI_PHY_725_DATA */
+ 0x00000000, /* DENALI_PHY_726_DATA */
+ 0x00000000, /* DENALI_PHY_727_DATA */
+ 0x00000000, /* DENALI_PHY_728_DATA */
+ 0x00000000, /* DENALI_PHY_729_DATA */
+ 0x00000000, /* DENALI_PHY_730_DATA */
+ 0x00000000, /* DENALI_PHY_731_DATA */
+ 0x00000000, /* DENALI_PHY_732_DATA */
+ 0x00000000, /* DENALI_PHY_733_DATA */
+ 0x00000000, /* DENALI_PHY_734_DATA */
+ 0x00000000, /* DENALI_PHY_735_DATA */
+ 0x00000000, /* DENALI_PHY_736_DATA */
+ 0x00000000, /* DENALI_PHY_737_DATA */
+ 0x00000000, /* DENALI_PHY_738_DATA */
+ 0x00000000, /* DENALI_PHY_739_DATA */
+ 0x00000000, /* DENALI_PHY_740_DATA */
+ 0x00000000, /* DENALI_PHY_741_DATA */
+ 0x00000000, /* DENALI_PHY_742_DATA */
+ 0x00000000, /* DENALI_PHY_743_DATA */
+ 0x00000000, /* DENALI_PHY_744_DATA */
+ 0x00000000, /* DENALI_PHY_745_DATA */
+ 0x00000000, /* DENALI_PHY_746_DATA */
+ 0x00000000, /* DENALI_PHY_747_DATA */
+ 0x00000000, /* DENALI_PHY_748_DATA */
+ 0x00000000, /* DENALI_PHY_749_DATA */
+ 0x00000000, /* DENALI_PHY_750_DATA */
+ 0x00000000, /* DENALI_PHY_751_DATA */
+ 0x00000000, /* DENALI_PHY_752_DATA */
+ 0x00000000, /* DENALI_PHY_753_DATA */
+ 0x00000000, /* DENALI_PHY_754_DATA */
+ 0x00000000, /* DENALI_PHY_755_DATA */
+ 0x00000000, /* DENALI_PHY_756_DATA */
+ 0x00000000, /* DENALI_PHY_757_DATA */
+ 0x00000000, /* DENALI_PHY_758_DATA */
+ 0x00000000, /* DENALI_PHY_759_DATA */
+ 0x00000000, /* DENALI_PHY_760_DATA */
+ 0x00000000, /* DENALI_PHY_761_DATA */
+ 0x00000000, /* DENALI_PHY_762_DATA */
+ 0x00000000, /* DENALI_PHY_763_DATA */
+ 0x00000000, /* DENALI_PHY_764_DATA */
+ 0x00000000, /* DENALI_PHY_765_DATA */
+ 0x00000000, /* DENALI_PHY_766_DATA */
+ 0x00000000, /* DENALI_PHY_767_DATA */
+ 0x00000000, /* DENALI_PHY_768_DATA */
+ 0x00000000, /* DENALI_PHY_769_DATA */
+ 0x00000000, /* DENALI_PHY_770_DATA */
+ 0x00000000, /* DENALI_PHY_771_DATA */
+ 0x00000000, /* DENALI_PHY_772_DATA */
+ 0x00000000, /* DENALI_PHY_773_DATA */
+ 0x00000000, /* DENALI_PHY_774_DATA */
+ 0x00000002, /* DENALI_PHY_775_DATA */
+ 0x00000000, /* DENALI_PHY_776_DATA */
+ 0x00000000, /* DENALI_PHY_777_DATA */
+ 0x00000000, /* DENALI_PHY_778_DATA */
+ 0x00400320, /* DENALI_PHY_779_DATA */
+ 0x00000040, /* DENALI_PHY_780_DATA */
+ 0x00000000, /* DENALI_PHY_781_DATA */
+ 0x00000000, /* DENALI_PHY_782_DATA */
+ 0x00000000, /* DENALI_PHY_783_DATA */
+ 0x01000000, /* DENALI_PHY_784_DATA */
+ 0x00020003, /* DENALI_PHY_785_DATA */
+ 0x00000000, /* DENALI_PHY_786_DATA */
+ 0x00000000, /* DENALI_PHY_787_DATA */
+ 0x00000000, /* DENALI_PHY_788_DATA */
+ 0x0000002a, /* DENALI_PHY_789_DATA */
+ 0x00000015, /* DENALI_PHY_790_DATA */
+ 0x00000015, /* DENALI_PHY_791_DATA */
+ 0x0000002a, /* DENALI_PHY_792_DATA */
+ 0x00000033, /* DENALI_PHY_793_DATA */
+ 0x0000000c, /* DENALI_PHY_794_DATA */
+ 0x0000000c, /* DENALI_PHY_795_DATA */
+ 0x00000033, /* DENALI_PHY_796_DATA */
+ 0x1ee6b16a, /* DENALI_PHY_797_DATA */
+ 0x10000000, /* DENALI_PHY_798_DATA */
+ 0x00000000, /* DENALI_PHY_799_DATA */
+ 0x00030055, /* DENALI_PHY_800_DATA */
+ 0x03000300, /* DENALI_PHY_801_DATA */
+ 0x03000300, /* DENALI_PHY_802_DATA */
+ 0x00000300, /* DENALI_PHY_803_DATA */
+ 0x42080010, /* DENALI_PHY_804_DATA */
+ 0x00000003, /* DENALI_PHY_805_DATA */
+ 0x00000000, /* DENALI_PHY_806_DATA */
+ 0x00000000, /* DENALI_PHY_807_DATA */
+ 0x00000000, /* DENALI_PHY_808_DATA */
+ 0x00000000, /* DENALI_PHY_809_DATA */
+ 0x00000000, /* DENALI_PHY_810_DATA */
+ 0x00000000, /* DENALI_PHY_811_DATA */
+ 0x00000000, /* DENALI_PHY_812_DATA */
+ 0x00000000, /* DENALI_PHY_813_DATA */
+ 0x00000000, /* DENALI_PHY_814_DATA */
+ 0x00000000, /* DENALI_PHY_815_DATA */
+ 0x00000000, /* DENALI_PHY_816_DATA */
+ 0x00000000, /* DENALI_PHY_817_DATA */
+ 0x00000000, /* DENALI_PHY_818_DATA */
+ 0x00000000, /* DENALI_PHY_819_DATA */
+ 0x00000000, /* DENALI_PHY_820_DATA */
+ 0x00000000, /* DENALI_PHY_821_DATA */
+ 0x00000000, /* DENALI_PHY_822_DATA */
+ 0x00000000, /* DENALI_PHY_823_DATA */
+ 0x00000000, /* DENALI_PHY_824_DATA */
+ 0x00000000, /* DENALI_PHY_825_DATA */
+ 0x00000000, /* DENALI_PHY_826_DATA */
+ 0x00000000, /* DENALI_PHY_827_DATA */
+ 0x00000000, /* DENALI_PHY_828_DATA */
+ 0x00000000, /* DENALI_PHY_829_DATA */
+ 0x00000000, /* DENALI_PHY_830_DATA */
+ 0x00000000, /* DENALI_PHY_831_DATA */
+ 0x00000000, /* DENALI_PHY_832_DATA */
+ 0x00000000, /* DENALI_PHY_833_DATA */
+ 0x00000000, /* DENALI_PHY_834_DATA */
+ 0x00000000, /* DENALI_PHY_835_DATA */
+ 0x00000000, /* DENALI_PHY_836_DATA */
+ 0x00000000, /* DENALI_PHY_837_DATA */
+ 0x00000000, /* DENALI_PHY_838_DATA */
+ 0x00000000, /* DENALI_PHY_839_DATA */
+ 0x00000000, /* DENALI_PHY_840_DATA */
+ 0x00000000, /* DENALI_PHY_841_DATA */
+ 0x00000000, /* DENALI_PHY_842_DATA */
+ 0x00000000, /* DENALI_PHY_843_DATA */
+ 0x00000000, /* DENALI_PHY_844_DATA */
+ 0x00000000, /* DENALI_PHY_845_DATA */
+ 0x00000000, /* DENALI_PHY_846_DATA */
+ 0x00000000, /* DENALI_PHY_847_DATA */
+ 0x00000000, /* DENALI_PHY_848_DATA */
+ 0x00000000, /* DENALI_PHY_849_DATA */
+ 0x00000000, /* DENALI_PHY_850_DATA */
+ 0x00000000, /* DENALI_PHY_851_DATA */
+ 0x00000000, /* DENALI_PHY_852_DATA */
+ 0x00000000, /* DENALI_PHY_853_DATA */
+ 0x00000000, /* DENALI_PHY_854_DATA */
+ 0x00000000, /* DENALI_PHY_855_DATA */
+ 0x00000000, /* DENALI_PHY_856_DATA */
+ 0x00000000, /* DENALI_PHY_857_DATA */
+ 0x00000000, /* DENALI_PHY_858_DATA */
+ 0x00000000, /* DENALI_PHY_859_DATA */
+ 0x00000000, /* DENALI_PHY_860_DATA */
+ 0x00000000, /* DENALI_PHY_861_DATA */
+ 0x00000000, /* DENALI_PHY_862_DATA */
+ 0x00000000, /* DENALI_PHY_863_DATA */
+ 0x00000000, /* DENALI_PHY_864_DATA */
+ 0x00000000, /* DENALI_PHY_865_DATA */
+ 0x00000000, /* DENALI_PHY_866_DATA */
+ 0x00000000, /* DENALI_PHY_867_DATA */
+ 0x00000000, /* DENALI_PHY_868_DATA */
+ 0x00000000, /* DENALI_PHY_869_DATA */
+ 0x00000000, /* DENALI_PHY_870_DATA */
+ 0x00000000, /* DENALI_PHY_871_DATA */
+ 0x00000000, /* DENALI_PHY_872_DATA */
+ 0x00000000, /* DENALI_PHY_873_DATA */
+ 0x00000000, /* DENALI_PHY_874_DATA */
+ 0x00000000, /* DENALI_PHY_875_DATA */
+ 0x00000000, /* DENALI_PHY_876_DATA */
+ 0x00000000, /* DENALI_PHY_877_DATA */
+ 0x00000000, /* DENALI_PHY_878_DATA */
+ 0x00000000, /* DENALI_PHY_879_DATA */
+ 0x00000000, /* DENALI_PHY_880_DATA */
+ 0x00000000, /* DENALI_PHY_881_DATA */
+ 0x00000000, /* DENALI_PHY_882_DATA */
+ 0x00000000, /* DENALI_PHY_883_DATA */
+ 0x00000000, /* DENALI_PHY_884_DATA */
+ 0x00000000, /* DENALI_PHY_885_DATA */
+ 0x00000000, /* DENALI_PHY_886_DATA */
+ 0x00000000, /* DENALI_PHY_887_DATA */
+ 0x00000000, /* DENALI_PHY_888_DATA */
+ 0x00000000, /* DENALI_PHY_889_DATA */
+ 0x00000000, /* DENALI_PHY_890_DATA */
+ 0x00000000, /* DENALI_PHY_891_DATA */
+ 0x00000000, /* DENALI_PHY_892_DATA */
+ 0x00000000, /* DENALI_PHY_893_DATA */
+ 0x00000000, /* DENALI_PHY_894_DATA */
+ 0x00000000, /* DENALI_PHY_895_DATA */
+ 0x00000000, /* DENALI_PHY_896_DATA */
+ 0x00000000, /* DENALI_PHY_897_DATA */
+ 0x00000005, /* DENALI_PHY_898_DATA */
+ 0x04000f01, /* DENALI_PHY_899_DATA */
+ 0x00020040, /* DENALI_PHY_900_DATA */
+ 0x00020055, /* DENALI_PHY_901_DATA */
+ 0x00000000, /* DENALI_PHY_902_DATA */
+ 0x00000000, /* DENALI_PHY_903_DATA */
+ 0x00000000, /* DENALI_PHY_904_DATA */
+ 0x00000050, /* DENALI_PHY_905_DATA */
+ 0x00000000, /* DENALI_PHY_906_DATA */
+ 0x01010100, /* DENALI_PHY_907_DATA */
+ 0x00000600, /* DENALI_PHY_908_DATA */
+ 0x00000000, /* DENALI_PHY_909_DATA */
+ 0x00006400, /* DENALI_PHY_910_DATA */
+ 0x03221302, /* DENALI_PHY_911_DATA */
+ 0x00000000, /* DENALI_PHY_912_DATA */
+ 0x000d1f01, /* DENALI_PHY_913_DATA */
+ 0x0d1f0d1f, /* DENALI_PHY_914_DATA */
+ 0x0d1f0d1f, /* DENALI_PHY_915_DATA */
+ 0x00030003, /* DENALI_PHY_916_DATA */
+ 0x03000300, /* DENALI_PHY_917_DATA */
+ 0x00000300, /* DENALI_PHY_918_DATA */
+ 0x03221302, /* DENALI_PHY_919_DATA */
+ 0x00000000, /* DENALI_PHY_920_DATA */
+ 0x00000000, /* DENALI_PHY_921_DATA */
+ 0x01020000, /* DENALI_PHY_922_DATA */
+ 0x00000001, /* DENALI_PHY_923_DATA */
+ 0x00000411, /* DENALI_PHY_924_DATA */
+ 0x00000411, /* DENALI_PHY_925_DATA */
+ 0x00000040, /* DENALI_PHY_926_DATA */
+ 0x00000040, /* DENALI_PHY_927_DATA */
+ 0x00000411, /* DENALI_PHY_928_DATA */
+ 0x00000411, /* DENALI_PHY_929_DATA */
+ 0x00004410, /* DENALI_PHY_930_DATA */
+ 0x00004410, /* DENALI_PHY_931_DATA */
+ 0x00004410, /* DENALI_PHY_932_DATA */
+ 0x00004410, /* DENALI_PHY_933_DATA */
+ 0x00004410, /* DENALI_PHY_934_DATA */
+ 0x00000411, /* DENALI_PHY_935_DATA */
+ 0x00004410, /* DENALI_PHY_936_DATA */
+ 0x00000411, /* DENALI_PHY_937_DATA */
+ 0x00004410, /* DENALI_PHY_938_DATA */
+ 0x00000411, /* DENALI_PHY_939_DATA */
+ 0x00004410, /* DENALI_PHY_940_DATA */
+ 0x00000000, /* DENALI_PHY_941_DATA */
+ 0x00000000, /* DENALI_PHY_942_DATA */
+ 0x00000000, /* DENALI_PHY_943_DATA */
+ 0x64000000, /* DENALI_PHY_944_DATA */
+ 0x00000000, /* DENALI_PHY_945_DATA */
+ 0x00000000, /* DENALI_PHY_946_DATA */
+ 0x00000408, /* DENALI_PHY_947_DATA */
+ 0x00000000, /* DENALI_PHY_948_DATA */
+ 0x00000000, /* DENALI_PHY_949_DATA */
+ 0x00000000, /* DENALI_PHY_950_DATA */
+ 0x00000000, /* DENALI_PHY_951_DATA */
+ 0x00000000, /* DENALI_PHY_952_DATA */
+ 0x00000000, /* DENALI_PHY_953_DATA */
+ 0xe4000000, /* DENALI_PHY_954_DATA */
+ 0x00000000, /* DENALI_PHY_955_DATA */
+ 0x00000000, /* DENALI_PHY_956_DATA */
+ 0x01010000, /* DENALI_PHY_957_DATA */
+ 0x00000000 /* DENALI_PHY_958_DATA */
+ }
+ },
+},
diff --git a/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc b/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc
new file mode 100644
index 0000000..d8ae335
--- /dev/null
+++ b/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc
@@ -0,0 +1,1570 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd.
+ * (C) Copyright 2019 Amarula Solutions
+ */
+
+{
+ {
+ {
+ {
+ .rank = 0x2,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x1,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF,
+ .ddrconfig = 1,
+ },
+ {
+ .ddrtiminga0 = 0x80241d22,
+ .ddrtimingb0 = 0x15050f08,
+ .ddrtimingc0 = {
+ 0x00000602,
+ },
+ .devtodev0 = 0x00002122,
+ .ddrmode = {
+ 0x0000004c,
+ },
+ .agingx0 = 0x00000000,
+ }
+ },
+ {
+ {
+ .rank = 0x2,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x1,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF,
+ .ddrconfig = 1,
+ },
+ {
+ .ddrtiminga0 = 0x80241d22,
+ .ddrtimingb0 = 0x15050f08,
+ .ddrtimingc0 = {
+ 0x00000602,
+ },
+ .devtodev0 = 0x00002122,
+ .ddrmode = {
+ 0x0000004c,
+ },
+ .agingx0 = 0x00000000,
+ }
+ }
+ },
+ {
+ .ddr_freq = 800 * MHz,
+ .dramtype = LPDDR4,
+ .num_channels = 2,
+ .stride = 13,
+ .odt = 1,
+ },
+ {
+ {
+ 0x00000b00, /* DENALI_CTL_00_DATA */
+ 0x00000000, /* DENALI_CTL_01_DATA */
+ 0x00000000, /* DENALI_CTL_02_DATA */
+ 0x00000000, /* DENALI_CTL_03_DATA */
+ 0x00000000, /* DENALI_CTL_04_DATA */
+ 0x00013880, /* DENALI_CTL_05_DATA */
+ 0x000c3500, /* DENALI_CTL_06_DATA */
+ 0x00000005, /* DENALI_CTL_07_DATA */
+ 0x00000320, /* DENALI_CTL_08_DATA */
+ 0x00027100, /* DENALI_CTL_09_DATA */
+ 0x00186a00, /* DENALI_CTL_10_DATA */
+ 0x00000005, /* DENALI_CTL_11_DATA */
+ 0x00000640, /* DENALI_CTL_12_DATA */
+ 0x00002710, /* DENALI_CTL_13_DATA */
+ 0x000186a0, /* DENALI_CTL_14_DATA */
+ 0x00000005, /* DENALI_CTL_15_DATA */
+ 0x01000064, /* DENALI_CTL_16_DATA */
+ 0x00000000, /* DENALI_CTL_17_DATA */
+ 0x02020101, /* DENALI_CTL_18_DATA */
+ 0x00000102, /* DENALI_CTL_19_DATA */
+ 0x00000050, /* DENALI_CTL_20_DATA */
+ 0x000000c8, /* DENALI_CTL_21_DATA */
+ 0x00000000, /* DENALI_CTL_22_DATA */
+ 0x06140000, /* DENALI_CTL_23_DATA */
+ 0x00081c00, /* DENALI_CTL_24_DATA */
+ 0x0400040c, /* DENALI_CTL_25_DATA */
+ 0x19042008, /* DENALI_CTL_26_DATA */
+ 0x10080a11, /* DENALI_CTL_27_DATA */
+ 0x22310800, /* DENALI_CTL_28_DATA */
+ 0x00200f0a, /* DENALI_CTL_29_DATA */
+ 0x0a030704, /* DENALI_CTL_30_DATA */
+ 0x08000204, /* DENALI_CTL_31_DATA */
+ 0x00000a0a, /* DENALI_CTL_32_DATA */
+ 0x04006db0, /* DENALI_CTL_33_DATA */
+ 0x0a0a0804, /* DENALI_CTL_34_DATA */
+ 0x0600db60, /* DENALI_CTL_35_DATA */
+ 0x0a0a0806, /* DENALI_CTL_36_DATA */
+ 0x04000db6, /* DENALI_CTL_37_DATA */
+ 0x02030404, /* DENALI_CTL_38_DATA */
+ 0x0f0a0800, /* DENALI_CTL_39_DATA */
+ 0x08040411, /* DENALI_CTL_40_DATA */
+ 0x1400640a, /* DENALI_CTL_41_DATA */
+ 0x02010a0a, /* DENALI_CTL_42_DATA */
+ 0x00010001, /* DENALI_CTL_43_DATA */
+ 0x04082012, /* DENALI_CTL_44_DATA */
+ 0x00041109, /* DENALI_CTL_45_DATA */
+ 0x00000000, /* DENALI_CTL_46_DATA */
+ 0x03010000, /* DENALI_CTL_47_DATA */
+ 0x06100034, /* DENALI_CTL_48_DATA */
+ 0x0c280068, /* DENALI_CTL_49_DATA */
+ 0x00bb0007, /* DENALI_CTL_50_DATA */
+ 0x00000000, /* DENALI_CTL_51_DATA */
+ 0x00060003, /* DENALI_CTL_52_DATA */
+ 0x000a0003, /* DENALI_CTL_53_DATA */
+ 0x000a0014, /* DENALI_CTL_54_DATA */
+ 0x01000000, /* DENALI_CTL_55_DATA */
+ 0x030a0000, /* DENALI_CTL_56_DATA */
+ 0x0c000002, /* DENALI_CTL_57_DATA */
+ 0x00000103, /* DENALI_CTL_58_DATA */
+ 0x0003030a, /* DENALI_CTL_59_DATA */
+ 0x00060037, /* DENALI_CTL_60_DATA */
+ 0x0003006e, /* DENALI_CTL_61_DATA */
+ 0x05050007, /* DENALI_CTL_62_DATA */
+ 0x03020605, /* DENALI_CTL_63_DATA */
+ 0x06050301, /* DENALI_CTL_64_DATA */
+ 0x06020c05, /* DENALI_CTL_65_DATA */
+ 0x05050302, /* DENALI_CTL_66_DATA */
+ 0x03020305, /* DENALI_CTL_67_DATA */
+ 0x00000301, /* DENALI_CTL_68_DATA */
+ 0x00000301, /* DENALI_CTL_69_DATA */
+ 0x00000001, /* DENALI_CTL_70_DATA */
+ 0x00000000, /* DENALI_CTL_71_DATA */
+ 0x00000000, /* DENALI_CTL_72_DATA */
+ 0x01000000, /* DENALI_CTL_73_DATA */
+ 0x80104002, /* DENALI_CTL_74_DATA */
+ 0x00040003, /* DENALI_CTL_75_DATA */
+ 0x00040005, /* DENALI_CTL_76_DATA */
+ 0x00030000, /* DENALI_CTL_77_DATA */
+ 0x00050004, /* DENALI_CTL_78_DATA */
+ 0x00000004, /* DENALI_CTL_79_DATA */
+ 0x00040003, /* DENALI_CTL_80_DATA */
+ 0x00040005, /* DENALI_CTL_81_DATA */
+ 0x18400000, /* DENALI_CTL_82_DATA */
+ 0x00000c20, /* DENALI_CTL_83_DATA */
+ 0x185030a0, /* DENALI_CTL_84_DATA */
+ 0x02ec0000, /* DENALI_CTL_85_DATA */
+ 0x00000176, /* DENALI_CTL_86_DATA */
+ 0x00000000, /* DENALI_CTL_87_DATA */
+ 0x00000000, /* DENALI_CTL_88_DATA */
+ 0x00000000, /* DENALI_CTL_89_DATA */
+ 0x00000000, /* DENALI_CTL_90_DATA */
+ 0x00000000, /* DENALI_CTL_91_DATA */
+ 0x06030300, /* DENALI_CTL_92_DATA */
+ 0x00030303, /* DENALI_CTL_93_DATA */
+ 0x02030200, /* DENALI_CTL_94_DATA */
+ 0x00040703, /* DENALI_CTL_95_DATA */
+ 0x03020302, /* DENALI_CTL_96_DATA */
+ 0x02000407, /* DENALI_CTL_97_DATA */
+ 0x07030203, /* DENALI_CTL_98_DATA */
+ 0x00030f04, /* DENALI_CTL_99_DATA */
+ 0x00070004, /* DENALI_CTL_100_DATA */
+ 0x00000000, /* DENALI_CTL_101_DATA */
+ 0x00000000, /* DENALI_CTL_102_DATA */
+ 0x00000000, /* DENALI_CTL_103_DATA */
+ 0x00000000, /* DENALI_CTL_104_DATA */
+ 0x00000000, /* DENALI_CTL_105_DATA */
+ 0x00000000, /* DENALI_CTL_106_DATA */
+ 0x00000000, /* DENALI_CTL_107_DATA */
+ 0x00010000, /* DENALI_CTL_108_DATA */
+ 0x20040020, /* DENALI_CTL_109_DATA */
+ 0x00200400, /* DENALI_CTL_110_DATA */
+ 0x01000400, /* DENALI_CTL_111_DATA */
+ 0x00000b80, /* DENALI_CTL_112_DATA */
+ 0x00000000, /* DENALI_CTL_113_DATA */
+ 0x00000001, /* DENALI_CTL_114_DATA */
+ 0x00000002, /* DENALI_CTL_115_DATA */
+ 0x0000000e, /* DENALI_CTL_116_DATA */
+ 0x00000000, /* DENALI_CTL_117_DATA */
+ 0x00000000, /* DENALI_CTL_118_DATA */
+ 0x00000000, /* DENALI_CTL_119_DATA */
+ 0x00000000, /* DENALI_CTL_120_DATA */
+ 0x00000000, /* DENALI_CTL_121_DATA */
+ 0x00500000, /* DENALI_CTL_122_DATA */
+ 0x00640028, /* DENALI_CTL_123_DATA */
+ 0x00640404, /* DENALI_CTL_124_DATA */
+ 0x005000a0, /* DENALI_CTL_125_DATA */
+ 0x060600c8, /* DENALI_CTL_126_DATA */
+ 0x000a00c8, /* DENALI_CTL_127_DATA */
+ 0x000d0005, /* DENALI_CTL_128_DATA */
+ 0x000d0404, /* DENALI_CTL_129_DATA */
+ 0x00000000, /* DENALI_CTL_130_DATA */
+ 0x00000000, /* DENALI_CTL_131_DATA */
+ 0x00000000, /* DENALI_CTL_132_DATA */
+ 0x001400a3, /* DENALI_CTL_133_DATA */
+ 0x00e30009, /* DENALI_CTL_134_DATA */
+ 0x00120024, /* DENALI_CTL_135_DATA */
+ 0x00040063, /* DENALI_CTL_136_DATA */
+ 0x00000000, /* DENALI_CTL_137_DATA */
+ 0x00310031, /* DENALI_CTL_138_DATA */
+ 0x00000031, /* DENALI_CTL_139_DATA */
+ 0x004d0000, /* DENALI_CTL_140_DATA */
+ 0x004d004d, /* DENALI_CTL_141_DATA */
+ 0x004d0000, /* DENALI_CTL_142_DATA */
+ 0x004d004d, /* DENALI_CTL_143_DATA */
+ 0x00010101, /* DENALI_CTL_144_DATA */
+ 0x00000000, /* DENALI_CTL_145_DATA */
+ 0x00000000, /* DENALI_CTL_146_DATA */
+ 0x001400a3, /* DENALI_CTL_147_DATA */
+ 0x00e30009, /* DENALI_CTL_148_DATA */
+ 0x00120024, /* DENALI_CTL_149_DATA */
+ 0x00040063, /* DENALI_CTL_150_DATA */
+ 0x00000000, /* DENALI_CTL_151_DATA */
+ 0x00310031, /* DENALI_CTL_152_DATA */
+ 0x00000031, /* DENALI_CTL_153_DATA */
+ 0x004d0000, /* DENALI_CTL_154_DATA */
+ 0x004d004d, /* DENALI_CTL_155_DATA */
+ 0x004d0000, /* DENALI_CTL_156_DATA */
+ 0x004d004d, /* DENALI_CTL_157_DATA */
+ 0x00010101, /* DENALI_CTL_158_DATA */
+ 0x00000000, /* DENALI_CTL_159_DATA */
+ 0x00000000, /* DENALI_CTL_160_DATA */
+ 0x00000000, /* DENALI_CTL_161_DATA */
+ 0x00000001, /* DENALI_CTL_162_DATA */
+ 0x00000000, /* DENALI_CTL_163_DATA */
+ 0x18151100, /* DENALI_CTL_164_DATA */
+ 0x0000000c, /* DENALI_CTL_165_DATA */
+ 0x00000000, /* DENALI_CTL_166_DATA */
+ 0x00000000, /* DENALI_CTL_167_DATA */
+ 0x00000000, /* DENALI_CTL_168_DATA */
+ 0x00000000, /* DENALI_CTL_169_DATA */
+ 0x00000000, /* DENALI_CTL_170_DATA */
+ 0x00000000, /* DENALI_CTL_171_DATA */
+ 0x00000000, /* DENALI_CTL_172_DATA */
+ 0x00000000, /* DENALI_CTL_173_DATA */
+ 0x00000000, /* DENALI_CTL_174_DATA */
+ 0x00000000, /* DENALI_CTL_175_DATA */
+ 0x00000000, /* DENALI_CTL_176_DATA */
+ 0x00000000, /* DENALI_CTL_177_DATA */
+ 0x00000000, /* DENALI_CTL_178_DATA */
+ 0x00020003, /* DENALI_CTL_179_DATA */
+ 0x00400100, /* DENALI_CTL_180_DATA */
+ 0x000c0190, /* DENALI_CTL_181_DATA */
+ 0x01000200, /* DENALI_CTL_182_DATA */
+ 0x03200040, /* DENALI_CTL_183_DATA */
+ 0x00020018, /* DENALI_CTL_184_DATA */
+ 0x00400100, /* DENALI_CTL_185_DATA */
+ 0x00080032, /* DENALI_CTL_186_DATA */
+ 0x00140000, /* DENALI_CTL_187_DATA */
+ 0x00030028, /* DENALI_CTL_188_DATA */
+ 0x01010100, /* DENALI_CTL_189_DATA */
+ 0x02000202, /* DENALI_CTL_190_DATA */
+ 0x0b000002, /* DENALI_CTL_191_DATA */
+ 0x01000f0f, /* DENALI_CTL_192_DATA */
+ 0x00000000, /* DENALI_CTL_193_DATA */
+ 0x00000000, /* DENALI_CTL_194_DATA */
+ 0x00010003, /* DENALI_CTL_195_DATA */
+ 0x00000c03, /* DENALI_CTL_196_DATA */
+ 0x00040101, /* DENALI_CTL_197_DATA */
+ 0x04010100, /* DENALI_CTL_198_DATA */
+ 0x01000000, /* DENALI_CTL_199_DATA */
+ 0x02010000, /* DENALI_CTL_200_DATA */
+ 0x00000001, /* DENALI_CTL_201_DATA */
+ 0x00000000, /* DENALI_CTL_202_DATA */
+ 0x00000000, /* DENALI_CTL_203_DATA */
+ 0x00000000, /* DENALI_CTL_204_DATA */
+ 0x00000000, /* DENALI_CTL_205_DATA */
+ 0x00000000, /* DENALI_CTL_206_DATA */
+ 0x00000000, /* DENALI_CTL_207_DATA */
+ 0x00000000, /* DENALI_CTL_208_DATA */
+ 0x00000000, /* DENALI_CTL_209_DATA */
+ 0x00000000, /* DENALI_CTL_210_DATA */
+ 0x00010000, /* DENALI_CTL_211_DATA */
+ 0x00000001, /* DENALI_CTL_212_DATA */
+ 0x01010001, /* DENALI_CTL_213_DATA */
+ 0x05040001, /* DENALI_CTL_214_DATA */
+ 0x040a0703, /* DENALI_CTL_215_DATA */
+ 0x02080808, /* DENALI_CTL_216_DATA */
+ 0x020e000a, /* DENALI_CTL_217_DATA */
+ 0x020f010b, /* DENALI_CTL_218_DATA */
+ 0x000d0008, /* DENALI_CTL_219_DATA */
+ 0x00080b0a, /* DENALI_CTL_220_DATA */
+ 0x03000200, /* DENALI_CTL_221_DATA */
+ 0x00000100, /* DENALI_CTL_222_DATA */
+ 0x00000000, /* DENALI_CTL_223_DATA */
+ 0x00000000, /* DENALI_CTL_224_DATA */
+ 0x0d000001, /* DENALI_CTL_225_DATA */
+ 0x00000028, /* DENALI_CTL_226_DATA */
+ 0x00010000, /* DENALI_CTL_227_DATA */
+ 0x00000003, /* DENALI_CTL_228_DATA */
+ 0x00000000, /* DENALI_CTL_229_DATA */
+ 0x00000000, /* DENALI_CTL_230_DATA */
+ 0x00000000, /* DENALI_CTL_231_DATA */
+ 0x00000000, /* DENALI_CTL_232_DATA */
+ 0x00000000, /* DENALI_CTL_233_DATA */
+ 0x00000000, /* DENALI_CTL_234_DATA */
+ 0x00000000, /* DENALI_CTL_235_DATA */
+ 0x00000000, /* DENALI_CTL_236_DATA */
+ 0x00010100, /* DENALI_CTL_237_DATA */
+ 0x01000000, /* DENALI_CTL_238_DATA */
+ 0x00000001, /* DENALI_CTL_239_DATA */
+ 0x00000303, /* DENALI_CTL_240_DATA */
+ 0x00000000, /* DENALI_CTL_241_DATA */
+ 0x00000000, /* DENALI_CTL_242_DATA */
+ 0x00000000, /* DENALI_CTL_243_DATA */
+ 0x00000000, /* DENALI_CTL_244_DATA */
+ 0x00000000, /* DENALI_CTL_245_DATA */
+ 0x00000000, /* DENALI_CTL_246_DATA */
+ 0x00000000, /* DENALI_CTL_247_DATA */
+ 0x00000000, /* DENALI_CTL_248_DATA */
+ 0x00000000, /* DENALI_CTL_249_DATA */
+ 0x00000000, /* DENALI_CTL_250_DATA */
+ 0x00000000, /* DENALI_CTL_251_DATA */
+ 0x00000000, /* DENALI_CTL_252_DATA */
+ 0x00000000, /* DENALI_CTL_253_DATA */
+ 0x00000000, /* DENALI_CTL_254_DATA */
+ 0x00000000, /* DENALI_CTL_255_DATA */
+ 0x000556aa, /* DENALI_CTL_256_DATA */
+ 0x000aaaaa, /* DENALI_CTL_257_DATA */
+ 0x000aa955, /* DENALI_CTL_258_DATA */
+ 0x00055555, /* DENALI_CTL_259_DATA */
+ 0x000b3133, /* DENALI_CTL_260_DATA */
+ 0x0004cd33, /* DENALI_CTL_261_DATA */
+ 0x0004cecc, /* DENALI_CTL_262_DATA */
+ 0x000b32cc, /* DENALI_CTL_263_DATA */
+ 0x00010300, /* DENALI_CTL_264_DATA */
+ 0x03000100, /* DENALI_CTL_265_DATA */
+ 0x00000000, /* DENALI_CTL_266_DATA */
+ 0x00000000, /* DENALI_CTL_267_DATA */
+ 0x00000000, /* DENALI_CTL_268_DATA */
+ 0x00000000, /* DENALI_CTL_269_DATA */
+ 0x00000000, /* DENALI_CTL_270_DATA */
+ 0x00000000, /* DENALI_CTL_271_DATA */
+ 0x00000000, /* DENALI_CTL_272_DATA */
+ 0x00000000, /* DENALI_CTL_273_DATA */
+ 0x00ffff00, /* DENALI_CTL_274_DATA */
+ 0x1a160000, /* DENALI_CTL_275_DATA */
+ 0x08000012, /* DENALI_CTL_276_DATA */
+ 0x00000c20, /* DENALI_CTL_277_DATA */
+ 0x00000200, /* DENALI_CTL_278_DATA */
+ 0x00000200, /* DENALI_CTL_279_DATA */
+ 0x00000200, /* DENALI_CTL_280_DATA */
+ 0x00000200, /* DENALI_CTL_281_DATA */
+ 0x00000c20, /* DENALI_CTL_282_DATA */
+ 0x00007940, /* DENALI_CTL_283_DATA */
+ 0x18500409, /* DENALI_CTL_284_DATA */
+ 0x00000200, /* DENALI_CTL_285_DATA */
+ 0x00000200, /* DENALI_CTL_286_DATA */
+ 0x00000200, /* DENALI_CTL_287_DATA */
+ 0x00000200, /* DENALI_CTL_288_DATA */
+ 0x00001850, /* DENALI_CTL_289_DATA */
+ 0x0000f320, /* DENALI_CTL_290_DATA */
+ 0x0176060c, /* DENALI_CTL_291_DATA */
+ 0x00000200, /* DENALI_CTL_292_DATA */
+ 0x00000200, /* DENALI_CTL_293_DATA */
+ 0x00000200, /* DENALI_CTL_294_DATA */
+ 0x00000200, /* DENALI_CTL_295_DATA */
+ 0x00000176, /* DENALI_CTL_296_DATA */
+ 0x00000e9c, /* DENALI_CTL_297_DATA */
+ 0x02020205, /* DENALI_CTL_298_DATA */
+ 0x03030202, /* DENALI_CTL_299_DATA */
+ 0x00000018, /* DENALI_CTL_300_DATA */
+ 0x00000000, /* DENALI_CTL_301_DATA */
+ 0x00000000, /* DENALI_CTL_302_DATA */
+ 0x00001403, /* DENALI_CTL_303_DATA */
+ 0x00000000, /* DENALI_CTL_304_DATA */
+ 0x00000000, /* DENALI_CTL_305_DATA */
+ 0x00000000, /* DENALI_CTL_306_DATA */
+ 0x00030000, /* DENALI_CTL_307_DATA */
+ 0x000a001c, /* DENALI_CTL_308_DATA */
+ 0x000e0020, /* DENALI_CTL_309_DATA */
+ 0x00060018, /* DENALI_CTL_310_DATA */
+ 0x00000000, /* DENALI_CTL_311_DATA */
+ 0x00000000, /* DENALI_CTL_312_DATA */
+ 0x02000000, /* DENALI_CTL_313_DATA */
+ 0x00090305, /* DENALI_CTL_314_DATA */
+ 0x00050101, /* DENALI_CTL_315_DATA */
+ 0x00000000, /* DENALI_CTL_316_DATA */
+ 0x00000000, /* DENALI_CTL_317_DATA */
+ 0x00000000, /* DENALI_CTL_318_DATA */
+ 0x00000000, /* DENALI_CTL_319_DATA */
+ 0x00000000, /* DENALI_CTL_320_DATA */
+ 0x00000000, /* DENALI_CTL_321_DATA */
+ 0x00000000, /* DENALI_CTL_322_DATA */
+ 0x00000000, /* DENALI_CTL_323_DATA */
+ 0x01000001, /* DENALI_CTL_324_DATA */
+ 0x01010101, /* DENALI_CTL_325_DATA */
+ 0x01000101, /* DENALI_CTL_326_DATA */
+ 0x01000100, /* DENALI_CTL_327_DATA */
+ 0x00010001, /* DENALI_CTL_328_DATA */
+ 0x00010002, /* DENALI_CTL_329_DATA */
+ 0x00020100, /* DENALI_CTL_330_DATA */
+ 0x00000002 /* DENALI_CTL_331_DATA */
+ }
+ },
+ {
+ {
+ 0x00000b00, /* DENALI_PI_00_DATA */
+ 0x00000000, /* DENALI_PI_01_DATA */
+ 0x000002ec, /* DENALI_PI_02_DATA */
+ 0x00000176, /* DENALI_PI_03_DATA */
+ 0x000030a0, /* DENALI_PI_04_DATA */
+ 0x00001850, /* DENALI_PI_05_DATA */
+ 0x00001840, /* DENALI_PI_06_DATA */
+ 0x01760c20, /* DENALI_PI_07_DATA */
+ 0x00000200, /* DENALI_PI_08_DATA */
+ 0x00000200, /* DENALI_PI_09_DATA */
+ 0x00000200, /* DENALI_PI_10_DATA */
+ 0x00000200, /* DENALI_PI_11_DATA */
+ 0x00001850, /* DENALI_PI_12_DATA */
+ 0x00000200, /* DENALI_PI_13_DATA */
+ 0x00000200, /* DENALI_PI_14_DATA */
+ 0x00000200, /* DENALI_PI_15_DATA */
+ 0x00000200, /* DENALI_PI_16_DATA */
+ 0x00000c20, /* DENALI_PI_17_DATA */
+ 0x00000200, /* DENALI_PI_18_DATA */
+ 0x00000200, /* DENALI_PI_19_DATA */
+ 0x00000200, /* DENALI_PI_20_DATA */
+ 0x00000200, /* DENALI_PI_21_DATA */
+ 0x00010000, /* DENALI_PI_22_DATA */
+ 0x00000007, /* DENALI_PI_23_DATA */
+ 0x01000001, /* DENALI_PI_24_DATA */
+ 0x00000000, /* DENALI_PI_25_DATA */
+ 0x3fffffff, /* DENALI_PI_26_DATA */
+ 0x00000000, /* DENALI_PI_27_DATA */
+ 0x00000000, /* DENALI_PI_28_DATA */
+ 0x00000000, /* DENALI_PI_29_DATA */
+ 0x00000000, /* DENALI_PI_30_DATA */
+ 0x00000000, /* DENALI_PI_31_DATA */
+ 0x00000000, /* DENALI_PI_32_DATA */
+ 0x00000000, /* DENALI_PI_33_DATA */
+ 0x00000000, /* DENALI_PI_34_DATA */
+ 0x00000000, /* DENALI_PI_35_DATA */
+ 0x00000000, /* DENALI_PI_36_DATA */
+ 0x00000000, /* DENALI_PI_37_DATA */
+ 0x00000000, /* DENALI_PI_38_DATA */
+ 0x00000000, /* DENALI_PI_39_DATA */
+ 0x00000000, /* DENALI_PI_40_DATA */
+ 0x0f000101, /* DENALI_PI_41_DATA */
+ 0x082b3223, /* DENALI_PI_42_DATA */
+ 0x080c0004, /* DENALI_PI_43_DATA */
+ 0x00061c00, /* DENALI_PI_44_DATA */
+ 0x00000214, /* DENALI_PI_45_DATA */
+ 0x00bb0007, /* DENALI_PI_46_DATA */
+ 0x0c280068, /* DENALI_PI_47_DATA */
+ 0x06100034, /* DENALI_PI_48_DATA */
+ 0x00000500, /* DENALI_PI_49_DATA */
+ 0x00000000, /* DENALI_PI_50_DATA */
+ 0x00000000, /* DENALI_PI_51_DATA */
+ 0x00000000, /* DENALI_PI_52_DATA */
+ 0x00000000, /* DENALI_PI_53_DATA */
+ 0x00000000, /* DENALI_PI_54_DATA */
+ 0x00000000, /* DENALI_PI_55_DATA */
+ 0x00000000, /* DENALI_PI_56_DATA */
+ 0x00000000, /* DENALI_PI_57_DATA */
+ 0x04040100, /* DENALI_PI_58_DATA */
+ 0x0a000004, /* DENALI_PI_59_DATA */
+ 0x00000128, /* DENALI_PI_60_DATA */
+ 0x00000000, /* DENALI_PI_61_DATA */
+ 0x0003000f, /* DENALI_PI_62_DATA */
+ 0x00000018, /* DENALI_PI_63_DATA */
+ 0x00000000, /* DENALI_PI_64_DATA */
+ 0x00000000, /* DENALI_PI_65_DATA */
+ 0x00060002, /* DENALI_PI_66_DATA */
+ 0x00010001, /* DENALI_PI_67_DATA */
+ 0x00000101, /* DENALI_PI_68_DATA */
+ 0x00020001, /* DENALI_PI_69_DATA */
+ 0x00080004, /* DENALI_PI_70_DATA */
+ 0x00000000, /* DENALI_PI_71_DATA */
+ 0x05030000, /* DENALI_PI_72_DATA */
+ 0x070a0404, /* DENALI_PI_73_DATA */
+ 0x00000000, /* DENALI_PI_74_DATA */
+ 0x00000000, /* DENALI_PI_75_DATA */
+ 0x00000000, /* DENALI_PI_76_DATA */
+ 0x000f0f00, /* DENALI_PI_77_DATA */
+ 0x0000001e, /* DENALI_PI_78_DATA */
+ 0x00000000, /* DENALI_PI_79_DATA */
+ 0x01010300, /* DENALI_PI_80_DATA */
+ 0x00000000, /* DENALI_PI_81_DATA */
+ 0x00000000, /* DENALI_PI_82_DATA */
+ 0x01000000, /* DENALI_PI_83_DATA */
+ 0x00000101, /* DENALI_PI_84_DATA */
+ 0x55555a5a, /* DENALI_PI_85_DATA */
+ 0x55555a5a, /* DENALI_PI_86_DATA */
+ 0x55555a5a, /* DENALI_PI_87_DATA */
+ 0x55555a5a, /* DENALI_PI_88_DATA */
+ 0x0c050001, /* DENALI_PI_89_DATA */
+ 0x06020009, /* DENALI_PI_90_DATA */
+ 0x00010004, /* DENALI_PI_91_DATA */
+ 0x00000203, /* DENALI_PI_92_DATA */
+ 0x00030000, /* DENALI_PI_93_DATA */
+ 0x170f0000, /* DENALI_PI_94_DATA */
+ 0x00060018, /* DENALI_PI_95_DATA */
+ 0x000e0020, /* DENALI_PI_96_DATA */
+ 0x000a001c, /* DENALI_PI_97_DATA */
+ 0x00000000, /* DENALI_PI_98_DATA */
+ 0x00000000, /* DENALI_PI_99_DATA */
+ 0x00000100, /* DENALI_PI_100_DATA */
+ 0x140a0000, /* DENALI_PI_101_DATA */
+ 0x000d010a, /* DENALI_PI_102_DATA */
+ 0x0100c802, /* DENALI_PI_103_DATA */
+ 0x010a0064, /* DENALI_PI_104_DATA */
+ 0x000e0100, /* DENALI_PI_105_DATA */
+ 0x0100000e, /* DENALI_PI_106_DATA */
+ 0x00c900c9, /* DENALI_PI_107_DATA */
+ 0x00650100, /* DENALI_PI_108_DATA */
+ 0x1e1a0065, /* DENALI_PI_109_DATA */
+ 0x10010204, /* DENALI_PI_110_DATA */
+ 0x06070605, /* DENALI_PI_111_DATA */
+ 0x20000202, /* DENALI_PI_112_DATA */
+ 0x00201000, /* DENALI_PI_113_DATA */
+ 0x00201000, /* DENALI_PI_114_DATA */
+ 0x04041000, /* DENALI_PI_115_DATA */
+ 0x10020100, /* DENALI_PI_116_DATA */
+ 0x0003010c, /* DENALI_PI_117_DATA */
+ 0x004b004a, /* DENALI_PI_118_DATA */
+ 0x1a0f0000, /* DENALI_PI_119_DATA */
+ 0x0102041e, /* DENALI_PI_120_DATA */
+ 0x34000000, /* DENALI_PI_121_DATA */
+ 0x00000000, /* DENALI_PI_122_DATA */
+ 0x00000000, /* DENALI_PI_123_DATA */
+ 0x00010000, /* DENALI_PI_124_DATA */
+ 0x00000400, /* DENALI_PI_125_DATA */
+ 0x00310000, /* DENALI_PI_126_DATA */
+ 0x004d4d00, /* DENALI_PI_127_DATA */
+ 0x00120024, /* DENALI_PI_128_DATA */
+ 0x4d000031, /* DENALI_PI_129_DATA */
+ 0x0000144d, /* DENALI_PI_130_DATA */
+ 0x00310009, /* DENALI_PI_131_DATA */
+ 0x004d4d00, /* DENALI_PI_132_DATA */
+ 0x00000004, /* DENALI_PI_133_DATA */
+ 0x4d000031, /* DENALI_PI_134_DATA */
+ 0x0000244d, /* DENALI_PI_135_DATA */
+ 0x00310012, /* DENALI_PI_136_DATA */
+ 0x004d4d00, /* DENALI_PI_137_DATA */
+ 0x00090014, /* DENALI_PI_138_DATA */
+ 0x4d000031, /* DENALI_PI_139_DATA */
+ 0x0004004d, /* DENALI_PI_140_DATA */
+ 0x00310000, /* DENALI_PI_141_DATA */
+ 0x004d4d00, /* DENALI_PI_142_DATA */
+ 0x00120024, /* DENALI_PI_143_DATA */
+ 0x4d000031, /* DENALI_PI_144_DATA */
+ 0x0000144d, /* DENALI_PI_145_DATA */
+ 0x00310009, /* DENALI_PI_146_DATA */
+ 0x004d4d00, /* DENALI_PI_147_DATA */
+ 0x00000004, /* DENALI_PI_148_DATA */
+ 0x4d000031, /* DENALI_PI_149_DATA */
+ 0x0000244d, /* DENALI_PI_150_DATA */
+ 0x00310012, /* DENALI_PI_151_DATA */
+ 0x004d4d00, /* DENALI_PI_152_DATA */
+ 0x00090014, /* DENALI_PI_153_DATA */
+ 0x4d000031, /* DENALI_PI_154_DATA */
+ 0x0200004d, /* DENALI_PI_155_DATA */
+ 0x00c8000d, /* DENALI_PI_156_DATA */
+ 0x08080064, /* DENALI_PI_157_DATA */
+ 0x040a0404, /* DENALI_PI_158_DATA */
+ 0x03000d92, /* DENALI_PI_159_DATA */
+ 0x010a2001, /* DENALI_PI_160_DATA */
+ 0x0f11080a, /* DENALI_PI_161_DATA */
+ 0x0000110a, /* DENALI_PI_162_DATA */
+ 0x2200d92e, /* DENALI_PI_163_DATA */
+ 0x080c2003, /* DENALI_PI_164_DATA */
+ 0x0809080a, /* DENALI_PI_165_DATA */
+ 0x00000a0a, /* DENALI_PI_166_DATA */
+ 0x11006c97, /* DENALI_PI_167_DATA */
+ 0x040a2002, /* DENALI_PI_168_DATA */
+ 0x0200020a, /* DENALI_PI_169_DATA */
+ 0x02000200, /* DENALI_PI_170_DATA */
+ 0x02000200, /* DENALI_PI_171_DATA */
+ 0x02000200, /* DENALI_PI_172_DATA */
+ 0x02000200, /* DENALI_PI_173_DATA */
+ 0x00000000, /* DENALI_PI_174_DATA */
+ 0x00000000, /* DENALI_PI_175_DATA */
+ 0x00000000, /* DENALI_PI_176_DATA */
+ 0x00000000, /* DENALI_PI_177_DATA */
+ 0x00000000, /* DENALI_PI_178_DATA */
+ 0x00000000, /* DENALI_PI_179_DATA */
+ 0x00000000, /* DENALI_PI_180_DATA */
+ 0x00000000, /* DENALI_PI_181_DATA */
+ 0x00000000, /* DENALI_PI_182_DATA */
+ 0x00000000, /* DENALI_PI_183_DATA */
+ 0x00000000, /* DENALI_PI_184_DATA */
+ 0x00000000, /* DENALI_PI_185_DATA */
+ 0x01000400, /* DENALI_PI_186_DATA */
+ 0x00017600, /* DENALI_PI_187_DATA */
+ 0x00000e9c, /* DENALI_PI_188_DATA */
+ 0x00001850, /* DENALI_PI_189_DATA */
+ 0x0000f320, /* DENALI_PI_190_DATA */
+ 0x00000c20, /* DENALI_PI_191_DATA */
+ 0x00007940, /* DENALI_PI_192_DATA */
+ 0x08000000, /* DENALI_PI_193_DATA */
+ 0x00000100, /* DENALI_PI_194_DATA */
+ 0x00000000, /* DENALI_PI_195_DATA */
+ 0x00000000, /* DENALI_PI_196_DATA */
+ 0x00000000, /* DENALI_PI_197_DATA */
+ 0x00000000, /* DENALI_PI_198_DATA */
+ 0x00000002 /* DENALI_PI_199_DATA */
+ }
+ },
+ {
+ {
+ 0x76543210, /* DENALI_PHY_00_DATA */
+ 0x0004f008, /* DENALI_PHY_01_DATA */
+ 0x00020119, /* DENALI_PHY_02_DATA */
+ 0x00000000, /* DENALI_PHY_03_DATA */
+ 0x00000000, /* DENALI_PHY_04_DATA */
+ 0x00010000, /* DENALI_PHY_05_DATA */
+ 0x01665555, /* DENALI_PHY_06_DATA */
+ 0x03665555, /* DENALI_PHY_07_DATA */
+ 0x00010f00, /* DENALI_PHY_08_DATA */
+ 0x05010200, /* DENALI_PHY_09_DATA */
+ 0x00000002, /* DENALI_PHY_10_DATA */
+ 0x00170180, /* DENALI_PHY_11_DATA */
+ 0x00cc0201, /* DENALI_PHY_12_DATA */
+ 0x00030066, /* DENALI_PHY_13_DATA */
+ 0x00000000, /* DENALI_PHY_14_DATA */
+ 0x00000000, /* DENALI_PHY_15_DATA */
+ 0x00000000, /* DENALI_PHY_16_DATA */
+ 0x00000000, /* DENALI_PHY_17_DATA */
+ 0x00000000, /* DENALI_PHY_18_DATA */
+ 0x00000000, /* DENALI_PHY_19_DATA */
+ 0x00000000, /* DENALI_PHY_20_DATA */
+ 0x00000000, /* DENALI_PHY_21_DATA */
+ 0x04080000, /* DENALI_PHY_22_DATA */
+ 0x04080400, /* DENALI_PHY_23_DATA */
+ 0x30000000, /* DENALI_PHY_24_DATA */
+ 0x0c00c007, /* DENALI_PHY_25_DATA */
+ 0x00000100, /* DENALI_PHY_26_DATA */
+ 0x00000000, /* DENALI_PHY_27_DATA */
+ 0xfd02fe01, /* DENALI_PHY_28_DATA */
+ 0xf708fb04, /* DENALI_PHY_29_DATA */
+ 0xdf20ef10, /* DENALI_PHY_30_DATA */
+ 0x7f80bf40, /* DENALI_PHY_31_DATA */
+ 0x0001aaaa, /* DENALI_PHY_32_DATA */
+ 0x00000000, /* DENALI_PHY_33_DATA */
+ 0x00000000, /* DENALI_PHY_34_DATA */
+ 0x00000000, /* DENALI_PHY_35_DATA */
+ 0x00000000, /* DENALI_PHY_36_DATA */
+ 0x00000000, /* DENALI_PHY_37_DATA */
+ 0x00000000, /* DENALI_PHY_38_DATA */
+ 0x00000000, /* DENALI_PHY_39_DATA */
+ 0x00000000, /* DENALI_PHY_40_DATA */
+ 0x00000000, /* DENALI_PHY_41_DATA */
+ 0x00000000, /* DENALI_PHY_42_DATA */
+ 0x00000000, /* DENALI_PHY_43_DATA */
+ 0x00000000, /* DENALI_PHY_44_DATA */
+ 0x00000000, /* DENALI_PHY_45_DATA */
+ 0x00000000, /* DENALI_PHY_46_DATA */
+ 0x00000000, /* DENALI_PHY_47_DATA */
+ 0x00000000, /* DENALI_PHY_48_DATA */
+ 0x00000000, /* DENALI_PHY_49_DATA */
+ 0x00000000, /* DENALI_PHY_50_DATA */
+ 0x00000000, /* DENALI_PHY_51_DATA */
+ 0x00200000, /* DENALI_PHY_52_DATA */
+ 0x00000000, /* DENALI_PHY_53_DATA */
+ 0x00000000, /* DENALI_PHY_54_DATA */
+ 0x00000000, /* DENALI_PHY_55_DATA */
+ 0x00000000, /* DENALI_PHY_56_DATA */
+ 0x00000000, /* DENALI_PHY_57_DATA */
+ 0x00000000, /* DENALI_PHY_58_DATA */
+ 0x02800280, /* DENALI_PHY_59_DATA */
+ 0x02800280, /* DENALI_PHY_60_DATA */
+ 0x02800280, /* DENALI_PHY_61_DATA */
+ 0x02800280, /* DENALI_PHY_62_DATA */
+ 0x00000280, /* DENALI_PHY_63_DATA */
+ 0x00000000, /* DENALI_PHY_64_DATA */
+ 0x00000000, /* DENALI_PHY_65_DATA */
+ 0x00000000, /* DENALI_PHY_66_DATA */
+ 0x00000000, /* DENALI_PHY_67_DATA */
+ 0x00800000, /* DENALI_PHY_68_DATA */
+ 0x00800080, /* DENALI_PHY_69_DATA */
+ 0x00800080, /* DENALI_PHY_70_DATA */
+ 0x00800080, /* DENALI_PHY_71_DATA */
+ 0x00800080, /* DENALI_PHY_72_DATA */
+ 0x00800080, /* DENALI_PHY_73_DATA */
+ 0x00800080, /* DENALI_PHY_74_DATA */
+ 0x00800080, /* DENALI_PHY_75_DATA */
+ 0x00800080, /* DENALI_PHY_76_DATA */
+ 0x01190080, /* DENALI_PHY_77_DATA */
+ 0x00000002, /* DENALI_PHY_78_DATA */
+ 0x00000000, /* DENALI_PHY_79_DATA */
+ 0x00000000, /* DENALI_PHY_80_DATA */
+ 0x00000200, /* DENALI_PHY_81_DATA */
+ 0x00000000, /* DENALI_PHY_82_DATA */
+ 0x51315152, /* DENALI_PHY_83_DATA */
+ 0xc0013150, /* DENALI_PHY_84_DATA */
+ 0x020000c0, /* DENALI_PHY_85_DATA */
+ 0x00100001, /* DENALI_PHY_86_DATA */
+ 0x07054204, /* DENALI_PHY_87_DATA */
+ 0x000f0c18, /* DENALI_PHY_88_DATA */
+ 0x01000140, /* DENALI_PHY_89_DATA */
+ 0x00000c10, /* DENALI_PHY_90_DATA */
+ 0x00000000, /* DENALI_PHY_91_DATA */
+ 0x00000000, /* DENALI_PHY_92_DATA */
+ 0x00000000, /* DENALI_PHY_93_DATA */
+ 0x00000000, /* DENALI_PHY_94_DATA */
+ 0x00000000, /* DENALI_PHY_95_DATA */
+ 0x00000000, /* DENALI_PHY_96_DATA */
+ 0x00000000, /* DENALI_PHY_97_DATA */
+ 0x00000000, /* DENALI_PHY_98_DATA */
+ 0x00000000, /* DENALI_PHY_99_DATA */
+ 0x00000000, /* DENALI_PHY_100_DATA */
+ 0x00000000, /* DENALI_PHY_101_DATA */
+ 0x00000000, /* DENALI_PHY_102_DATA */
+ 0x00000000, /* DENALI_PHY_103_DATA */
+ 0x00000000, /* DENALI_PHY_104_DATA */
+ 0x00000000, /* DENALI_PHY_105_DATA */
+ 0x00000000, /* DENALI_PHY_106_DATA */
+ 0x00000000, /* DENALI_PHY_107_DATA */
+ 0x00000000, /* DENALI_PHY_108_DATA */
+ 0x00000000, /* DENALI_PHY_109_DATA */
+ 0x00000000, /* DENALI_PHY_110_DATA */
+ 0x00000000, /* DENALI_PHY_111_DATA */
+ 0x00000000, /* DENALI_PHY_112_DATA */
+ 0x00000000, /* DENALI_PHY_113_DATA */
+ 0x00000000, /* DENALI_PHY_114_DATA */
+ 0x00000000, /* DENALI_PHY_115_DATA */
+ 0x00000000, /* DENALI_PHY_116_DATA */
+ 0x00000000, /* DENALI_PHY_117_DATA */
+ 0x00000000, /* DENALI_PHY_118_DATA */
+ 0x00000000, /* DENALI_PHY_119_DATA */
+ 0x00000000, /* DENALI_PHY_120_DATA */
+ 0x00000000, /* DENALI_PHY_121_DATA */
+ 0x00000000, /* DENALI_PHY_122_DATA */
+ 0x00000000, /* DENALI_PHY_123_DATA */
+ 0x00000000, /* DENALI_PHY_124_DATA */
+ 0x00000000, /* DENALI_PHY_125_DATA */
+ 0x00000000, /* DENALI_PHY_126_DATA */
+ 0x00000000, /* DENALI_PHY_127_DATA */
+ 0x76543210, /* DENALI_PHY_128_DATA */
+ 0x0004f008, /* DENALI_PHY_129_DATA */
+ 0x00020119, /* DENALI_PHY_130_DATA */
+ 0x00000000, /* DENALI_PHY_131_DATA */
+ 0x00000000, /* DENALI_PHY_132_DATA */
+ 0x00010000, /* DENALI_PHY_133_DATA */
+ 0x01665555, /* DENALI_PHY_134_DATA */
+ 0x03665555, /* DENALI_PHY_135_DATA */
+ 0x00010f00, /* DENALI_PHY_136_DATA */
+ 0x05010200, /* DENALI_PHY_137_DATA */
+ 0x00000002, /* DENALI_PHY_138_DATA */
+ 0x00170180, /* DENALI_PHY_139_DATA */
+ 0x00cc0201, /* DENALI_PHY_140_DATA */
+ 0x00030066, /* DENALI_PHY_141_DATA */
+ 0x00000000, /* DENALI_PHY_142_DATA */
+ 0x00000000, /* DENALI_PHY_143_DATA */
+ 0x00000000, /* DENALI_PHY_144_DATA */
+ 0x00000000, /* DENALI_PHY_145_DATA */
+ 0x00000000, /* DENALI_PHY_146_DATA */
+ 0x00000000, /* DENALI_PHY_147_DATA */
+ 0x00000000, /* DENALI_PHY_148_DATA */
+ 0x00000000, /* DENALI_PHY_149_DATA */
+ 0x04080000, /* DENALI_PHY_150_DATA */
+ 0x04080400, /* DENALI_PHY_151_DATA */
+ 0x30000000, /* DENALI_PHY_152_DATA */
+ 0x0c00c007, /* DENALI_PHY_153_DATA */
+ 0x00000100, /* DENALI_PHY_154_DATA */
+ 0x00000000, /* DENALI_PHY_155_DATA */
+ 0xfd02fe01, /* DENALI_PHY_156_DATA */
+ 0xf708fb04, /* DENALI_PHY_157_DATA */
+ 0xdf20ef10, /* DENALI_PHY_158_DATA */
+ 0x7f80bf40, /* DENALI_PHY_159_DATA */
+ 0x0000aaaa, /* DENALI_PHY_160_DATA */
+ 0x00000000, /* DENALI_PHY_161_DATA */
+ 0x00000000, /* DENALI_PHY_162_DATA */
+ 0x00000000, /* DENALI_PHY_163_DATA */
+ 0x00000000, /* DENALI_PHY_164_DATA */
+ 0x00000000, /* DENALI_PHY_165_DATA */
+ 0x00000000, /* DENALI_PHY_166_DATA */
+ 0x00000000, /* DENALI_PHY_167_DATA */
+ 0x00000000, /* DENALI_PHY_168_DATA */
+ 0x00000000, /* DENALI_PHY_169_DATA */
+ 0x00000000, /* DENALI_PHY_170_DATA */
+ 0x00000000, /* DENALI_PHY_171_DATA */
+ 0x00000000, /* DENALI_PHY_172_DATA */
+ 0x00000000, /* DENALI_PHY_173_DATA */
+ 0x00000000, /* DENALI_PHY_174_DATA */
+ 0x00000000, /* DENALI_PHY_175_DATA */
+ 0x00000000, /* DENALI_PHY_176_DATA */
+ 0x00000000, /* DENALI_PHY_177_DATA */
+ 0x00000000, /* DENALI_PHY_178_DATA */
+ 0x00000000, /* DENALI_PHY_179_DATA */
+ 0x00200000, /* DENALI_PHY_180_DATA */
+ 0x00000000, /* DENALI_PHY_181_DATA */
+ 0x00000000, /* DENALI_PHY_182_DATA */
+ 0x00000000, /* DENALI_PHY_183_DATA */
+ 0x00000000, /* DENALI_PHY_184_DATA */
+ 0x00000000, /* DENALI_PHY_185_DATA */
+ 0x00000000, /* DENALI_PHY_186_DATA */
+ 0x02800280, /* DENALI_PHY_187_DATA */
+ 0x02800280, /* DENALI_PHY_188_DATA */
+ 0x02800280, /* DENALI_PHY_189_DATA */
+ 0x02800280, /* DENALI_PHY_190_DATA */
+ 0x00000280, /* DENALI_PHY_191_DATA */
+ 0x00000000, /* DENALI_PHY_192_DATA */
+ 0x00000000, /* DENALI_PHY_193_DATA */
+ 0x00000000, /* DENALI_PHY_194_DATA */
+ 0x00000000, /* DENALI_PHY_195_DATA */
+ 0x00800000, /* DENALI_PHY_196_DATA */
+ 0x00800080, /* DENALI_PHY_197_DATA */
+ 0x00800080, /* DENALI_PHY_198_DATA */
+ 0x00800080, /* DENALI_PHY_199_DATA */
+ 0x00800080, /* DENALI_PHY_200_DATA */
+ 0x00800080, /* DENALI_PHY_201_DATA */
+ 0x00800080, /* DENALI_PHY_202_DATA */
+ 0x00800080, /* DENALI_PHY_203_DATA */
+ 0x00800080, /* DENALI_PHY_204_DATA */
+ 0x01190080, /* DENALI_PHY_205_DATA */
+ 0x00000002, /* DENALI_PHY_206_DATA */
+ 0x00000000, /* DENALI_PHY_207_DATA */
+ 0x00000000, /* DENALI_PHY_208_DATA */
+ 0x00000200, /* DENALI_PHY_209_DATA */
+ 0x00000000, /* DENALI_PHY_210_DATA */
+ 0x51315152, /* DENALI_PHY_211_DATA */
+ 0xc0013150, /* DENALI_PHY_212_DATA */
+ 0x020000c0, /* DENALI_PHY_213_DATA */
+ 0x00100001, /* DENALI_PHY_214_DATA */
+ 0x07054204, /* DENALI_PHY_215_DATA */
+ 0x000f0c18, /* DENALI_PHY_216_DATA */
+ 0x01000140, /* DENALI_PHY_217_DATA */
+ 0x00000c10, /* DENALI_PHY_218_DATA */
+ 0x00000000, /* DENALI_PHY_219_DATA */
+ 0x00000000, /* DENALI_PHY_220_DATA */
+ 0x00000000, /* DENALI_PHY_221_DATA */
+ 0x00000000, /* DENALI_PHY_222_DATA */
+ 0x00000000, /* DENALI_PHY_223_DATA */
+ 0x00000000, /* DENALI_PHY_224_DATA */
+ 0x00000000, /* DENALI_PHY_225_DATA */
+ 0x00000000, /* DENALI_PHY_226_DATA */
+ 0x00000000, /* DENALI_PHY_227_DATA */
+ 0x00000000, /* DENALI_PHY_228_DATA */
+ 0x00000000, /* DENALI_PHY_229_DATA */
+ 0x00000000, /* DENALI_PHY_230_DATA */
+ 0x00000000, /* DENALI_PHY_231_DATA */
+ 0x00000000, /* DENALI_PHY_232_DATA */
+ 0x00000000, /* DENALI_PHY_233_DATA */
+ 0x00000000, /* DENALI_PHY_234_DATA */
+ 0x00000000, /* DENALI_PHY_235_DATA */
+ 0x00000000, /* DENALI_PHY_236_DATA */
+ 0x00000000, /* DENALI_PHY_237_DATA */
+ 0x00000000, /* DENALI_PHY_238_DATA */
+ 0x00000000, /* DENALI_PHY_239_DATA */
+ 0x00000000, /* DENALI_PHY_240_DATA */
+ 0x00000000, /* DENALI_PHY_241_DATA */
+ 0x00000000, /* DENALI_PHY_242_DATA */
+ 0x00000000, /* DENALI_PHY_243_DATA */
+ 0x00000000, /* DENALI_PHY_244_DATA */
+ 0x00000000, /* DENALI_PHY_245_DATA */
+ 0x00000000, /* DENALI_PHY_246_DATA */
+ 0x00000000, /* DENALI_PHY_247_DATA */
+ 0x00000000, /* DENALI_PHY_248_DATA */
+ 0x00000000, /* DENALI_PHY_249_DATA */
+ 0x00000000, /* DENALI_PHY_250_DATA */
+ 0x00000000, /* DENALI_PHY_251_DATA */
+ 0x00000000, /* DENALI_PHY_252_DATA */
+ 0x00000000, /* DENALI_PHY_253_DATA */
+ 0x00000000, /* DENALI_PHY_254_DATA */
+ 0x00000000, /* DENALI_PHY_255_DATA */
+ 0x76543210, /* DENALI_PHY_256_DATA */
+ 0x0004f008, /* DENALI_PHY_257_DATA */
+ 0x00020119, /* DENALI_PHY_258_DATA */
+ 0x00000000, /* DENALI_PHY_259_DATA */
+ 0x00000000, /* DENALI_PHY_260_DATA */
+ 0x00010000, /* DENALI_PHY_261_DATA */
+ 0x01665555, /* DENALI_PHY_262_DATA */
+ 0x03665555, /* DENALI_PHY_263_DATA */
+ 0x00010f00, /* DENALI_PHY_264_DATA */
+ 0x05010200, /* DENALI_PHY_265_DATA */
+ 0x00000002, /* DENALI_PHY_266_DATA */
+ 0x00170180, /* DENALI_PHY_267_DATA */
+ 0x00cc0201, /* DENALI_PHY_268_DATA */
+ 0x00030066, /* DENALI_PHY_269_DATA */
+ 0x00000000, /* DENALI_PHY_270_DATA */
+ 0x00000000, /* DENALI_PHY_271_DATA */
+ 0x00000000, /* DENALI_PHY_272_DATA */
+ 0x00000000, /* DENALI_PHY_273_DATA */
+ 0x00000000, /* DENALI_PHY_274_DATA */
+ 0x00000000, /* DENALI_PHY_275_DATA */
+ 0x00000000, /* DENALI_PHY_276_DATA */
+ 0x00000000, /* DENALI_PHY_277_DATA */
+ 0x04080000, /* DENALI_PHY_278_DATA */
+ 0x04080400, /* DENALI_PHY_279_DATA */
+ 0x30000000, /* DENALI_PHY_280_DATA */
+ 0x0c00c007, /* DENALI_PHY_281_DATA */
+ 0x00000100, /* DENALI_PHY_282_DATA */
+ 0x00000000, /* DENALI_PHY_283_DATA */
+ 0xfd02fe01, /* DENALI_PHY_284_DATA */
+ 0xf708fb04, /* DENALI_PHY_285_DATA */
+ 0xdf20ef10, /* DENALI_PHY_286_DATA */
+ 0x7f80bf40, /* DENALI_PHY_287_DATA */
+ 0x0001aaaa, /* DENALI_PHY_288_DATA */
+ 0x00000000, /* DENALI_PHY_289_DATA */
+ 0x00000000, /* DENALI_PHY_290_DATA */
+ 0x00000000, /* DENALI_PHY_291_DATA */
+ 0x00000000, /* DENALI_PHY_292_DATA */
+ 0x00000000, /* DENALI_PHY_293_DATA */
+ 0x00000000, /* DENALI_PHY_294_DATA */
+ 0x00000000, /* DENALI_PHY_295_DATA */
+ 0x00000000, /* DENALI_PHY_296_DATA */
+ 0x00000000, /* DENALI_PHY_297_DATA */
+ 0x00000000, /* DENALI_PHY_298_DATA */
+ 0x00000000, /* DENALI_PHY_299_DATA */
+ 0x00000000, /* DENALI_PHY_300_DATA */
+ 0x00000000, /* DENALI_PHY_301_DATA */
+ 0x00000000, /* DENALI_PHY_302_DATA */
+ 0x00000000, /* DENALI_PHY_303_DATA */
+ 0x00000000, /* DENALI_PHY_304_DATA */
+ 0x00000000, /* DENALI_PHY_305_DATA */
+ 0x00000000, /* DENALI_PHY_306_DATA */
+ 0x00000000, /* DENALI_PHY_307_DATA */
+ 0x00200000, /* DENALI_PHY_308_DATA */
+ 0x00000000, /* DENALI_PHY_309_DATA */
+ 0x00000000, /* DENALI_PHY_310_DATA */
+ 0x00000000, /* DENALI_PHY_311_DATA */
+ 0x00000000, /* DENALI_PHY_312_DATA */
+ 0x00000000, /* DENALI_PHY_313_DATA */
+ 0x00000000, /* DENALI_PHY_314_DATA */
+ 0x02800280, /* DENALI_PHY_315_DATA */
+ 0x02800280, /* DENALI_PHY_316_DATA */
+ 0x02800280, /* DENALI_PHY_317_DATA */
+ 0x02800280, /* DENALI_PHY_318_DATA */
+ 0x00000280, /* DENALI_PHY_319_DATA */
+ 0x00000000, /* DENALI_PHY_320_DATA */
+ 0x00000000, /* DENALI_PHY_321_DATA */
+ 0x00000000, /* DENALI_PHY_322_DATA */
+ 0x00000000, /* DENALI_PHY_323_DATA */
+ 0x00800000, /* DENALI_PHY_324_DATA */
+ 0x00800080, /* DENALI_PHY_325_DATA */
+ 0x00800080, /* DENALI_PHY_326_DATA */
+ 0x00800080, /* DENALI_PHY_327_DATA */
+ 0x00800080, /* DENALI_PHY_328_DATA */
+ 0x00800080, /* DENALI_PHY_329_DATA */
+ 0x00800080, /* DENALI_PHY_330_DATA */
+ 0x00800080, /* DENALI_PHY_331_DATA */
+ 0x00800080, /* DENALI_PHY_332_DATA */
+ 0x01190080, /* DENALI_PHY_333_DATA */
+ 0x00000002, /* DENALI_PHY_334_DATA */
+ 0x00000000, /* DENALI_PHY_335_DATA */
+ 0x00000000, /* DENALI_PHY_336_DATA */
+ 0x00000200, /* DENALI_PHY_337_DATA */
+ 0x00000000, /* DENALI_PHY_338_DATA */
+ 0x51315152, /* DENALI_PHY_339_DATA */
+ 0xc0013150, /* DENALI_PHY_340_DATA */
+ 0x020000c0, /* DENALI_PHY_341_DATA */
+ 0x00100001, /* DENALI_PHY_342_DATA */
+ 0x07054204, /* DENALI_PHY_343_DATA */
+ 0x000f0c18, /* DENALI_PHY_344_DATA */
+ 0x01000140, /* DENALI_PHY_345_DATA */
+ 0x00000c10, /* DENALI_PHY_346_DATA */
+ 0x00000000, /* DENALI_PHY_347_DATA */
+ 0x00000000, /* DENALI_PHY_348_DATA */
+ 0x00000000, /* DENALI_PHY_349_DATA */
+ 0x00000000, /* DENALI_PHY_350_DATA */
+ 0x00000000, /* DENALI_PHY_351_DATA */
+ 0x00000000, /* DENALI_PHY_352_DATA */
+ 0x00000000, /* DENALI_PHY_353_DATA */
+ 0x00000000, /* DENALI_PHY_354_DATA */
+ 0x00000000, /* DENALI_PHY_355_DATA */
+ 0x00000000, /* DENALI_PHY_356_DATA */
+ 0x00000000, /* DENALI_PHY_357_DATA */
+ 0x00000000, /* DENALI_PHY_358_DATA */
+ 0x00000000, /* DENALI_PHY_359_DATA */
+ 0x00000000, /* DENALI_PHY_360_DATA */
+ 0x00000000, /* DENALI_PHY_361_DATA */
+ 0x00000000, /* DENALI_PHY_362_DATA */
+ 0x00000000, /* DENALI_PHY_363_DATA */
+ 0x00000000, /* DENALI_PHY_364_DATA */
+ 0x00000000, /* DENALI_PHY_365_DATA */
+ 0x00000000, /* DENALI_PHY_366_DATA */
+ 0x00000000, /* DENALI_PHY_367_DATA */
+ 0x00000000, /* DENALI_PHY_368_DATA */
+ 0x00000000, /* DENALI_PHY_369_DATA */
+ 0x00000000, /* DENALI_PHY_370_DATA */
+ 0x00000000, /* DENALI_PHY_371_DATA */
+ 0x00000000, /* DENALI_PHY_372_DATA */
+ 0x00000000, /* DENALI_PHY_373_DATA */
+ 0x00000000, /* DENALI_PHY_374_DATA */
+ 0x00000000, /* DENALI_PHY_375_DATA */
+ 0x00000000, /* DENALI_PHY_376_DATA */
+ 0x00000000, /* DENALI_PHY_377_DATA */
+ 0x00000000, /* DENALI_PHY_378_DATA */
+ 0x00000000, /* DENALI_PHY_379_DATA */
+ 0x00000000, /* DENALI_PHY_380_DATA */
+ 0x00000000, /* DENALI_PHY_381_DATA */
+ 0x00000000, /* DENALI_PHY_382_DATA */
+ 0x00000000, /* DENALI_PHY_383_DATA */
+ 0x76543210, /* DENALI_PHY_384_DATA */
+ 0x0004f008, /* DENALI_PHY_385_DATA */
+ 0x00020119, /* DENALI_PHY_386_DATA */
+ 0x00000000, /* DENALI_PHY_387_DATA */
+ 0x00000000, /* DENALI_PHY_388_DATA */
+ 0x00010000, /* DENALI_PHY_389_DATA */
+ 0x01665555, /* DENALI_PHY_390_DATA */
+ 0x03665555, /* DENALI_PHY_391_DATA */
+ 0x00010f00, /* DENALI_PHY_392_DATA */
+ 0x05010200, /* DENALI_PHY_393_DATA */
+ 0x00000002, /* DENALI_PHY_394_DATA */
+ 0x00170180, /* DENALI_PHY_395_DATA */
+ 0x00cc0201, /* DENALI_PHY_396_DATA */
+ 0x00030066, /* DENALI_PHY_397_DATA */
+ 0x00000000, /* DENALI_PHY_398_DATA */
+ 0x00000000, /* DENALI_PHY_399_DATA */
+ 0x00000000, /* DENALI_PHY_400_DATA */
+ 0x00000000, /* DENALI_PHY_401_DATA */
+ 0x00000000, /* DENALI_PHY_402_DATA */
+ 0x00000000, /* DENALI_PHY_403_DATA */
+ 0x00000000, /* DENALI_PHY_404_DATA */
+ 0x00000000, /* DENALI_PHY_405_DATA */
+ 0x04080000, /* DENALI_PHY_406_DATA */
+ 0x04080400, /* DENALI_PHY_407_DATA */
+ 0x30000000, /* DENALI_PHY_408_DATA */
+ 0x0c00c007, /* DENALI_PHY_409_DATA */
+ 0x00000100, /* DENALI_PHY_410_DATA */
+ 0x00000000, /* DENALI_PHY_411_DATA */
+ 0xfd02fe01, /* DENALI_PHY_412_DATA */
+ 0xf708fb04, /* DENALI_PHY_413_DATA */
+ 0xdf20ef10, /* DENALI_PHY_414_DATA */
+ 0x7f80bf40, /* DENALI_PHY_415_DATA */
+ 0x0000aaaa, /* DENALI_PHY_416_DATA */
+ 0x00000000, /* DENALI_PHY_417_DATA */
+ 0x00000000, /* DENALI_PHY_418_DATA */
+ 0x00000000, /* DENALI_PHY_419_DATA */
+ 0x00000000, /* DENALI_PHY_420_DATA */
+ 0x00000000, /* DENALI_PHY_421_DATA */
+ 0x00000000, /* DENALI_PHY_422_DATA */
+ 0x00000000, /* DENALI_PHY_423_DATA */
+ 0x00000000, /* DENALI_PHY_424_DATA */
+ 0x00000000, /* DENALI_PHY_425_DATA */
+ 0x00000000, /* DENALI_PHY_426_DATA */
+ 0x00000000, /* DENALI_PHY_427_DATA */
+ 0x00000000, /* DENALI_PHY_428_DATA */
+ 0x00000000, /* DENALI_PHY_429_DATA */
+ 0x00000000, /* DENALI_PHY_430_DATA */
+ 0x00000000, /* DENALI_PHY_431_DATA */
+ 0x00000000, /* DENALI_PHY_432_DATA */
+ 0x00000000, /* DENALI_PHY_433_DATA */
+ 0x00000000, /* DENALI_PHY_434_DATA */
+ 0x00000000, /* DENALI_PHY_435_DATA */
+ 0x00200000, /* DENALI_PHY_436_DATA */
+ 0x00000000, /* DENALI_PHY_437_DATA */
+ 0x00000000, /* DENALI_PHY_438_DATA */
+ 0x00000000, /* DENALI_PHY_439_DATA */
+ 0x00000000, /* DENALI_PHY_440_DATA */
+ 0x00000000, /* DENALI_PHY_441_DATA */
+ 0x00000000, /* DENALI_PHY_442_DATA */
+ 0x02800280, /* DENALI_PHY_443_DATA */
+ 0x02800280, /* DENALI_PHY_444_DATA */
+ 0x02800280, /* DENALI_PHY_445_DATA */
+ 0x02800280, /* DENALI_PHY_446_DATA */
+ 0x00000280, /* DENALI_PHY_447_DATA */
+ 0x00000000, /* DENALI_PHY_448_DATA */
+ 0x00000000, /* DENALI_PHY_449_DATA */
+ 0x00000000, /* DENALI_PHY_450_DATA */
+ 0x00000000, /* DENALI_PHY_451_DATA */
+ 0x00800000, /* DENALI_PHY_452_DATA */
+ 0x00800080, /* DENALI_PHY_453_DATA */
+ 0x00800080, /* DENALI_PHY_454_DATA */
+ 0x00800080, /* DENALI_PHY_455_DATA */
+ 0x00800080, /* DENALI_PHY_456_DATA */
+ 0x00800080, /* DENALI_PHY_457_DATA */
+ 0x00800080, /* DENALI_PHY_458_DATA */
+ 0x00800080, /* DENALI_PHY_459_DATA */
+ 0x00800080, /* DENALI_PHY_460_DATA */
+ 0x01190080, /* DENALI_PHY_461_DATA */
+ 0x00000002, /* DENALI_PHY_462_DATA */
+ 0x00000000, /* DENALI_PHY_463_DATA */
+ 0x00000000, /* DENALI_PHY_464_DATA */
+ 0x00000200, /* DENALI_PHY_465_DATA */
+ 0x00000000, /* DENALI_PHY_466_DATA */
+ 0x51315152, /* DENALI_PHY_467_DATA */
+ 0xc0013150, /* DENALI_PHY_468_DATA */
+ 0x020000c0, /* DENALI_PHY_469_DATA */
+ 0x00100001, /* DENALI_PHY_470_DATA */
+ 0x07054204, /* DENALI_PHY_471_DATA */
+ 0x000f0c18, /* DENALI_PHY_472_DATA */
+ 0x01000140, /* DENALI_PHY_473_DATA */
+ 0x00000c10, /* DENALI_PHY_474_DATA */
+ 0x00000000, /* DENALI_PHY_475_DATA */
+ 0x00000000, /* DENALI_PHY_476_DATA */
+ 0x00000000, /* DENALI_PHY_477_DATA */
+ 0x00000000, /* DENALI_PHY_478_DATA */
+ 0x00000000, /* DENALI_PHY_479_DATA */
+ 0x00000000, /* DENALI_PHY_480_DATA */
+ 0x00000000, /* DENALI_PHY_481_DATA */
+ 0x00000000, /* DENALI_PHY_482_DATA */
+ 0x00000000, /* DENALI_PHY_483_DATA */
+ 0x00000000, /* DENALI_PHY_484_DATA */
+ 0x00000000, /* DENALI_PHY_485_DATA */
+ 0x00000000, /* DENALI_PHY_486_DATA */
+ 0x00000000, /* DENALI_PHY_487_DATA */
+ 0x00000000, /* DENALI_PHY_488_DATA */
+ 0x00000000, /* DENALI_PHY_489_DATA */
+ 0x00000000, /* DENALI_PHY_490_DATA */
+ 0x00000000, /* DENALI_PHY_491_DATA */
+ 0x00000000, /* DENALI_PHY_492_DATA */
+ 0x00000000, /* DENALI_PHY_493_DATA */
+ 0x00000000, /* DENALI_PHY_494_DATA */
+ 0x00000000, /* DENALI_PHY_495_DATA */
+ 0x00000000, /* DENALI_PHY_496_DATA */
+ 0x00000000, /* DENALI_PHY_497_DATA */
+ 0x00000000, /* DENALI_PHY_498_DATA */
+ 0x00000000, /* DENALI_PHY_499_DATA */
+ 0x00000000, /* DENALI_PHY_500_DATA */
+ 0x00000000, /* DENALI_PHY_501_DATA */
+ 0x00000000, /* DENALI_PHY_502_DATA */
+ 0x00000000, /* DENALI_PHY_503_DATA */
+ 0x00000000, /* DENALI_PHY_504_DATA */
+ 0x00000000, /* DENALI_PHY_505_DATA */
+ 0x00000000, /* DENALI_PHY_506_DATA */
+ 0x00000000, /* DENALI_PHY_507_DATA */
+ 0x00000000, /* DENALI_PHY_508_DATA */
+ 0x00000000, /* DENALI_PHY_509_DATA */
+ 0x00000000, /* DENALI_PHY_510_DATA */
+ 0x00000000, /* DENALI_PHY_511_DATA */
+ 0x00000000, /* DENALI_PHY_512_DATA */
+ 0x00000000, /* DENALI_PHY_513_DATA */
+ 0x00000000, /* DENALI_PHY_514_DATA */
+ 0x00000000, /* DENALI_PHY_515_DATA */
+ 0x00000000, /* DENALI_PHY_516_DATA */
+ 0x00000000, /* DENALI_PHY_517_DATA */
+ 0x00000000, /* DENALI_PHY_518_DATA */
+ 0x00000002, /* DENALI_PHY_519_DATA */
+ 0x00000000, /* DENALI_PHY_520_DATA */
+ 0x00000000, /* DENALI_PHY_521_DATA */
+ 0x00000000, /* DENALI_PHY_522_DATA */
+ 0x00400320, /* DENALI_PHY_523_DATA */
+ 0x00000040, /* DENALI_PHY_524_DATA */
+ 0x00dcba98, /* DENALI_PHY_525_DATA */
+ 0x00000000, /* DENALI_PHY_526_DATA */
+ 0x00dcba98, /* DENALI_PHY_527_DATA */
+ 0x01000000, /* DENALI_PHY_528_DATA */
+ 0x00020003, /* DENALI_PHY_529_DATA */
+ 0x00000000, /* DENALI_PHY_530_DATA */
+ 0x00000000, /* DENALI_PHY_531_DATA */
+ 0x00000000, /* DENALI_PHY_532_DATA */
+ 0x0000002a, /* DENALI_PHY_533_DATA */
+ 0x00000015, /* DENALI_PHY_534_DATA */
+ 0x00000015, /* DENALI_PHY_535_DATA */
+ 0x0000002a, /* DENALI_PHY_536_DATA */
+ 0x00000033, /* DENALI_PHY_537_DATA */
+ 0x0000000c, /* DENALI_PHY_538_DATA */
+ 0x0000000c, /* DENALI_PHY_539_DATA */
+ 0x00000033, /* DENALI_PHY_540_DATA */
+ 0x0a418820, /* DENALI_PHY_541_DATA */
+ 0x003f0000, /* DENALI_PHY_542_DATA */
+ 0x0000003f, /* DENALI_PHY_543_DATA */
+ 0x00030055, /* DENALI_PHY_544_DATA */
+ 0x03000300, /* DENALI_PHY_545_DATA */
+ 0x03000300, /* DENALI_PHY_546_DATA */
+ 0x00000300, /* DENALI_PHY_547_DATA */
+ 0x42080010, /* DENALI_PHY_548_DATA */
+ 0x00000003, /* DENALI_PHY_549_DATA */
+ 0x00000000, /* DENALI_PHY_550_DATA */
+ 0x00000000, /* DENALI_PHY_551_DATA */
+ 0x00000000, /* DENALI_PHY_552_DATA */
+ 0x00000000, /* DENALI_PHY_553_DATA */
+ 0x00000000, /* DENALI_PHY_554_DATA */
+ 0x00000000, /* DENALI_PHY_555_DATA */
+ 0x00000000, /* DENALI_PHY_556_DATA */
+ 0x00000000, /* DENALI_PHY_557_DATA */
+ 0x00000000, /* DENALI_PHY_558_DATA */
+ 0x00000000, /* DENALI_PHY_559_DATA */
+ 0x00000000, /* DENALI_PHY_560_DATA */
+ 0x00000000, /* DENALI_PHY_561_DATA */
+ 0x00000000, /* DENALI_PHY_562_DATA */
+ 0x00000000, /* DENALI_PHY_563_DATA */
+ 0x00000000, /* DENALI_PHY_564_DATA */
+ 0x00000000, /* DENALI_PHY_565_DATA */
+ 0x00000000, /* DENALI_PHY_566_DATA */
+ 0x00000000, /* DENALI_PHY_567_DATA */
+ 0x00000000, /* DENALI_PHY_568_DATA */
+ 0x00000000, /* DENALI_PHY_569_DATA */
+ 0x00000000, /* DENALI_PHY_570_DATA */
+ 0x00000000, /* DENALI_PHY_571_DATA */
+ 0x00000000, /* DENALI_PHY_572_DATA */
+ 0x00000000, /* DENALI_PHY_573_DATA */
+ 0x00000000, /* DENALI_PHY_574_DATA */
+ 0x00000000, /* DENALI_PHY_575_DATA */
+ 0x00000000, /* DENALI_PHY_576_DATA */
+ 0x00000000, /* DENALI_PHY_577_DATA */
+ 0x00000000, /* DENALI_PHY_578_DATA */
+ 0x00000000, /* DENALI_PHY_579_DATA */
+ 0x00000000, /* DENALI_PHY_580_DATA */
+ 0x00000000, /* DENALI_PHY_581_DATA */
+ 0x00000000, /* DENALI_PHY_582_DATA */
+ 0x00000000, /* DENALI_PHY_583_DATA */
+ 0x00000000, /* DENALI_PHY_584_DATA */
+ 0x00000000, /* DENALI_PHY_585_DATA */
+ 0x00000000, /* DENALI_PHY_586_DATA */
+ 0x00000000, /* DENALI_PHY_587_DATA */
+ 0x00000000, /* DENALI_PHY_588_DATA */
+ 0x00000000, /* DENALI_PHY_589_DATA */
+ 0x00000000, /* DENALI_PHY_590_DATA */
+ 0x00000000, /* DENALI_PHY_591_DATA */
+ 0x00000000, /* DENALI_PHY_592_DATA */
+ 0x00000000, /* DENALI_PHY_593_DATA */
+ 0x00000000, /* DENALI_PHY_594_DATA */
+ 0x00000000, /* DENALI_PHY_595_DATA */
+ 0x00000000, /* DENALI_PHY_596_DATA */
+ 0x00000000, /* DENALI_PHY_597_DATA */
+ 0x00000000, /* DENALI_PHY_598_DATA */
+ 0x00000000, /* DENALI_PHY_599_DATA */
+ 0x00000000, /* DENALI_PHY_600_DATA */
+ 0x00000000, /* DENALI_PHY_601_DATA */
+ 0x00000000, /* DENALI_PHY_602_DATA */
+ 0x00000000, /* DENALI_PHY_603_DATA */
+ 0x00000000, /* DENALI_PHY_604_DATA */
+ 0x00000000, /* DENALI_PHY_605_DATA */
+ 0x00000000, /* DENALI_PHY_606_DATA */
+ 0x00000000, /* DENALI_PHY_607_DATA */
+ 0x00000000, /* DENALI_PHY_608_DATA */
+ 0x00000000, /* DENALI_PHY_609_DATA */
+ 0x00000000, /* DENALI_PHY_610_DATA */
+ 0x00000000, /* DENALI_PHY_611_DATA */
+ 0x00000000, /* DENALI_PHY_612_DATA */
+ 0x00000000, /* DENALI_PHY_613_DATA */
+ 0x00000000, /* DENALI_PHY_614_DATA */
+ 0x00000000, /* DENALI_PHY_615_DATA */
+ 0x00000000, /* DENALI_PHY_616_DATA */
+ 0x00000000, /* DENALI_PHY_617_DATA */
+ 0x00000000, /* DENALI_PHY_618_DATA */
+ 0x00000000, /* DENALI_PHY_619_DATA */
+ 0x00000000, /* DENALI_PHY_620_DATA */
+ 0x00000000, /* DENALI_PHY_621_DATA */
+ 0x00000000, /* DENALI_PHY_622_DATA */
+ 0x00000000, /* DENALI_PHY_623_DATA */
+ 0x00000000, /* DENALI_PHY_624_DATA */
+ 0x00000000, /* DENALI_PHY_625_DATA */
+ 0x00000000, /* DENALI_PHY_626_DATA */
+ 0x00000000, /* DENALI_PHY_627_DATA */
+ 0x00000000, /* DENALI_PHY_628_DATA */
+ 0x00000000, /* DENALI_PHY_629_DATA */
+ 0x00000000, /* DENALI_PHY_630_DATA */
+ 0x00000000, /* DENALI_PHY_631_DATA */
+ 0x00000000, /* DENALI_PHY_632_DATA */
+ 0x00000000, /* DENALI_PHY_633_DATA */
+ 0x00000000, /* DENALI_PHY_634_DATA */
+ 0x00000000, /* DENALI_PHY_635_DATA */
+ 0x00000000, /* DENALI_PHY_636_DATA */
+ 0x00000000, /* DENALI_PHY_637_DATA */
+ 0x00000000, /* DENALI_PHY_638_DATA */
+ 0x00000000, /* DENALI_PHY_639_DATA */
+ 0x00000000, /* DENALI_PHY_640_DATA */
+ 0x00000000, /* DENALI_PHY_641_DATA */
+ 0x00000000, /* DENALI_PHY_642_DATA */
+ 0x00000000, /* DENALI_PHY_643_DATA */
+ 0x00000000, /* DENALI_PHY_644_DATA */
+ 0x00000000, /* DENALI_PHY_645_DATA */
+ 0x00000000, /* DENALI_PHY_646_DATA */
+ 0x00000002, /* DENALI_PHY_647_DATA */
+ 0x00000000, /* DENALI_PHY_648_DATA */
+ 0x00000000, /* DENALI_PHY_649_DATA */
+ 0x00000000, /* DENALI_PHY_650_DATA */
+ 0x00400320, /* DENALI_PHY_651_DATA */
+ 0x00000040, /* DENALI_PHY_652_DATA */
+ 0x00000000, /* DENALI_PHY_653_DATA */
+ 0x00000000, /* DENALI_PHY_654_DATA */
+ 0x00000000, /* DENALI_PHY_655_DATA */
+ 0x01000000, /* DENALI_PHY_656_DATA */
+ 0x00020003, /* DENALI_PHY_657_DATA */
+ 0x00000000, /* DENALI_PHY_658_DATA */
+ 0x00000000, /* DENALI_PHY_659_DATA */
+ 0x00000000, /* DENALI_PHY_660_DATA */
+ 0x0000002a, /* DENALI_PHY_661_DATA */
+ 0x00000015, /* DENALI_PHY_662_DATA */
+ 0x00000015, /* DENALI_PHY_663_DATA */
+ 0x0000002a, /* DENALI_PHY_664_DATA */
+ 0x00000033, /* DENALI_PHY_665_DATA */
+ 0x0000000c, /* DENALI_PHY_666_DATA */
+ 0x0000000c, /* DENALI_PHY_667_DATA */
+ 0x00000033, /* DENALI_PHY_668_DATA */
+ 0x00000000, /* DENALI_PHY_669_DATA */
+ 0x00000000, /* DENALI_PHY_670_DATA */
+ 0x00000000, /* DENALI_PHY_671_DATA */
+ 0x00030055, /* DENALI_PHY_672_DATA */
+ 0x03000300, /* DENALI_PHY_673_DATA */
+ 0x03000300, /* DENALI_PHY_674_DATA */
+ 0x00000300, /* DENALI_PHY_675_DATA */
+ 0x42080010, /* DENALI_PHY_676_DATA */
+ 0x00000003, /* DENALI_PHY_677_DATA */
+ 0x00000000, /* DENALI_PHY_678_DATA */
+ 0x00000000, /* DENALI_PHY_679_DATA */
+ 0x00000000, /* DENALI_PHY_680_DATA */
+ 0x00000000, /* DENALI_PHY_681_DATA */
+ 0x00000000, /* DENALI_PHY_682_DATA */
+ 0x00000000, /* DENALI_PHY_683_DATA */
+ 0x00000000, /* DENALI_PHY_684_DATA */
+ 0x00000000, /* DENALI_PHY_685_DATA */
+ 0x00000000, /* DENALI_PHY_686_DATA */
+ 0x00000000, /* DENALI_PHY_687_DATA */
+ 0x00000000, /* DENALI_PHY_688_DATA */
+ 0x00000000, /* DENALI_PHY_689_DATA */
+ 0x00000000, /* DENALI_PHY_690_DATA */
+ 0x00000000, /* DENALI_PHY_691_DATA */
+ 0x00000000, /* DENALI_PHY_692_DATA */
+ 0x00000000, /* DENALI_PHY_693_DATA */
+ 0x00000000, /* DENALI_PHY_694_DATA */
+ 0x00000000, /* DENALI_PHY_695_DATA */
+ 0x00000000, /* DENALI_PHY_696_DATA */
+ 0x00000000, /* DENALI_PHY_697_DATA */
+ 0x00000000, /* DENALI_PHY_698_DATA */
+ 0x00000000, /* DENALI_PHY_699_DATA */
+ 0x00000000, /* DENALI_PHY_700_DATA */
+ 0x00000000, /* DENALI_PHY_701_DATA */
+ 0x00000000, /* DENALI_PHY_702_DATA */
+ 0x00000000, /* DENALI_PHY_703_DATA */
+ 0x00000000, /* DENALI_PHY_704_DATA */
+ 0x00000000, /* DENALI_PHY_705_DATA */
+ 0x00000000, /* DENALI_PHY_706_DATA */
+ 0x00000000, /* DENALI_PHY_707_DATA */
+ 0x00000000, /* DENALI_PHY_708_DATA */
+ 0x00000000, /* DENALI_PHY_709_DATA */
+ 0x00000000, /* DENALI_PHY_710_DATA */
+ 0x00000000, /* DENALI_PHY_711_DATA */
+ 0x00000000, /* DENALI_PHY_712_DATA */
+ 0x00000000, /* DENALI_PHY_713_DATA */
+ 0x00000000, /* DENALI_PHY_714_DATA */
+ 0x00000000, /* DENALI_PHY_715_DATA */
+ 0x00000000, /* DENALI_PHY_716_DATA */
+ 0x00000000, /* DENALI_PHY_717_DATA */
+ 0x00000000, /* DENALI_PHY_718_DATA */
+ 0x00000000, /* DENALI_PHY_719_DATA */
+ 0x00000000, /* DENALI_PHY_720_DATA */
+ 0x00000000, /* DENALI_PHY_721_DATA */
+ 0x00000000, /* DENALI_PHY_722_DATA */
+ 0x00000000, /* DENALI_PHY_723_DATA */
+ 0x00000000, /* DENALI_PHY_724_DATA */
+ 0x00000000, /* DENALI_PHY_725_DATA */
+ 0x00000000, /* DENALI_PHY_726_DATA */
+ 0x00000000, /* DENALI_PHY_727_DATA */
+ 0x00000000, /* DENALI_PHY_728_DATA */
+ 0x00000000, /* DENALI_PHY_729_DATA */
+ 0x00000000, /* DENALI_PHY_730_DATA */
+ 0x00000000, /* DENALI_PHY_731_DATA */
+ 0x00000000, /* DENALI_PHY_732_DATA */
+ 0x00000000, /* DENALI_PHY_733_DATA */
+ 0x00000000, /* DENALI_PHY_734_DATA */
+ 0x00000000, /* DENALI_PHY_735_DATA */
+ 0x00000000, /* DENALI_PHY_736_DATA */
+ 0x00000000, /* DENALI_PHY_737_DATA */
+ 0x00000000, /* DENALI_PHY_738_DATA */
+ 0x00000000, /* DENALI_PHY_739_DATA */
+ 0x00000000, /* DENALI_PHY_740_DATA */
+ 0x00000000, /* DENALI_PHY_741_DATA */
+ 0x00000000, /* DENALI_PHY_742_DATA */
+ 0x00000000, /* DENALI_PHY_743_DATA */
+ 0x00000000, /* DENALI_PHY_744_DATA */
+ 0x00000000, /* DENALI_PHY_745_DATA */
+ 0x00000000, /* DENALI_PHY_746_DATA */
+ 0x00000000, /* DENALI_PHY_747_DATA */
+ 0x00000000, /* DENALI_PHY_748_DATA */
+ 0x00000000, /* DENALI_PHY_749_DATA */
+ 0x00000000, /* DENALI_PHY_750_DATA */
+ 0x00000000, /* DENALI_PHY_751_DATA */
+ 0x00000000, /* DENALI_PHY_752_DATA */
+ 0x00000000, /* DENALI_PHY_753_DATA */
+ 0x00000000, /* DENALI_PHY_754_DATA */
+ 0x00000000, /* DENALI_PHY_755_DATA */
+ 0x00000000, /* DENALI_PHY_756_DATA */
+ 0x00000000, /* DENALI_PHY_757_DATA */
+ 0x00000000, /* DENALI_PHY_758_DATA */
+ 0x00000000, /* DENALI_PHY_759_DATA */
+ 0x00000000, /* DENALI_PHY_760_DATA */
+ 0x00000000, /* DENALI_PHY_761_DATA */
+ 0x00000000, /* DENALI_PHY_762_DATA */
+ 0x00000000, /* DENALI_PHY_763_DATA */
+ 0x00000000, /* DENALI_PHY_764_DATA */
+ 0x00000000, /* DENALI_PHY_765_DATA */
+ 0x00000000, /* DENALI_PHY_766_DATA */
+ 0x00000000, /* DENALI_PHY_767_DATA */
+ 0x00000000, /* DENALI_PHY_768_DATA */
+ 0x00000000, /* DENALI_PHY_769_DATA */
+ 0x00000000, /* DENALI_PHY_770_DATA */
+ 0x00000000, /* DENALI_PHY_771_DATA */
+ 0x00000000, /* DENALI_PHY_772_DATA */
+ 0x00000000, /* DENALI_PHY_773_DATA */
+ 0x00000000, /* DENALI_PHY_774_DATA */
+ 0x00000002, /* DENALI_PHY_775_DATA */
+ 0x00000000, /* DENALI_PHY_776_DATA */
+ 0x00000000, /* DENALI_PHY_777_DATA */
+ 0x00000000, /* DENALI_PHY_778_DATA */
+ 0x00400320, /* DENALI_PHY_779_DATA */
+ 0x00000040, /* DENALI_PHY_780_DATA */
+ 0x00000000, /* DENALI_PHY_781_DATA */
+ 0x00000000, /* DENALI_PHY_782_DATA */
+ 0x00000000, /* DENALI_PHY_783_DATA */
+ 0x01000000, /* DENALI_PHY_784_DATA */
+ 0x00020003, /* DENALI_PHY_785_DATA */
+ 0x00000000, /* DENALI_PHY_786_DATA */
+ 0x00000000, /* DENALI_PHY_787_DATA */
+ 0x00000000, /* DENALI_PHY_788_DATA */
+ 0x0000002a, /* DENALI_PHY_789_DATA */
+ 0x00000015, /* DENALI_PHY_790_DATA */
+ 0x00000015, /* DENALI_PHY_791_DATA */
+ 0x0000002a, /* DENALI_PHY_792_DATA */
+ 0x00000033, /* DENALI_PHY_793_DATA */
+ 0x0000000c, /* DENALI_PHY_794_DATA */
+ 0x0000000c, /* DENALI_PHY_795_DATA */
+ 0x00000033, /* DENALI_PHY_796_DATA */
+ 0x1ee6b16a, /* DENALI_PHY_797_DATA */
+ 0x10000000, /* DENALI_PHY_798_DATA */
+ 0x00000000, /* DENALI_PHY_799_DATA */
+ 0x00030055, /* DENALI_PHY_800_DATA */
+ 0x03000300, /* DENALI_PHY_801_DATA */
+ 0x03000300, /* DENALI_PHY_802_DATA */
+ 0x00000300, /* DENALI_PHY_803_DATA */
+ 0x42080010, /* DENALI_PHY_804_DATA */
+ 0x00000003, /* DENALI_PHY_805_DATA */
+ 0x00000000, /* DENALI_PHY_806_DATA */
+ 0x00000000, /* DENALI_PHY_807_DATA */
+ 0x00000000, /* DENALI_PHY_808_DATA */
+ 0x00000000, /* DENALI_PHY_809_DATA */
+ 0x00000000, /* DENALI_PHY_810_DATA */
+ 0x00000000, /* DENALI_PHY_811_DATA */
+ 0x00000000, /* DENALI_PHY_812_DATA */
+ 0x00000000, /* DENALI_PHY_813_DATA */
+ 0x00000000, /* DENALI_PHY_814_DATA */
+ 0x00000000, /* DENALI_PHY_815_DATA */
+ 0x00000000, /* DENALI_PHY_816_DATA */
+ 0x00000000, /* DENALI_PHY_817_DATA */
+ 0x00000000, /* DENALI_PHY_818_DATA */
+ 0x00000000, /* DENALI_PHY_819_DATA */
+ 0x00000000, /* DENALI_PHY_820_DATA */
+ 0x00000000, /* DENALI_PHY_821_DATA */
+ 0x00000000, /* DENALI_PHY_822_DATA */
+ 0x00000000, /* DENALI_PHY_823_DATA */
+ 0x00000000, /* DENALI_PHY_824_DATA */
+ 0x00000000, /* DENALI_PHY_825_DATA */
+ 0x00000000, /* DENALI_PHY_826_DATA */
+ 0x00000000, /* DENALI_PHY_827_DATA */
+ 0x00000000, /* DENALI_PHY_828_DATA */
+ 0x00000000, /* DENALI_PHY_829_DATA */
+ 0x00000000, /* DENALI_PHY_830_DATA */
+ 0x00000000, /* DENALI_PHY_831_DATA */
+ 0x00000000, /* DENALI_PHY_832_DATA */
+ 0x00000000, /* DENALI_PHY_833_DATA */
+ 0x00000000, /* DENALI_PHY_834_DATA */
+ 0x00000000, /* DENALI_PHY_835_DATA */
+ 0x00000000, /* DENALI_PHY_836_DATA */
+ 0x00000000, /* DENALI_PHY_837_DATA */
+ 0x00000000, /* DENALI_PHY_838_DATA */
+ 0x00000000, /* DENALI_PHY_839_DATA */
+ 0x00000000, /* DENALI_PHY_840_DATA */
+ 0x00000000, /* DENALI_PHY_841_DATA */
+ 0x00000000, /* DENALI_PHY_842_DATA */
+ 0x00000000, /* DENALI_PHY_843_DATA */
+ 0x00000000, /* DENALI_PHY_844_DATA */
+ 0x00000000, /* DENALI_PHY_845_DATA */
+ 0x00000000, /* DENALI_PHY_846_DATA */
+ 0x00000000, /* DENALI_PHY_847_DATA */
+ 0x00000000, /* DENALI_PHY_848_DATA */
+ 0x00000000, /* DENALI_PHY_849_DATA */
+ 0x00000000, /* DENALI_PHY_850_DATA */
+ 0x00000000, /* DENALI_PHY_851_DATA */
+ 0x00000000, /* DENALI_PHY_852_DATA */
+ 0x00000000, /* DENALI_PHY_853_DATA */
+ 0x00000000, /* DENALI_PHY_854_DATA */
+ 0x00000000, /* DENALI_PHY_855_DATA */
+ 0x00000000, /* DENALI_PHY_856_DATA */
+ 0x00000000, /* DENALI_PHY_857_DATA */
+ 0x00000000, /* DENALI_PHY_858_DATA */
+ 0x00000000, /* DENALI_PHY_859_DATA */
+ 0x00000000, /* DENALI_PHY_860_DATA */
+ 0x00000000, /* DENALI_PHY_861_DATA */
+ 0x00000000, /* DENALI_PHY_862_DATA */
+ 0x00000000, /* DENALI_PHY_863_DATA */
+ 0x00000000, /* DENALI_PHY_864_DATA */
+ 0x00000000, /* DENALI_PHY_865_DATA */
+ 0x00000000, /* DENALI_PHY_866_DATA */
+ 0x00000000, /* DENALI_PHY_867_DATA */
+ 0x00000000, /* DENALI_PHY_868_DATA */
+ 0x00000000, /* DENALI_PHY_869_DATA */
+ 0x00000000, /* DENALI_PHY_870_DATA */
+ 0x00000000, /* DENALI_PHY_871_DATA */
+ 0x00000000, /* DENALI_PHY_872_DATA */
+ 0x00000000, /* DENALI_PHY_873_DATA */
+ 0x00000000, /* DENALI_PHY_874_DATA */
+ 0x00000000, /* DENALI_PHY_875_DATA */
+ 0x00000000, /* DENALI_PHY_876_DATA */
+ 0x00000000, /* DENALI_PHY_877_DATA */
+ 0x00000000, /* DENALI_PHY_878_DATA */
+ 0x00000000, /* DENALI_PHY_879_DATA */
+ 0x00000000, /* DENALI_PHY_880_DATA */
+ 0x00000000, /* DENALI_PHY_881_DATA */
+ 0x00000000, /* DENALI_PHY_882_DATA */
+ 0x00000000, /* DENALI_PHY_883_DATA */
+ 0x00000000, /* DENALI_PHY_884_DATA */
+ 0x00000000, /* DENALI_PHY_885_DATA */
+ 0x00000000, /* DENALI_PHY_886_DATA */
+ 0x00000000, /* DENALI_PHY_887_DATA */
+ 0x00000000, /* DENALI_PHY_888_DATA */
+ 0x00000000, /* DENALI_PHY_889_DATA */
+ 0x00000000, /* DENALI_PHY_890_DATA */
+ 0x00000000, /* DENALI_PHY_891_DATA */
+ 0x00000000, /* DENALI_PHY_892_DATA */
+ 0x00000000, /* DENALI_PHY_893_DATA */
+ 0x00000000, /* DENALI_PHY_894_DATA */
+ 0x00000000, /* DENALI_PHY_895_DATA */
+ 0x00000000, /* DENALI_PHY_896_DATA */
+ 0x00000000, /* DENALI_PHY_897_DATA */
+ 0x00000005, /* DENALI_PHY_898_DATA */
+ 0x04000f01, /* DENALI_PHY_899_DATA */
+ 0x00020040, /* DENALI_PHY_900_DATA */
+ 0x00020055, /* DENALI_PHY_901_DATA */
+ 0x00000000, /* DENALI_PHY_902_DATA */
+ 0x00000000, /* DENALI_PHY_903_DATA */
+ 0x00000000, /* DENALI_PHY_904_DATA */
+ 0x00000050, /* DENALI_PHY_905_DATA */
+ 0x00000000, /* DENALI_PHY_906_DATA */
+ 0x01010100, /* DENALI_PHY_907_DATA */
+ 0x00000600, /* DENALI_PHY_908_DATA */
+ 0x00000000, /* DENALI_PHY_909_DATA */
+ 0x00006400, /* DENALI_PHY_910_DATA */
+ 0x01221102, /* DENALI_PHY_911_DATA */
+ 0x00000000, /* DENALI_PHY_912_DATA */
+ 0x000d1f00, /* DENALI_PHY_913_DATA */
+ 0x0d1f0d1f, /* DENALI_PHY_914_DATA */
+ 0x0d1f0d1f, /* DENALI_PHY_915_DATA */
+ 0x00030003, /* DENALI_PHY_916_DATA */
+ 0x03000300, /* DENALI_PHY_917_DATA */
+ 0x00000300, /* DENALI_PHY_918_DATA */
+ 0x01221102, /* DENALI_PHY_919_DATA */
+ 0x00000000, /* DENALI_PHY_920_DATA */
+ 0x00000000, /* DENALI_PHY_921_DATA */
+ 0x03020000, /* DENALI_PHY_922_DATA */
+ 0x00000001, /* DENALI_PHY_923_DATA */
+ 0x00000411, /* DENALI_PHY_924_DATA */
+ 0x00000411, /* DENALI_PHY_925_DATA */
+ 0x00000040, /* DENALI_PHY_926_DATA */
+ 0x00000040, /* DENALI_PHY_927_DATA */
+ 0x00000411, /* DENALI_PHY_928_DATA */
+ 0x00000411, /* DENALI_PHY_929_DATA */
+ 0x00004410, /* DENALI_PHY_930_DATA */
+ 0x00004410, /* DENALI_PHY_931_DATA */
+ 0x00004410, /* DENALI_PHY_932_DATA */
+ 0x00004410, /* DENALI_PHY_933_DATA */
+ 0x00004410, /* DENALI_PHY_934_DATA */
+ 0x00000411, /* DENALI_PHY_935_DATA */
+ 0x00004410, /* DENALI_PHY_936_DATA */
+ 0x00000411, /* DENALI_PHY_937_DATA */
+ 0x00004410, /* DENALI_PHY_938_DATA */
+ 0x00000411, /* DENALI_PHY_939_DATA */
+ 0x00004410, /* DENALI_PHY_940_DATA */
+ 0x00000000, /* DENALI_PHY_941_DATA */
+ 0x00000000, /* DENALI_PHY_942_DATA */
+ 0x00000000, /* DENALI_PHY_943_DATA */
+ 0x64000000, /* DENALI_PHY_944_DATA */
+ 0x00000000, /* DENALI_PHY_945_DATA */
+ 0x00000000, /* DENALI_PHY_946_DATA */
+ 0x00000508, /* DENALI_PHY_947_DATA */
+ 0x00000000, /* DENALI_PHY_948_DATA */
+ 0x00000000, /* DENALI_PHY_949_DATA */
+ 0x00000000, /* DENALI_PHY_950_DATA */
+ 0x00000000, /* DENALI_PHY_951_DATA */
+ 0x00000000, /* DENALI_PHY_952_DATA */
+ 0x00000000, /* DENALI_PHY_953_DATA */
+ 0xe4000000, /* DENALI_PHY_954_DATA */
+ 0x00000000, /* DENALI_PHY_955_DATA */
+ 0x00000000, /* DENALI_PHY_956_DATA */
+ 0x01010000, /* DENALI_PHY_957_DATA */
+ 0x00000000 /* DENALI_PHY_958_DATA */
+ }
+ },
+},
diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c
new file mode 100644
index 0000000..9cf6626
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_debug.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
+ * (C) Copyright 2019 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <asm/arch-rockchip/sdram_common.h>
+
+void sdram_print_dram_type(unsigned char dramtype)
+{
+ switch (dramtype) {
+ case DDR3:
+ printascii("DDR3");
+ break;
+ case DDR4:
+ printascii("DDR4");
+ break;
+ case LPDDR2:
+ printascii("LPDDR2");
+ break;
+ case LPDDR3:
+ printascii("LPDDR3");
+ break;
+ case LPDDR4:
+ printascii("LPDDR4");
+ break;
+ default:
+ printascii("Unknown Device");
+ break;
+ }
+}
+
+/**
+ * cs = 0, cs0
+ * cs = 1, cs1
+ * cs => 2, cs0+cs1
+ * note: it didn't consider about row_3_4
+ */
+u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
+{
+ u32 bg;
+ u64 cap[2];
+
+ if (dram_type == DDR4)
+ /* DDR4 8bit dram BG = 2(4bank groups),
+ * 16bit dram BG = 1 (2 bank groups)
+ */
+ bg = (cap_info->dbw == 0) ? 2 : 1;
+ else
+ bg = 0;
+
+ cap[0] = 1llu << (cap_info->bw + cap_info->col +
+ bg + cap_info->bk + cap_info->cs0_row);
+
+ if (cap_info->rank == 2)
+ cap[1] = 1llu << (cap_info->bw + cap_info->col +
+ bg + cap_info->bk + cap_info->cs1_row);
+ else
+ cap[1] = 0;
+
+ if (cs == 0)
+ return cap[0];
+ else if (cs == 1)
+ return cap[1];
+ else
+ return (cap[0] + cap[1]);
+}
+
+void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
+ struct sdram_base_params *base)
+{
+ u32 bg, cap;
+
+ bg = (cap_info->dbw == 0) ? 2 : 1;
+
+ sdram_print_dram_type(base->dramtype);
+
+ printascii(", ");
+ printdec(base->ddr_freq);
+ printascii("MHz\n");
+
+ printascii("BW=");
+ printdec(8 << cap_info->bw);
+
+ printascii(" Col=");
+ printdec(cap_info->col);
+
+ printascii(" Bk=");
+ printdec(0x1 << cap_info->bk);
+ if (base->dramtype == DDR4) {
+ printascii(" BG=");
+ printdec(1 << bg);
+ }
+
+ printascii(" CS0 Row=");
+ printdec(cap_info->cs0_row);
+ if (cap_info->rank > 1) {
+ printascii(" CS1 Row=");
+ printdec(cap_info->cs1_row);
+ }
+
+ printascii(" CS=");
+ printdec(cap_info->rank);
+
+ printascii(" Die BW=");
+ printdec(8 << cap_info->dbw);
+
+ cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
+ if (cap_info->row_3_4)
+ cap = cap * 3 / 4;
+
+ printascii(" Size=");
+ printdec(cap >> 20);
+ printascii("MB\n");
+}
+
+void sdram_print_stride(unsigned int stride)
+{
+ switch (stride) {
+ case 0xc:
+ printf("128B stride\n");
+ break;
+ case 5:
+ case 9:
+ case 0xd:
+ case 0x11:
+ case 0x19:
+ printf("256B stride\n");
+ break;
+ case 0xa:
+ case 0xe:
+ case 0x12:
+ printf("512B stride\n");
+ break;
+ case 0xf:
+ printf("4K stride\n");
+ break;
+ case 0x1f:
+ printf("32MB + 256B stride\n");
+ break;
+ default:
+ printf("no stride\n");
+ }
+}
diff --git a/drivers/ram/rockchip/sdram_rk322x.c b/drivers/ram/rockchip/sdram_rk322x.c
index e96ac54..94893e1 100644
--- a/drivers/ram/rockchip/sdram_rk322x.c
+++ b/drivers/ram/rockchip/sdram_rk322x.c
@@ -16,7 +16,6 @@
#include <asm/arch-rockchip/grf_rk322x.h>
#include <asm/arch-rockchip/hardware.h>
#include <asm/arch-rockchip/sdram_rk322x.h>
-#include <asm/arch-rockchip/timer.h>
#include <asm/arch-rockchip/uart.h>
#include <asm/arch-rockchip/sdram_common.h>
#include <asm/types.h>
@@ -96,26 +95,26 @@
1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT |
1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
rk_clrreg(&cru->cru_softrst_con[5], 1 << DDRPHY_PSRST_SHIFT |
1 << DDRPHY_SRST_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
rk_clrreg(&cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT |
1 << DDRCTRL_SRST_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
clrbits_le32(&ddr_phy->ddrphy_reg[0],
SOFT_RESET_MASK << SOFT_RESET_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
setbits_le32(&ddr_phy->ddrphy_reg[0],
SOFT_DERESET_ANALOG);
- rockchip_udelay(5);
+ udelay(5);
setbits_le32(&ddr_phy->ddrphy_reg[0],
SOFT_DERESET_DIGITAL);
- rockchip_udelay(1);
+ udelay(1);
}
void phy_dll_bypass_set(struct rk322x_ddr_phy *ddr_phy, u32 freq)
@@ -154,7 +153,7 @@
u32 rank, u32 cmd, u32 arg)
{
writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd);
- rockchip_udelay(1);
+ udelay(1);
while (readl(&pctl->mcmd) & START_CMD)
;
}
@@ -167,7 +166,7 @@
if (dramtype == DDR3) {
send_command(pctl, 3, DESELECT_CMD, 0);
- rockchip_udelay(1);
+ udelay(1);
send_command(pctl, 3, PREA_CMD, 0);
send_command(pctl, 3, MRS_CMD,
(0x02 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
@@ -196,17 +195,17 @@
(0x63 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
(0 & LPDDR23_OP_MASK) <<
LPDDR23_OP_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
send_command(pctl, 3, MRS_CMD,
(0x10 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
(0xff & LPDDR23_OP_MASK) <<
LPDDR23_OP_SHIFT);
- rockchip_udelay(1);
+ udelay(1);
send_command(pctl, 3, MRS_CMD,
(0x10 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
(0xff & LPDDR23_OP_MASK) <<
LPDDR23_OP_SHIFT);
- rockchip_udelay(1);
+ udelay(1);
send_command(pctl, 3, MRS_CMD,
(1 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
(sdram_params->phy_timing.mr[1] &
@@ -243,7 +242,7 @@
DQS_SQU_CAL_SEL_CS0);
setbits_le32(&ddr_phy->ddrphy_reg[2], DQS_SQU_CAL_START);
- rockchip_udelay(30);
+ udelay(30);
ret = readl(&ddr_phy->ddrphy_reg[0xff]);
clrbits_le32(&ddr_phy->ddrphy_reg[2],
@@ -367,9 +366,9 @@
writel(GRF_DDRPHY_BUFFEREN_CORE_EN, &grf->soc_con[0]);
clrbits_le32(&ddr_phy->ddrphy_reg[0], 0x3 << 2);
- rockchip_udelay(1);
+ udelay(1);
setbits_le32(&ddr_phy->ddrphy_reg[0], 1 << 2);
- rockchip_udelay(5);
+ udelay(5);
setbits_le32(&ddr_phy->ddrphy_reg[0], 1 << 3);
writel(GRF_DDRPHY_BUFFEREN_CORE_DIS, &grf->soc_con[0]);
}
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c
index 5251865..81fc71c 100644
--- a/drivers/ram/rockchip/sdram_rk3399.c
+++ b/drivers/ram/rockchip/sdram_rk3399.c
@@ -14,14 +14,40 @@
#include <syscon.h>
#include <asm/io.h>
#include <asm/arch-rockchip/clock.h>
-#include <asm/arch-rockchip/sdram_common.h>
-#include <asm/arch-rockchip/sdram_rk3399.h>
#include <asm/arch-rockchip/cru_rk3399.h>
#include <asm/arch-rockchip/grf_rk3399.h>
+#include <asm/arch-rockchip/pmu_rk3399.h>
#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram_rk3399.h>
#include <linux/err.h>
#include <time.h>
+#define PRESET_SGRF_HOLD(n) ((0x1 << (6 + 16)) | ((n) << 6))
+#define PRESET_GPIO0_HOLD(n) ((0x1 << (7 + 16)) | ((n) << 7))
+#define PRESET_GPIO1_HOLD(n) ((0x1 << (8 + 16)) | ((n) << 8))
+
+#define PHY_DRV_ODT_HI_Z 0x0
+#define PHY_DRV_ODT_240 0x1
+#define PHY_DRV_ODT_120 0x8
+#define PHY_DRV_ODT_80 0x9
+#define PHY_DRV_ODT_60 0xc
+#define PHY_DRV_ODT_48 0xd
+#define PHY_DRV_ODT_40 0xe
+#define PHY_DRV_ODT_34_3 0xf
+
+#define PHY_BOOSTP_EN 0x1
+#define PHY_BOOSTN_EN 0x1
+#define PHY_SLEWP_EN 0x1
+#define PHY_SLEWN_EN 0x1
+#define PHY_RX_CM_INPUT 0x1
+#define CS0_MR22_VAL 0
+#define CS1_MR22_VAL 3
+
+#define CRU_SFTRST_DDR_CTRL(ch, n) ((0x1 << (8 + 16 + (ch) * 4)) | \
+ ((n) << (8 + (ch) * 4)))
+#define CRU_SFTRST_DDR_PHY(ch, n) ((0x1 << (9 + 16 + (ch) * 4)) | \
+ ((n) << (9 + (ch) * 4)))
struct chan_info {
struct rk3399_ddr_pctl_regs *pctl;
struct rk3399_ddr_pi_regs *pi;
@@ -32,29 +58,27 @@
struct dram_info {
#if defined(CONFIG_TPL_BUILD) || \
(!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
+ u32 pwrup_srefresh_exit[2];
struct chan_info chan[2];
struct clk ddr_clk;
struct rk3399_cru *cru;
+ struct rk3399_grf_regs *grf;
+ struct rk3399_pmu_regs *pmu;
struct rk3399_pmucru *pmucru;
struct rk3399_pmusgrf_regs *pmusgrf;
struct rk3399_ddr_cic_regs *cic;
+ const struct sdram_rk3399_ops *ops;
#endif
struct ram_info info;
struct rk3399_pmugrf_regs *pmugrf;
};
-#define PRESET_SGRF_HOLD(n) ((0x1 << (6 + 16)) | ((n) << 6))
-#define PRESET_GPIO0_HOLD(n) ((0x1 << (7 + 16)) | ((n) << 7))
-#define PRESET_GPIO1_HOLD(n) ((0x1 << (8 + 16)) | ((n) << 8))
-
-#define PHY_DRV_ODT_Hi_Z 0x0
-#define PHY_DRV_ODT_240 0x1
-#define PHY_DRV_ODT_120 0x8
-#define PHY_DRV_ODT_80 0x9
-#define PHY_DRV_ODT_60 0xc
-#define PHY_DRV_ODT_48 0xd
-#define PHY_DRV_ODT_40 0xe
-#define PHY_DRV_ODT_34_3 0xf
+struct sdram_rk3399_ops {
+ int (*data_training)(struct dram_info *dram, u32 channel, u8 rank,
+ struct rk3399_sdram_params *sdram);
+ int (*set_rate)(struct dram_info *dram,
+ struct rk3399_sdram_params *params);
+};
#if defined(CONFIG_TPL_BUILD) || \
(!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
@@ -68,6 +92,154 @@
struct regmap *map;
};
+struct io_setting {
+ u32 mhz;
+ u32 mr5;
+ /* dram side */
+ u32 dq_odt;
+ u32 ca_odt;
+ u32 pdds;
+ u32 dq_vref;
+ u32 ca_vref;
+ /* phy side */
+ u32 rd_odt;
+ u32 wr_dq_drv;
+ u32 wr_ca_drv;
+ u32 wr_ckcs_drv;
+ u32 rd_odt_en;
+ u32 rd_vref;
+} lpddr4_io_setting[] = {
+ {
+ 50 * MHz,
+ 0,
+ /* dram side */
+ 0, /* dq_odt; */
+ 0, /* ca_odt; */
+ 6, /* pdds; */
+ 0x72, /* dq_vref; */
+ 0x72, /* ca_vref; */
+ /* phy side */
+ PHY_DRV_ODT_HI_Z, /* rd_odt; */
+ PHY_DRV_ODT_40, /* wr_dq_drv; */
+ PHY_DRV_ODT_40, /* wr_ca_drv; */
+ PHY_DRV_ODT_40, /* wr_ckcs_drv; */
+ 0, /* rd_odt_en;*/
+ 41, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ },
+ {
+ 600 * MHz,
+ 0,
+ /* dram side */
+ 1, /* dq_odt; */
+ 0, /* ca_odt; */
+ 6, /* pdds; */
+ 0x72, /* dq_vref; */
+ 0x72, /* ca_vref; */
+ /* phy side */
+ PHY_DRV_ODT_HI_Z, /* rd_odt; */
+ PHY_DRV_ODT_48, /* wr_dq_drv; */
+ PHY_DRV_ODT_40, /* wr_ca_drv; */
+ PHY_DRV_ODT_40, /* wr_ckcs_drv; */
+ 0, /* rd_odt_en; */
+ 32, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ },
+ {
+ 800 * MHz,
+ 0,
+ /* dram side */
+ 1, /* dq_odt; */
+ 0, /* ca_odt; */
+ 1, /* pdds; */
+ 0x72, /* dq_vref; */
+ 0x72, /* ca_vref; */
+ /* phy side */
+ PHY_DRV_ODT_40, /* rd_odt; */
+ PHY_DRV_ODT_48, /* wr_dq_drv; */
+ PHY_DRV_ODT_40, /* wr_ca_drv; */
+ PHY_DRV_ODT_40, /* wr_ckcs_drv; */
+ 1, /* rd_odt_en; */
+ 17, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ },
+ {
+ 933 * MHz,
+ 0,
+ /* dram side */
+ 3, /* dq_odt; */
+ 0, /* ca_odt; */
+ 6, /* pdds; */
+ 0x59, /* dq_vref; 32% */
+ 0x72, /* ca_vref; */
+ /* phy side */
+ PHY_DRV_ODT_HI_Z, /* rd_odt; */
+ PHY_DRV_ODT_48, /* wr_dq_drv; */
+ PHY_DRV_ODT_40, /* wr_ca_drv; */
+ PHY_DRV_ODT_40, /* wr_ckcs_drv; */
+ 0, /* rd_odt_en; */
+ 32, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ },
+ {
+ 1066 * MHz,
+ 0,
+ /* dram side */
+ 6, /* dq_odt; */
+ 0, /* ca_odt; */
+ 1, /* pdds; */
+ 0x10, /* dq_vref; */
+ 0x72, /* ca_vref; */
+ /* phy side */
+ PHY_DRV_ODT_40, /* rd_odt; */
+ PHY_DRV_ODT_60, /* wr_dq_drv; */
+ PHY_DRV_ODT_40, /* wr_ca_drv; */
+ PHY_DRV_ODT_40, /* wr_ckcs_drv; */
+ 1, /* rd_odt_en; */
+ 17, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ },
+};
+
+/**
+ * phy = 0, PHY boot freq
+ * phy = 1, PHY index 0
+ * phy = 2, PHY index 1
+ */
+static struct io_setting *
+lpddr4_get_io_settings(const struct rk3399_sdram_params *params, u32 mr5)
+{
+ struct io_setting *io = NULL;
+ u32 n;
+
+ for (n = 0; n < ARRAY_SIZE(lpddr4_io_setting); n++) {
+ io = &lpddr4_io_setting[n];
+
+ if (io->mr5 != 0) {
+ if (io->mhz >= params->base.ddr_freq &&
+ io->mr5 == mr5)
+ break;
+ } else {
+ if (io->mhz >= params->base.ddr_freq)
+ break;
+ }
+ }
+
+ return io;
+}
+
+static void *get_denali_phy(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, bool reg)
+{
+ return reg ? &chan->publ->denali_phy : ¶ms->phy_regs.denali_phy;
+}
+
+static void *get_denali_ctl(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, bool reg)
+{
+ return reg ? &chan->pctl->denali_ctl : ¶ms->pctl_regs.denali_ctl;
+}
+
+static void *get_ddrc0_con(struct dram_info *dram, u8 channel)
+{
+ return (channel == 0) ? &dram->grf->ddrc0_con0 : &dram->grf->ddrc0_con1;
+}
+
static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
{
int i;
@@ -79,6 +251,29 @@
}
}
+static void rkclk_ddr_reset(struct rk3399_cru *cru, u32 channel, u32 ctl,
+ u32 phy)
+{
+ channel &= 0x1;
+ ctl &= 0x1;
+ phy &= 0x1;
+ writel(CRU_SFTRST_DDR_CTRL(channel, ctl) |
+ CRU_SFTRST_DDR_PHY(channel, phy),
+ &cru->softrst_con[4]);
+}
+
+static void phy_pctrl_reset(struct rk3399_cru *cru, u32 channel)
+{
+ rkclk_ddr_reset(cru, channel, 1, 1);
+ udelay(10);
+
+ rkclk_ddr_reset(cru, channel, 1, 0);
+ udelay(10);
+
+ rkclk_ddr_reset(cru, channel, 0, 0);
+ udelay(10);
+}
+
static void phy_dll_bypass_set(struct rk3399_ddr_publ_regs *ddr_publ_regs,
u32 freq)
{
@@ -111,10 +306,9 @@
}
static void set_memory_map(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
- const struct rk3399_sdram_channel *sdram_ch =
- &sdram_params->ch[channel];
+ const struct rk3399_sdram_channel *sdram_ch = ¶ms->ch[channel];
u32 *denali_ctl = chan->pctl->denali_ctl;
u32 *denali_pi = chan->pi->denali_pi;
u32 cs_map;
@@ -122,179 +316,51 @@
u32 row;
/* Get row number from ddrconfig setting */
- if (sdram_ch->ddrconfig < 2 || sdram_ch->ddrconfig == 4)
+ if (sdram_ch->cap_info.ddrconfig < 2 ||
+ sdram_ch->cap_info.ddrconfig == 4)
row = 16;
- else if (sdram_ch->ddrconfig == 3)
+ else if (sdram_ch->cap_info.ddrconfig == 3)
row = 14;
else
row = 15;
- cs_map = (sdram_ch->rank > 1) ? 3 : 1;
- reduc = (sdram_ch->bw == 2) ? 0 : 1;
+ cs_map = (sdram_ch->cap_info.rank > 1) ? 3 : 1;
+ reduc = (sdram_ch->cap_info.bw == 2) ? 0 : 1;
/* Set the dram configuration to ctrl */
- clrsetbits_le32(&denali_ctl[191], 0xF, (12 - sdram_ch->col));
+ clrsetbits_le32(&denali_ctl[191], 0xF, (12 - sdram_ch->cap_info.col));
clrsetbits_le32(&denali_ctl[190], (0x3 << 16) | (0x7 << 24),
- ((3 - sdram_ch->bk) << 16) |
+ ((3 - sdram_ch->cap_info.bk) << 16) |
((16 - row) << 24));
clrsetbits_le32(&denali_ctl[196], 0x3 | (1 << 16),
cs_map | (reduc << 16));
/* PI_199 PI_COL_DIFF:RW:0:4 */
- clrsetbits_le32(&denali_pi[199], 0xF, (12 - sdram_ch->col));
+ clrsetbits_le32(&denali_pi[199], 0xF, (12 - sdram_ch->cap_info.col));
/* PI_155 PI_ROW_DIFF:RW:24:3 PI_BANK_DIFF:RW:16:2 */
clrsetbits_le32(&denali_pi[155], (0x3 << 16) | (0x7 << 24),
- ((3 - sdram_ch->bk) << 16) |
+ ((3 - sdram_ch->cap_info.bk) << 16) |
((16 - row) << 24));
- /* PI_41 PI_CS_MAP:RW:24:4 */
- clrsetbits_le32(&denali_pi[41], 0xf << 24, cs_map << 24);
- if ((sdram_ch->rank == 1) && (sdram_params->base.dramtype == DDR3))
- writel(0x2EC7FFFF, &denali_pi[34]);
-}
-
-static void set_ds_odt(const struct chan_info *chan,
- const struct rk3399_sdram_params *sdram_params)
-{
- u32 *denali_phy = chan->publ->denali_phy;
-
- u32 tsel_idle_en, tsel_wr_en, tsel_rd_en;
- u32 tsel_idle_select_p, tsel_wr_select_p, tsel_rd_select_p;
- u32 ca_tsel_wr_select_p, ca_tsel_wr_select_n;
- u32 tsel_idle_select_n, tsel_wr_select_n, tsel_rd_select_n;
- u32 reg_value;
-
- if (sdram_params->base.dramtype == LPDDR4) {
- tsel_rd_select_p = PHY_DRV_ODT_Hi_Z;
- tsel_wr_select_p = PHY_DRV_ODT_40;
- ca_tsel_wr_select_p = PHY_DRV_ODT_40;
- tsel_idle_select_p = PHY_DRV_ODT_Hi_Z;
-
- tsel_rd_select_n = PHY_DRV_ODT_240;
- tsel_wr_select_n = PHY_DRV_ODT_40;
- ca_tsel_wr_select_n = PHY_DRV_ODT_40;
- tsel_idle_select_n = PHY_DRV_ODT_240;
- } else if (sdram_params->base.dramtype == LPDDR3) {
- tsel_rd_select_p = PHY_DRV_ODT_240;
- tsel_wr_select_p = PHY_DRV_ODT_34_3;
- ca_tsel_wr_select_p = PHY_DRV_ODT_48;
- tsel_idle_select_p = PHY_DRV_ODT_240;
-
- tsel_rd_select_n = PHY_DRV_ODT_Hi_Z;
- tsel_wr_select_n = PHY_DRV_ODT_34_3;
- ca_tsel_wr_select_n = PHY_DRV_ODT_48;
- tsel_idle_select_n = PHY_DRV_ODT_Hi_Z;
- } else {
- tsel_rd_select_p = PHY_DRV_ODT_240;
- tsel_wr_select_p = PHY_DRV_ODT_34_3;
- ca_tsel_wr_select_p = PHY_DRV_ODT_34_3;
- tsel_idle_select_p = PHY_DRV_ODT_240;
- tsel_rd_select_n = PHY_DRV_ODT_240;
- tsel_wr_select_n = PHY_DRV_ODT_34_3;
- ca_tsel_wr_select_n = PHY_DRV_ODT_34_3;
- tsel_idle_select_n = PHY_DRV_ODT_240;
+ if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ if (cs_map == 1)
+ cs_map = 0x5;
+ else if (cs_map == 2)
+ cs_map = 0xa;
+ else
+ cs_map = 0xF;
}
- if (sdram_params->base.odt == 1)
- tsel_rd_en = 1;
- else
- tsel_rd_en = 0;
-
- tsel_wr_en = 0;
- tsel_idle_en = 0;
-
- /*
- * phy_dq_tsel_select_X 24bits DENALI_PHY_6/134/262/390 offset_0
- * sets termination values for read/idle cycles and drive strength
- * for write cycles for DQ/DM
- */
- reg_value = tsel_rd_select_n | (tsel_rd_select_p << 0x4) |
- (tsel_wr_select_n << 8) | (tsel_wr_select_p << 12) |
- (tsel_idle_select_n << 16) | (tsel_idle_select_p << 20);
- clrsetbits_le32(&denali_phy[6], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[134], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[262], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[390], 0xffffff, reg_value);
-
- /*
- * phy_dqs_tsel_select_X 24bits DENALI_PHY_7/135/263/391 offset_0
- * sets termination values for read/idle cycles and drive strength
- * for write cycles for DQS
- */
- clrsetbits_le32(&denali_phy[7], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[135], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[263], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[391], 0xffffff, reg_value);
-
- /* phy_adr_tsel_select_ 8bits DENALI_PHY_544/672/800 offset_0 */
- reg_value = ca_tsel_wr_select_n | (ca_tsel_wr_select_p << 0x4);
- clrsetbits_le32(&denali_phy[544], 0xff, reg_value);
- clrsetbits_le32(&denali_phy[672], 0xff, reg_value);
- clrsetbits_le32(&denali_phy[800], 0xff, reg_value);
-
- /* phy_pad_addr_drive 8bits DENALI_PHY_928 offset_0 */
- clrsetbits_le32(&denali_phy[928], 0xff, reg_value);
-
- /* phy_pad_rst_drive 8bits DENALI_PHY_937 offset_0 */
- clrsetbits_le32(&denali_phy[937], 0xff, reg_value);
-
- /* phy_pad_cke_drive 8bits DENALI_PHY_935 offset_0 */
- clrsetbits_le32(&denali_phy[935], 0xff, reg_value);
-
- /* phy_pad_cs_drive 8bits DENALI_PHY_939 offset_0 */
- clrsetbits_le32(&denali_phy[939], 0xff, reg_value);
-
- /* phy_pad_clk_drive 8bits DENALI_PHY_929 offset_0 */
- clrsetbits_le32(&denali_phy[929], 0xff, reg_value);
-
- /* phy_pad_fdbk_drive 23bit DENALI_PHY_924/925 */
- clrsetbits_le32(&denali_phy[924], 0xff,
- tsel_wr_select_n | (tsel_wr_select_p << 4));
- clrsetbits_le32(&denali_phy[925], 0xff,
- tsel_rd_select_n | (tsel_rd_select_p << 4));
-
- /* phy_dq_tsel_enable_X 3bits DENALI_PHY_5/133/261/389 offset_16 */
- reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
- << 16;
- clrsetbits_le32(&denali_phy[5], 0x7 << 16, reg_value);
- clrsetbits_le32(&denali_phy[133], 0x7 << 16, reg_value);
- clrsetbits_le32(&denali_phy[261], 0x7 << 16, reg_value);
- clrsetbits_le32(&denali_phy[389], 0x7 << 16, reg_value);
-
- /* phy_dqs_tsel_enable_X 3bits DENALI_PHY_6/134/262/390 offset_24 */
- reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
- << 24;
- clrsetbits_le32(&denali_phy[6], 0x7 << 24, reg_value);
- clrsetbits_le32(&denali_phy[134], 0x7 << 24, reg_value);
- clrsetbits_le32(&denali_phy[262], 0x7 << 24, reg_value);
- clrsetbits_le32(&denali_phy[390], 0x7 << 24, reg_value);
-
- /* phy_adr_tsel_enable_ 1bit DENALI_PHY_518/646/774 offset_8 */
- reg_value = tsel_wr_en << 8;
- clrsetbits_le32(&denali_phy[518], 0x1 << 8, reg_value);
- clrsetbits_le32(&denali_phy[646], 0x1 << 8, reg_value);
- clrsetbits_le32(&denali_phy[774], 0x1 << 8, reg_value);
-
- /* phy_pad_addr_term tsel 1bit DENALI_PHY_933 offset_17 */
- reg_value = tsel_wr_en << 17;
- clrsetbits_le32(&denali_phy[933], 0x1 << 17, reg_value);
- /*
- * pad_rst/cke/cs/clk_term tsel 1bits
- * DENALI_PHY_938/936/940/934 offset_17
- */
- clrsetbits_le32(&denali_phy[938], 0x1 << 17, reg_value);
- clrsetbits_le32(&denali_phy[936], 0x1 << 17, reg_value);
- clrsetbits_le32(&denali_phy[940], 0x1 << 17, reg_value);
- clrsetbits_le32(&denali_phy[934], 0x1 << 17, reg_value);
-
- /* phy_pad_fdbk_term 1bit DENALI_PHY_930 offset_17 */
- clrsetbits_le32(&denali_phy[930], 0x1 << 17, reg_value);
+ /* PI_41 PI_CS_MAP:RW:24:4 */
+ clrsetbits_le32(&denali_pi[41], 0xf << 24, cs_map << 24);
+ if (sdram_ch->cap_info.rank == 1 && params->base.dramtype == DDR3)
+ writel(0x2EC7FFFF, &denali_pi[34]);
}
static int phy_io_config(const struct chan_info *chan,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params, u32 mr5)
{
u32 *denali_phy = chan->publ->denali_phy;
u32 vref_mode_dq, vref_value_dq, vref_mode_ac, vref_value_ac;
@@ -303,15 +369,29 @@
u32 drv_value, odt_value;
u32 speed;
- /* vref setting */
- if (sdram_params->base.dramtype == LPDDR4) {
- /* LPDDR4 */
- vref_mode_dq = 0x6;
- vref_value_dq = 0x1f;
+ /* vref setting & mode setting */
+ if (params->base.dramtype == LPDDR4) {
+ struct io_setting *io = lpddr4_get_io_settings(params, mr5);
+ u32 rd_vref = io->rd_vref * 1000;
+
+ if (rd_vref < 36700) {
+ /* MODE_LV[2:0] = LPDDR4 (Range 2)*/
+ vref_mode_dq = 0x7;
+ /* MODE[2:0]= LPDDR4 Range 2(0.4*VDDQ) */
+ mode_sel = 0x5;
+ vref_value_dq = (rd_vref - 3300) / 521;
+ } else {
+ /* MODE_LV[2:0] = LPDDR4 (Range 1)*/
+ vref_mode_dq = 0x6;
+ /* MODE[2:0]= LPDDR4 Range 1(0.33*VDDQ) */
+ mode_sel = 0x4;
+ vref_value_dq = (rd_vref - 15300) / 521;
+ }
vref_mode_ac = 0x6;
- vref_value_ac = 0x1f;
- } else if (sdram_params->base.dramtype == LPDDR3) {
- if (sdram_params->base.odt == 1) {
+ /* VDDQ/3/2=16.8% */
+ vref_value_ac = 0x3;
+ } else if (params->base.dramtype == LPDDR3) {
+ if (params->base.odt == 1) {
vref_mode_dq = 0x5; /* LPDDR3 ODT */
drv_value = (readl(&denali_phy[6]) >> 12) & 0xf;
odt_value = (readl(&denali_phy[6]) >> 4) & 0xf;
@@ -370,12 +450,14 @@
}
vref_mode_ac = 0x2;
vref_value_ac = 0x1f;
- } else if (sdram_params->base.dramtype == DDR3) {
+ mode_sel = 0x0;
+ } else if (params->base.dramtype == DDR3) {
/* DDR3L */
vref_mode_dq = 0x1;
vref_value_dq = 0x1f;
vref_mode_ac = 0x1;
vref_value_ac = 0x1f;
+ mode_sel = 0x1;
} else {
debug("Unknown DRAM type.\n");
return -EINVAL;
@@ -397,15 +479,6 @@
/* PHY_915 PHY_PAD_VREF_CTRL_AC 12bits offset_16 */
clrsetbits_le32(&denali_phy[915], 0xfff << 16, reg_value << 16);
- if (sdram_params->base.dramtype == LPDDR4)
- mode_sel = 0x6;
- else if (sdram_params->base.dramtype == LPDDR3)
- mode_sel = 0x0;
- else if (sdram_params->base.dramtype == DDR3)
- mode_sel = 0x1;
- else
- return -EINVAL;
-
/* PHY_924 PHY_PAD_FDBK_DRIVE */
clrsetbits_le32(&denali_phy[924], 0x7 << 15, mode_sel << 15);
/* PHY_926 PHY_PAD_DATA_DRIVE */
@@ -423,13 +496,52 @@
/* PHY_939 PHY_PAD_CS_DRIVE */
clrsetbits_le32(&denali_phy[939], 0x7 << 14, mode_sel << 14);
+ if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ /* BOOSTP_EN & BOOSTN_EN */
+ reg_value = ((PHY_BOOSTP_EN << 4) | PHY_BOOSTN_EN);
+ /* PHY_925 PHY_PAD_FDBK_DRIVE2 */
+ clrsetbits_le32(&denali_phy[925], 0xff << 8, reg_value << 8);
+ /* PHY_926 PHY_PAD_DATA_DRIVE */
+ clrsetbits_le32(&denali_phy[926], 0xff << 12, reg_value << 12);
+ /* PHY_927 PHY_PAD_DQS_DRIVE */
+ clrsetbits_le32(&denali_phy[927], 0xff << 14, reg_value << 14);
+ /* PHY_928 PHY_PAD_ADDR_DRIVE */
+ clrsetbits_le32(&denali_phy[928], 0xff << 20, reg_value << 20);
+ /* PHY_929 PHY_PAD_CLK_DRIVE */
+ clrsetbits_le32(&denali_phy[929], 0xff << 22, reg_value << 22);
+ /* PHY_935 PHY_PAD_CKE_DRIVE */
+ clrsetbits_le32(&denali_phy[935], 0xff << 20, reg_value << 20);
+ /* PHY_937 PHY_PAD_RST_DRIVE */
+ clrsetbits_le32(&denali_phy[937], 0xff << 20, reg_value << 20);
+ /* PHY_939 PHY_PAD_CS_DRIVE */
+ clrsetbits_le32(&denali_phy[939], 0xff << 20, reg_value << 20);
+
+ /* SLEWP_EN & SLEWN_EN */
+ reg_value = ((PHY_SLEWP_EN << 3) | PHY_SLEWN_EN);
+ /* PHY_924 PHY_PAD_FDBK_DRIVE */
+ clrsetbits_le32(&denali_phy[924], 0x3f << 8, reg_value << 8);
+ /* PHY_926 PHY_PAD_DATA_DRIVE */
+ clrsetbits_le32(&denali_phy[926], 0x3f, reg_value);
+ /* PHY_927 PHY_PAD_DQS_DRIVE */
+ clrsetbits_le32(&denali_phy[927], 0x3f, reg_value);
+ /* PHY_928 PHY_PAD_ADDR_DRIVE */
+ clrsetbits_le32(&denali_phy[928], 0x3f << 8, reg_value << 8);
+ /* PHY_929 PHY_PAD_CLK_DRIVE */
+ clrsetbits_le32(&denali_phy[929], 0x3f << 8, reg_value << 8);
+ /* PHY_935 PHY_PAD_CKE_DRIVE */
+ clrsetbits_le32(&denali_phy[935], 0x3f << 8, reg_value << 8);
+ /* PHY_937 PHY_PAD_RST_DRIVE */
+ clrsetbits_le32(&denali_phy[937], 0x3f << 8, reg_value << 8);
+ /* PHY_939 PHY_PAD_CS_DRIVE */
+ clrsetbits_le32(&denali_phy[939], 0x3f << 8, reg_value << 8);
+ }
/* speed setting */
- if (sdram_params->base.ddr_freq < 400)
+ if (params->base.ddr_freq < 400)
speed = 0x0;
- else if (sdram_params->base.ddr_freq < 800)
+ else if (params->base.ddr_freq < 800)
speed = 0x1;
- else if (sdram_params->base.ddr_freq < 1200)
+ else if (params->base.ddr_freq < 1200)
speed = 0x2;
else
speed = 0x3;
@@ -451,115 +563,406 @@
/* PHY_939 PHY_PAD_CS_DRIVE */
clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17);
+ if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ /* RX_CM_INPUT */
+ reg_value = PHY_RX_CM_INPUT;
+ /* PHY_924 PHY_PAD_FDBK_DRIVE */
+ clrsetbits_le32(&denali_phy[924], 0x1 << 14, reg_value << 14);
+ /* PHY_926 PHY_PAD_DATA_DRIVE */
+ clrsetbits_le32(&denali_phy[926], 0x1 << 11, reg_value << 11);
+ /* PHY_927 PHY_PAD_DQS_DRIVE */
+ clrsetbits_le32(&denali_phy[927], 0x1 << 13, reg_value << 13);
+ /* PHY_928 PHY_PAD_ADDR_DRIVE */
+ clrsetbits_le32(&denali_phy[928], 0x1 << 19, reg_value << 19);
+ /* PHY_929 PHY_PAD_CLK_DRIVE */
+ clrsetbits_le32(&denali_phy[929], 0x1 << 21, reg_value << 21);
+ /* PHY_935 PHY_PAD_CKE_DRIVE */
+ clrsetbits_le32(&denali_phy[935], 0x1 << 19, reg_value << 19);
+ /* PHY_937 PHY_PAD_RST_DRIVE */
+ clrsetbits_le32(&denali_phy[937], 0x1 << 19, reg_value << 19);
+ /* PHY_939 PHY_PAD_CS_DRIVE */
+ clrsetbits_le32(&denali_phy[939], 0x1 << 19, reg_value << 19);
+ }
+
return 0;
}
-static int pctl_cfg(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+static void set_ds_odt(const struct chan_info *chan,
+ struct rk3399_sdram_params *params,
+ bool ctl_phy_reg, u32 mr5)
{
- u32 *denali_ctl = chan->pctl->denali_ctl;
- u32 *denali_pi = chan->pi->denali_pi;
- u32 *denali_phy = chan->publ->denali_phy;
- const u32 *params_ctl = sdram_params->pctl_regs.denali_ctl;
- const u32 *params_phy = sdram_params->phy_regs.denali_phy;
- u32 tmp, tmp1, tmp2;
- u32 pwrup_srefresh_exit;
- int ret;
- const ulong timeout_ms = 200;
+ u32 *denali_phy = get_denali_phy(chan, params, ctl_phy_reg);
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 tsel_idle_en, tsel_wr_en, tsel_rd_en;
+ u32 tsel_idle_select_p, tsel_rd_select_p;
+ u32 tsel_idle_select_n, tsel_rd_select_n;
+ u32 tsel_wr_select_dq_p, tsel_wr_select_ca_p;
+ u32 tsel_wr_select_dq_n, tsel_wr_select_ca_n;
+ u32 tsel_ckcs_select_p, tsel_ckcs_select_n;
+ struct io_setting *io = NULL;
+ u32 soc_odt = 0;
+ u32 reg_value;
- /*
- * work around controller bug:
- * Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed
- */
- copy_to_reg(&denali_ctl[1], ¶ms_ctl[1],
- sizeof(struct rk3399_ddr_pctl_regs) - 4);
- writel(params_ctl[0], &denali_ctl[0]);
- copy_to_reg(denali_pi, &sdram_params->pi_regs.denali_pi[0],
- sizeof(struct rk3399_ddr_pi_regs));
- /* rank count need to set for init */
- set_memory_map(chan, channel, sdram_params);
+ if (params->base.dramtype == LPDDR4) {
+ io = lpddr4_get_io_settings(params, mr5);
- writel(sdram_params->phy_regs.denali_phy[910], &denali_phy[910]);
- writel(sdram_params->phy_regs.denali_phy[911], &denali_phy[911]);
- writel(sdram_params->phy_regs.denali_phy[912], &denali_phy[912]);
+ tsel_rd_select_p = PHY_DRV_ODT_HI_Z;
+ tsel_rd_select_n = io->rd_odt;
- pwrup_srefresh_exit = readl(&denali_ctl[68]) & PWRUP_SREFRESH_EXIT;
- clrbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT);
+ tsel_idle_select_p = PHY_DRV_ODT_HI_Z;
+ tsel_idle_select_n = PHY_DRV_ODT_240;
- /* PHY_DLL_RST_EN */
- clrsetbits_le32(&denali_phy[957], 0x3 << 24, 1 << 24);
+ tsel_wr_select_dq_p = io->wr_dq_drv;
+ tsel_wr_select_dq_n = PHY_DRV_ODT_40;
- setbits_le32(&denali_pi[0], START);
- setbits_le32(&denali_ctl[0], START);
+ tsel_wr_select_ca_p = io->wr_ca_drv;
+ tsel_wr_select_ca_n = PHY_DRV_ODT_40;
- /* Wating for phy DLL lock */
- while (1) {
- tmp = readl(&denali_phy[920]);
- tmp1 = readl(&denali_phy[921]);
- tmp2 = readl(&denali_phy[922]);
- if ((((tmp >> 16) & 0x1) == 0x1) &&
- (((tmp1 >> 16) & 0x1) == 0x1) &&
- (((tmp1 >> 0) & 0x1) == 0x1) &&
- (((tmp2 >> 0) & 0x1) == 0x1))
+ tsel_ckcs_select_p = io->wr_ckcs_drv;
+ tsel_ckcs_select_n = PHY_DRV_ODT_34_3;
+ switch (tsel_rd_select_n) {
+ case PHY_DRV_ODT_240:
+ soc_odt = 1;
break;
- }
+ case PHY_DRV_ODT_120:
+ soc_odt = 2;
+ break;
+ case PHY_DRV_ODT_80:
+ soc_odt = 3;
+ break;
+ case PHY_DRV_ODT_60:
+ soc_odt = 4;
+ break;
+ case PHY_DRV_ODT_48:
+ soc_odt = 5;
+ break;
+ case PHY_DRV_ODT_40:
+ soc_odt = 6;
+ break;
+ case PHY_DRV_ODT_34_3:
+ soc_odt = 6;
+ printf("%s: Unable to support LPDDR4 MR22 Soc ODT\n",
+ __func__);
+ break;
+ case PHY_DRV_ODT_HI_Z:
+ default:
+ soc_odt = 0;
+ break;
+ }
+ } else if (params->base.dramtype == LPDDR3) {
+ tsel_rd_select_p = PHY_DRV_ODT_240;
+ tsel_rd_select_n = PHY_DRV_ODT_HI_Z;
- copy_to_reg(&denali_phy[896], ¶ms_phy[896], (958 - 895) * 4);
- copy_to_reg(&denali_phy[0], ¶ms_phy[0], (90 - 0 + 1) * 4);
- copy_to_reg(&denali_phy[128], ¶ms_phy[128], (218 - 128 + 1) * 4);
- copy_to_reg(&denali_phy[256], ¶ms_phy[256], (346 - 256 + 1) * 4);
- copy_to_reg(&denali_phy[384], ¶ms_phy[384], (474 - 384 + 1) * 4);
- copy_to_reg(&denali_phy[512], ¶ms_phy[512], (549 - 512 + 1) * 4);
- copy_to_reg(&denali_phy[640], ¶ms_phy[640], (677 - 640 + 1) * 4);
- copy_to_reg(&denali_phy[768], ¶ms_phy[768], (805 - 768 + 1) * 4);
- set_ds_odt(chan, sdram_params);
+ tsel_idle_select_p = PHY_DRV_ODT_240;
+ tsel_idle_select_n = PHY_DRV_ODT_HI_Z;
- /*
- * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_84/212/340/468 offset_8
- * dqs_tsel_wr_end[7:4] add Half cycle
- */
- tmp = (readl(&denali_phy[84]) >> 8) & 0xff;
- clrsetbits_le32(&denali_phy[84], 0xff << 8, (tmp + 0x10) << 8);
- tmp = (readl(&denali_phy[212]) >> 8) & 0xff;
- clrsetbits_le32(&denali_phy[212], 0xff << 8, (tmp + 0x10) << 8);
- tmp = (readl(&denali_phy[340]) >> 8) & 0xff;
- clrsetbits_le32(&denali_phy[340], 0xff << 8, (tmp + 0x10) << 8);
- tmp = (readl(&denali_phy[468]) >> 8) & 0xff;
- clrsetbits_le32(&denali_phy[468], 0xff << 8, (tmp + 0x10) << 8);
+ tsel_wr_select_dq_p = PHY_DRV_ODT_34_3;
+ tsel_wr_select_dq_n = PHY_DRV_ODT_34_3;
- /*
- * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_83/211/339/467 offset_8
- * dq_tsel_wr_end[7:4] add Half cycle
- */
- tmp = (readl(&denali_phy[83]) >> 16) & 0xff;
- clrsetbits_le32(&denali_phy[83], 0xff << 16, (tmp + 0x10) << 16);
- tmp = (readl(&denali_phy[211]) >> 16) & 0xff;
- clrsetbits_le32(&denali_phy[211], 0xff << 16, (tmp + 0x10) << 16);
- tmp = (readl(&denali_phy[339]) >> 16) & 0xff;
- clrsetbits_le32(&denali_phy[339], 0xff << 16, (tmp + 0x10) << 16);
- tmp = (readl(&denali_phy[467]) >> 16) & 0xff;
- clrsetbits_le32(&denali_phy[467], 0xff << 16, (tmp + 0x10) << 16);
+ tsel_wr_select_ca_p = PHY_DRV_ODT_48;
+ tsel_wr_select_ca_n = PHY_DRV_ODT_48;
- ret = phy_io_config(chan, sdram_params);
- if (ret)
- return ret;
+ tsel_ckcs_select_p = PHY_DRV_ODT_34_3;
+ tsel_ckcs_select_n = PHY_DRV_ODT_34_3;
+ } else {
+ tsel_rd_select_p = PHY_DRV_ODT_240;
+ tsel_rd_select_n = PHY_DRV_ODT_240;
- /* PHY_DLL_RST_EN */
+ tsel_idle_select_p = PHY_DRV_ODT_240;
+ tsel_idle_select_n = PHY_DRV_ODT_240;
+
+ tsel_wr_select_dq_p = PHY_DRV_ODT_34_3;
+ tsel_wr_select_dq_n = PHY_DRV_ODT_34_3;
+
+ tsel_wr_select_ca_p = PHY_DRV_ODT_34_3;
+ tsel_wr_select_ca_n = PHY_DRV_ODT_34_3;
+
+ tsel_ckcs_select_p = PHY_DRV_ODT_34_3;
+ tsel_ckcs_select_n = PHY_DRV_ODT_34_3;
+ }
+
+ if (params->base.odt == 1) {
+ tsel_rd_en = 1;
+
+ if (params->base.dramtype == LPDDR4)
+ tsel_rd_en = io->rd_odt_en;
+ } else {
+ tsel_rd_en = 0;
+ }
+
+ tsel_wr_en = 0;
+ tsel_idle_en = 0;
+
+ /* F0_0 */
+ clrsetbits_le32(&denali_ctl[145], 0xFF << 16,
+ (soc_odt | (CS0_MR22_VAL << 3)) << 16);
+ /* F2_0, F1_0 */
+ clrsetbits_le32(&denali_ctl[146], 0xFF00FF,
+ ((soc_odt | (CS0_MR22_VAL << 3)) << 16) |
+ (soc_odt | (CS0_MR22_VAL << 3)));
+ /* F0_1 */
+ clrsetbits_le32(&denali_ctl[159], 0xFF << 16,
+ (soc_odt | (CS1_MR22_VAL << 3)) << 16);
+ /* F2_1, F1_1 */
+ clrsetbits_le32(&denali_ctl[160], 0xFF00FF,
+ ((soc_odt | (CS1_MR22_VAL << 3)) << 16) |
+ (soc_odt | (CS1_MR22_VAL << 3)));
+
+ /*
+ * phy_dq_tsel_select_X 24bits DENALI_PHY_6/134/262/390 offset_0
+ * sets termination values for read/idle cycles and drive strength
+ * for write cycles for DQ/DM
+ */
+ reg_value = tsel_rd_select_n | (tsel_rd_select_p << 0x4) |
+ (tsel_wr_select_dq_n << 8) | (tsel_wr_select_dq_p << 12) |
+ (tsel_idle_select_n << 16) | (tsel_idle_select_p << 20);
+ clrsetbits_le32(&denali_phy[6], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[134], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[262], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[390], 0xffffff, reg_value);
+
+ /*
+ * phy_dqs_tsel_select_X 24bits DENALI_PHY_7/135/263/391 offset_0
+ * sets termination values for read/idle cycles and drive strength
+ * for write cycles for DQS
+ */
+ clrsetbits_le32(&denali_phy[7], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[135], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[263], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[391], 0xffffff, reg_value);
+
+ /* phy_adr_tsel_select_ 8bits DENALI_PHY_544/672/800 offset_0 */
+ reg_value = tsel_wr_select_ca_n | (tsel_wr_select_ca_p << 0x4);
+ if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ /* LPDDR4 these register read always return 0, so
+ * can not use clrsetbits_le32(), need to write32
+ */
+ writel((0x300 << 8) | reg_value, &denali_phy[544]);
+ writel((0x300 << 8) | reg_value, &denali_phy[672]);
+ writel((0x300 << 8) | reg_value, &denali_phy[800]);
+ } else {
+ clrsetbits_le32(&denali_phy[544], 0xff, reg_value);
+ clrsetbits_le32(&denali_phy[672], 0xff, reg_value);
+ clrsetbits_le32(&denali_phy[800], 0xff, reg_value);
+ }
+
+ /* phy_pad_addr_drive 8bits DENALI_PHY_928 offset_0 */
+ clrsetbits_le32(&denali_phy[928], 0xff, reg_value);
+
+ /* phy_pad_rst_drive 8bits DENALI_PHY_937 offset_0 */
+ if (!ctl_phy_reg)
+ clrsetbits_le32(&denali_phy[937], 0xff, reg_value);
+
+ /* phy_pad_cke_drive 8bits DENALI_PHY_935 offset_0 */
+ clrsetbits_le32(&denali_phy[935], 0xff, reg_value);
+
+ /* phy_pad_cs_drive 8bits DENALI_PHY_939 offset_0 */
+ clrsetbits_le32(&denali_phy[939], 0xff,
+ tsel_ckcs_select_n | (tsel_ckcs_select_p << 0x4));
+
+ /* phy_pad_clk_drive 8bits DENALI_PHY_929 offset_0 */
+ clrsetbits_le32(&denali_phy[929], 0xff,
+ tsel_ckcs_select_n | (tsel_ckcs_select_p << 0x4));
+
+ /* phy_pad_fdbk_drive 23bit DENALI_PHY_924/925 */
+ clrsetbits_le32(&denali_phy[924], 0xff,
+ tsel_wr_select_dq_n | (tsel_wr_select_dq_p << 4));
+ clrsetbits_le32(&denali_phy[925], 0xff,
+ tsel_rd_select_n | (tsel_rd_select_p << 4));
+
+ /* phy_dq_tsel_enable_X 3bits DENALI_PHY_5/133/261/389 offset_16 */
+ reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
+ << 16;
+ clrsetbits_le32(&denali_phy[5], 0x7 << 16, reg_value);
+ clrsetbits_le32(&denali_phy[133], 0x7 << 16, reg_value);
+ clrsetbits_le32(&denali_phy[261], 0x7 << 16, reg_value);
+ clrsetbits_le32(&denali_phy[389], 0x7 << 16, reg_value);
+
+ /* phy_dqs_tsel_enable_X 3bits DENALI_PHY_6/134/262/390 offset_24 */
+ reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
+ << 24;
+ clrsetbits_le32(&denali_phy[6], 0x7 << 24, reg_value);
+ clrsetbits_le32(&denali_phy[134], 0x7 << 24, reg_value);
+ clrsetbits_le32(&denali_phy[262], 0x7 << 24, reg_value);
+ clrsetbits_le32(&denali_phy[390], 0x7 << 24, reg_value);
+
+ /* phy_adr_tsel_enable_ 1bit DENALI_PHY_518/646/774 offset_8 */
+ reg_value = tsel_wr_en << 8;
+ clrsetbits_le32(&denali_phy[518], 0x1 << 8, reg_value);
+ clrsetbits_le32(&denali_phy[646], 0x1 << 8, reg_value);
+ clrsetbits_le32(&denali_phy[774], 0x1 << 8, reg_value);
+
+ /* phy_pad_addr_term tsel 1bit DENALI_PHY_933 offset_17 */
+ reg_value = tsel_wr_en << 17;
+ clrsetbits_le32(&denali_phy[933], 0x1 << 17, reg_value);
+ /*
+ * pad_rst/cke/cs/clk_term tsel 1bits
+ * DENALI_PHY_938/936/940/934 offset_17
+ */
+ clrsetbits_le32(&denali_phy[938], 0x1 << 17, reg_value);
+ clrsetbits_le32(&denali_phy[936], 0x1 << 17, reg_value);
+ clrsetbits_le32(&denali_phy[940], 0x1 << 17, reg_value);
+ clrsetbits_le32(&denali_phy[934], 0x1 << 17, reg_value);
+
+ /* phy_pad_fdbk_term 1bit DENALI_PHY_930 offset_17 */
+ clrsetbits_le32(&denali_phy[930], 0x1 << 17, reg_value);
+
+ phy_io_config(chan, params, mr5);
+}
+
+static void pctl_start(struct dram_info *dram, u8 channel)
+{
+ const struct chan_info *chan = &dram->chan[channel];
+ u32 *denali_ctl = chan->pctl->denali_ctl;
+ u32 *denali_phy = chan->publ->denali_phy;
+ u32 *ddrc0_con = get_ddrc0_con(dram, channel);
+ u32 count = 0;
+ u32 byte, tmp;
+
+ writel(0x01000000, &ddrc0_con);
+
clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24);
- /* Wating for PHY and DRAM init complete */
- tmp = get_timer(0);
- do {
- if (get_timer(tmp) > timeout_ms) {
- pr_err("DRAM (%s): phy failed to lock within %ld ms\n",
- __func__, timeout_ms);
- return -ETIME;
+ while (!(readl(&denali_ctl[203]) & (1 << 3))) {
+ if (count > 1000) {
+ printf("%s: Failed to init pctl for channel %d\n",
+ __func__, channel);
+ while (1)
+ ;
}
- } while (!(readl(&denali_ctl[203]) & (1 << 3)));
- debug("DRAM (%s): phy locked after %ld ms\n", __func__, get_timer(tmp));
+
+ udelay(1);
+ count++;
+ }
+
+ writel(0x01000100, &ddrc0_con);
+
+ for (byte = 0; byte < 4; byte++) {
+ tmp = 0x820;
+ writel((tmp << 16) | tmp, &denali_phy[53 + (128 * byte)]);
+ writel((tmp << 16) | tmp, &denali_phy[54 + (128 * byte)]);
+ writel((tmp << 16) | tmp, &denali_phy[55 + (128 * byte)]);
+ writel((tmp << 16) | tmp, &denali_phy[56 + (128 * byte)]);
+ writel((tmp << 16) | tmp, &denali_phy[57 + (128 * byte)]);
+
+ clrsetbits_le32(&denali_phy[58 + (128 * byte)], 0xffff, tmp);
+ }
clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT,
- pwrup_srefresh_exit);
+ dram->pwrup_srefresh_exit[channel]);
+}
+
+static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
+ u32 channel, struct rk3399_sdram_params *params)
+{
+ u32 *denali_ctl = chan->pctl->denali_ctl;
+ u32 *denali_pi = chan->pi->denali_pi;
+ u32 *denali_phy = chan->publ->denali_phy;
+ const u32 *params_ctl = params->pctl_regs.denali_ctl;
+ const u32 *params_phy = params->phy_regs.denali_phy;
+ u32 tmp, tmp1, tmp2;
+
+ /*
+ * work around controller bug:
+ * Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed
+ */
+ copy_to_reg(&denali_ctl[1], ¶ms_ctl[1],
+ sizeof(struct rk3399_ddr_pctl_regs) - 4);
+ writel(params_ctl[0], &denali_ctl[0]);
+
+ /*
+ * two channel init at the same time, then ZQ Cal Start
+ * at the same time, it will use the same RZQ, but cannot
+ * start at the same time.
+ *
+ * So, increase tINIT3 for channel 1, will avoid two
+ * channel ZQ Cal Start at the same time
+ */
+ if (params->base.dramtype == LPDDR4 && channel == 1) {
+ tmp = ((params->base.ddr_freq * MHz + 999) / 1000);
+ tmp1 = readl(&denali_ctl[14]);
+ writel(tmp + tmp1, &denali_ctl[14]);
+ }
+
+ copy_to_reg(denali_pi, ¶ms->pi_regs.denali_pi[0],
+ sizeof(struct rk3399_ddr_pi_regs));
+
+ /* rank count need to set for init */
+ set_memory_map(chan, channel, params);
+
+ writel(params->phy_regs.denali_phy[910], &denali_phy[910]);
+ writel(params->phy_regs.denali_phy[911], &denali_phy[911]);
+ writel(params->phy_regs.denali_phy[912], &denali_phy[912]);
+
+ if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ writel(params->phy_regs.denali_phy[898], &denali_phy[898]);
+ writel(params->phy_regs.denali_phy[919], &denali_phy[919]);
+ }
+
+ dram->pwrup_srefresh_exit[channel] = readl(&denali_ctl[68]) &
+ PWRUP_SREFRESH_EXIT;
+ clrbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT);
+
+ /* PHY_DLL_RST_EN */
+ clrsetbits_le32(&denali_phy[957], 0x3 << 24, 1 << 24);
+
+ setbits_le32(&denali_pi[0], START);
+ setbits_le32(&denali_ctl[0], START);
+
+ /**
+ * LPDDR4 use PLL bypass mode for init
+ * not need to wait for the PLL to lock
+ */
+ if (params->base.dramtype != LPDDR4) {
+ /* Waiting for phy DLL lock */
+ while (1) {
+ tmp = readl(&denali_phy[920]);
+ tmp1 = readl(&denali_phy[921]);
+ tmp2 = readl(&denali_phy[922]);
+ if ((((tmp >> 16) & 0x1) == 0x1) &&
+ (((tmp1 >> 16) & 0x1) == 0x1) &&
+ (((tmp1 >> 0) & 0x1) == 0x1) &&
+ (((tmp2 >> 0) & 0x1) == 0x1))
+ break;
+ }
+ }
+
+ copy_to_reg(&denali_phy[896], ¶ms_phy[896], (958 - 895) * 4);
+ copy_to_reg(&denali_phy[0], ¶ms_phy[0], (90 - 0 + 1) * 4);
+ copy_to_reg(&denali_phy[128], ¶ms_phy[128], (218 - 128 + 1) * 4);
+ copy_to_reg(&denali_phy[256], ¶ms_phy[256], (346 - 256 + 1) * 4);
+ copy_to_reg(&denali_phy[384], ¶ms_phy[384], (474 - 384 + 1) * 4);
+ copy_to_reg(&denali_phy[512], ¶ms_phy[512], (549 - 512 + 1) * 4);
+ copy_to_reg(&denali_phy[640], ¶ms_phy[640], (677 - 640 + 1) * 4);
+ copy_to_reg(&denali_phy[768], ¶ms_phy[768], (805 - 768 + 1) * 4);
+ set_ds_odt(chan, params, true, 0);
+
+ /*
+ * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_84/212/340/468 offset_8
+ * dqs_tsel_wr_end[7:4] add Half cycle
+ */
+ tmp = (readl(&denali_phy[84]) >> 8) & 0xff;
+ clrsetbits_le32(&denali_phy[84], 0xff << 8, (tmp + 0x10) << 8);
+ tmp = (readl(&denali_phy[212]) >> 8) & 0xff;
+ clrsetbits_le32(&denali_phy[212], 0xff << 8, (tmp + 0x10) << 8);
+ tmp = (readl(&denali_phy[340]) >> 8) & 0xff;
+ clrsetbits_le32(&denali_phy[340], 0xff << 8, (tmp + 0x10) << 8);
+ tmp = (readl(&denali_phy[468]) >> 8) & 0xff;
+ clrsetbits_le32(&denali_phy[468], 0xff << 8, (tmp + 0x10) << 8);
+
+ /*
+ * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_83/211/339/467 offset_8
+ * dq_tsel_wr_end[7:4] add Half cycle
+ */
+ tmp = (readl(&denali_phy[83]) >> 16) & 0xff;
+ clrsetbits_le32(&denali_phy[83], 0xff << 16, (tmp + 0x10) << 16);
+ tmp = (readl(&denali_phy[211]) >> 16) & 0xff;
+ clrsetbits_le32(&denali_phy[211], 0xff << 16, (tmp + 0x10) << 16);
+ tmp = (readl(&denali_phy[339]) >> 16) & 0xff;
+ clrsetbits_le32(&denali_phy[339], 0xff << 16, (tmp + 0x10) << 16);
+ tmp = (readl(&denali_phy[467]) >> 16) & 0xff;
+ clrsetbits_le32(&denali_phy[467], 0xff << 16, (tmp + 0x10) << 16);
+
return 0;
}
@@ -569,7 +972,7 @@
u32 *denali_phy = chan->publ->denali_phy;
/* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */
- if ((readl(&denali_phy[84])>>16) & 1) {
+ if ((readl(&denali_phy[84]) >> 16) & 1) {
/*
* PHY_8/136/264/392
* phy_per_cs_training_index_X 1bit offset_24
@@ -611,18 +1014,32 @@
}
static int data_training_ca(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
u32 *denali_pi = chan->pi->denali_pi;
u32 *denali_phy = chan->publ->denali_phy;
u32 i, tmp;
u32 obs_0, obs_1, obs_2, obs_err = 0;
- u32 rank = sdram_params->ch[channel].rank;
+ u32 rank = params->ch[channel].cap_info.rank;
+ u32 rank_mask;
- for (i = 0; i < rank; i++) {
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ writel(0x00003f7c, (&denali_pi[175]));
+
+ if (params->base.dramtype == LPDDR4)
+ rank_mask = (rank == 1) ? 0x5 : 0xf;
+ else
+ rank_mask = (rank == 1) ? 0x1 : 0x3;
+
+ for (i = 0; i < 4; i++) {
+ if (!(rank_mask & (1 << i)))
+ continue;
+
select_per_cs_training_index(chan, i);
+
/* PI_100 PI_CALVL_EN:RW:8:2 */
clrsetbits_le32(&denali_pi[100], 0x3 << 8, 0x2 << 8);
+
/* PI_92 PI_CALVL_REQ:WR:16:1,PI_CALVL_CS:RW:24:2 */
clrsetbits_le32(&denali_pi[92],
(0x1 << 16) | (0x3 << 24),
@@ -646,33 +1063,40 @@
if ((((tmp >> 11) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 5) & 0x1) == 0x0) &&
- (obs_err == 0))
+ obs_err == 0)
break;
else if ((((tmp >> 5) & 0x1) == 0x1) ||
(obs_err == 1))
return -EIO;
}
+
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
writel(0x00003f7c, (&denali_pi[175]));
}
+
clrbits_le32(&denali_pi[100], 0x3 << 8);
return 0;
}
static int data_training_wl(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
u32 *denali_pi = chan->pi->denali_pi;
u32 *denali_phy = chan->publ->denali_phy;
u32 i, tmp;
u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0;
- u32 rank = sdram_params->ch[channel].rank;
+ u32 rank = params->ch[channel].cap_info.rank;
+
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ writel(0x00003f7c, (&denali_pi[175]));
for (i = 0; i < rank; i++) {
select_per_cs_training_index(chan, i);
+
/* PI_60 PI_WRLVL_EN:RW:8:2 */
clrsetbits_le32(&denali_pi[60], 0x3 << 8, 0x2 << 8);
+
/* PI_59 PI_WRLVL_REQ:WR:8:1,PI_WRLVL_CS:RW:16:2 */
clrsetbits_le32(&denali_pi[59],
(0x1 << 8) | (0x3 << 16),
@@ -700,12 +1124,13 @@
if ((((tmp >> 10) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 4) & 0x1) == 0x0) &&
- (obs_err == 0))
+ obs_err == 0)
break;
else if ((((tmp >> 4) & 0x1) == 0x1) ||
(obs_err == 1))
return -EIO;
}
+
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
writel(0x00003f7c, (&denali_pi[175]));
}
@@ -717,18 +1142,23 @@
}
static int data_training_rg(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
u32 *denali_pi = chan->pi->denali_pi;
u32 *denali_phy = chan->publ->denali_phy;
u32 i, tmp;
u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0;
- u32 rank = sdram_params->ch[channel].rank;
+ u32 rank = params->ch[channel].cap_info.rank;
+
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ writel(0x00003f7c, (&denali_pi[175]));
for (i = 0; i < rank; i++) {
select_per_cs_training_index(chan, i);
+
/* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */
clrsetbits_le32(&denali_pi[80], 0x3 << 24, 0x2 << 24);
+
/*
* PI_74 PI_RDLVL_GATE_REQ:WR:16:1
* PI_RDLVL_CS:RW:24:2
@@ -759,31 +1189,38 @@
if ((((tmp >> 9) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 3) & 0x1) == 0x0) &&
- (obs_err == 0))
+ obs_err == 0)
break;
else if ((((tmp >> 3) & 0x1) == 0x1) ||
(obs_err == 1))
return -EIO;
}
+
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
writel(0x00003f7c, (&denali_pi[175]));
}
+
clrbits_le32(&denali_pi[80], 0x3 << 24);
return 0;
}
static int data_training_rl(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
u32 *denali_pi = chan->pi->denali_pi;
u32 i, tmp;
- u32 rank = sdram_params->ch[channel].rank;
+ u32 rank = params->ch[channel].cap_info.rank;
+
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ writel(0x00003f7c, (&denali_pi[175]));
for (i = 0; i < rank; i++) {
select_per_cs_training_index(chan, i);
+
/* PI_80 PI_RDLVL_EN:RW:16:2 */
clrsetbits_le32(&denali_pi[80], 0x3 << 16, 0x2 << 16);
+
/* PI_74 PI_RDLVL_REQ:WR:8:1,PI_RDLVL_CS:RW:24:2 */
clrsetbits_le32(&denali_pi[74],
(0x1 << 8) | (0x3 << 24),
@@ -806,30 +1243,47 @@
else if (((tmp >> 2) & 0x1) == 0x1)
return -EIO;
}
+
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
writel(0x00003f7c, (&denali_pi[175]));
}
+
clrbits_le32(&denali_pi[80], 0x3 << 16);
return 0;
}
static int data_training_wdql(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
u32 *denali_pi = chan->pi->denali_pi;
u32 i, tmp;
- u32 rank = sdram_params->ch[channel].rank;
+ u32 rank = params->ch[channel].cap_info.rank;
+ u32 rank_mask;
- for (i = 0; i < rank; i++) {
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ writel(0x00003f7c, (&denali_pi[175]));
+
+ if (params->base.dramtype == LPDDR4)
+ rank_mask = (rank == 1) ? 0x5 : 0xf;
+ else
+ rank_mask = (rank == 1) ? 0x1 : 0x3;
+
+ for (i = 0; i < 4; i++) {
+ if (!(rank_mask & (1 << i)))
+ continue;
+
select_per_cs_training_index(chan, i);
+
/*
* disable PI_WDQLVL_VREF_EN before wdq leveling?
* PI_181 PI_WDQLVL_VREF_EN:RW:8:1
*/
clrbits_le32(&denali_pi[181], 0x1 << 8);
+
/* PI_124 PI_WDQLVL_EN:RW:16:2 */
clrsetbits_le32(&denali_pi[124], 0x3 << 16, 0x2 << 16);
+
/* PI_121 PI_WDQLVL_REQ:WR:8:1,PI_WDQLVL_CS:RW:16:2 */
clrsetbits_le32(&denali_pi[121],
(0x1 << 8) | (0x3 << 16),
@@ -846,32 +1300,36 @@
else if (((tmp >> 6) & 0x1) == 0x1)
return -EIO;
}
+
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
writel(0x00003f7c, (&denali_pi[175]));
}
+
clrbits_le32(&denali_pi[124], 0x3 << 16);
return 0;
}
-static int data_training(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params,
+static int data_training(struct dram_info *dram, u32 channel,
+ const struct rk3399_sdram_params *params,
u32 training_flag)
{
+ struct chan_info *chan = &dram->chan[channel];
u32 *denali_phy = chan->publ->denali_phy;
+ int ret;
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */
setbits_le32(&denali_phy[927], (1 << 22));
if (training_flag == PI_FULL_TRAINING) {
- if (sdram_params->base.dramtype == LPDDR4) {
- training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
+ if (params->base.dramtype == LPDDR4) {
+ training_flag = PI_WRITE_LEVELING |
PI_READ_GATE_TRAINING |
PI_READ_LEVELING | PI_WDQ_LEVELING;
- } else if (sdram_params->base.dramtype == LPDDR3) {
+ } else if (params->base.dramtype == LPDDR3) {
training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
PI_READ_GATE_TRAINING;
- } else if (sdram_params->base.dramtype == DDR3) {
+ } else if (params->base.dramtype == DDR3) {
training_flag = PI_WRITE_LEVELING |
PI_READ_GATE_TRAINING |
PI_READ_LEVELING;
@@ -879,24 +1337,49 @@
}
/* ca training(LPDDR4,LPDDR3 support) */
- if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING)
- data_training_ca(chan, channel, sdram_params);
+ if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) {
+ ret = data_training_ca(chan, channel, params);
+ if (ret < 0) {
+ debug("%s: data training ca failed\n", __func__);
+ return ret;
+ }
+ }
/* write leveling(LPDDR4,LPDDR3,DDR3 support) */
- if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING)
- data_training_wl(chan, channel, sdram_params);
+ if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) {
+ ret = data_training_wl(chan, channel, params);
+ if (ret < 0) {
+ debug("%s: data training wl failed\n", __func__);
+ return ret;
+ }
+ }
/* read gate training(LPDDR4,LPDDR3,DDR3 support) */
- if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING)
- data_training_rg(chan, channel, sdram_params);
+ if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) {
+ ret = data_training_rg(chan, channel, params);
+ if (ret < 0) {
+ debug("%s: data training rg failed\n", __func__);
+ return ret;
+ }
+ }
/* read leveling(LPDDR4,LPDDR3,DDR3 support) */
- if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING)
- data_training_rl(chan, channel, sdram_params);
+ if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) {
+ ret = data_training_rl(chan, channel, params);
+ if (ret < 0) {
+ debug("%s: data training rl failed\n", __func__);
+ return ret;
+ }
+ }
/* wdq leveling(LPDDR4 support) */
- if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING)
- data_training_wdql(chan, channel, sdram_params);
+ if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) {
+ ret = data_training_wdql(chan, channel, params);
+ if (ret < 0) {
+ debug("%s: data training wdql failed\n", __func__);
+ return ret;
+ }
+ }
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */
clrbits_le32(&denali_phy[927], (1 << 22));
@@ -905,7 +1388,7 @@
}
static void set_ddrconfig(const struct chan_info *chan,
- const struct rk3399_sdram_params *sdram_params,
+ const struct rk3399_sdram_params *params,
unsigned char channel, u32 ddrconfig)
{
/* only need to set ddrconfig */
@@ -913,14 +1396,14 @@
unsigned int cs0_cap = 0;
unsigned int cs1_cap = 0;
- cs0_cap = (1 << (sdram_params->ch[channel].cs0_row
- + sdram_params->ch[channel].col
- + sdram_params->ch[channel].bk
- + sdram_params->ch[channel].bw - 20));
- if (sdram_params->ch[channel].rank > 1)
- cs1_cap = cs0_cap >> (sdram_params->ch[channel].cs0_row
- - sdram_params->ch[channel].cs1_row);
- if (sdram_params->ch[channel].row_3_4) {
+ cs0_cap = (1 << (params->ch[channel].cap_info.cs0_row
+ + params->ch[channel].cap_info.col
+ + params->ch[channel].cap_info.bk
+ + params->ch[channel].cap_info.bw - 20));
+ if (params->ch[channel].cap_info.rank > 1)
+ cs1_cap = cs0_cap >> (params->ch[channel].cap_info.cs0_row
+ - params->ch[channel].cap_info.cs1_row);
+ if (params->ch[channel].cap_info.row_3_4) {
cs0_cap = cs0_cap * 3 / 4;
cs1_cap = cs1_cap * 3 / 4;
}
@@ -931,57 +1414,72 @@
}
static void dram_all_config(struct dram_info *dram,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
- u32 sys_reg = 0;
+ u32 sys_reg2 = 0;
+ u32 sys_reg3 = 0;
unsigned int channel, idx;
- sys_reg |= sdram_params->base.dramtype << SYS_REG_DDRTYPE_SHIFT;
- sys_reg |= (sdram_params->base.num_channels - 1)
- << SYS_REG_NUM_CH_SHIFT;
+ sys_reg2 |= SYS_REG_ENC_DDRTYPE(params->base.dramtype);
+ sys_reg2 |= SYS_REG_ENC_NUM_CH(params->base.num_channels);
+
for (channel = 0, idx = 0;
- (idx < sdram_params->base.num_channels) && (channel < 2);
+ (idx < params->base.num_channels) && (channel < 2);
channel++) {
- const struct rk3399_sdram_channel *info =
- &sdram_params->ch[channel];
+ const struct rk3399_sdram_channel *info = ¶ms->ch[channel];
struct rk3399_msch_regs *ddr_msch_regs;
const struct rk3399_msch_timings *noc_timing;
- if (sdram_params->ch[channel].col == 0)
+ if (params->ch[channel].cap_info.col == 0)
continue;
idx++;
- sys_reg |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(channel);
- sys_reg |= 1 << SYS_REG_CHINFO_SHIFT(channel);
- sys_reg |= (info->rank - 1) << SYS_REG_RANK_SHIFT(channel);
- sys_reg |= (info->col - 9) << SYS_REG_COL_SHIFT(channel);
- sys_reg |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(channel);
- sys_reg |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(channel);
- sys_reg |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(channel);
- sys_reg |= (2 >> info->bw) << SYS_REG_BW_SHIFT(channel);
- sys_reg |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(channel);
+ sys_reg2 |= SYS_REG_ENC_ROW_3_4(info->cap_info.row_3_4, channel);
+ sys_reg2 |= SYS_REG_ENC_CHINFO(channel);
+ sys_reg2 |= SYS_REG_ENC_RANK(info->cap_info.rank, channel);
+ sys_reg2 |= SYS_REG_ENC_COL(info->cap_info.col, channel);
+ sys_reg2 |= SYS_REG_ENC_BK(info->cap_info.bk, channel);
+ sys_reg2 |= SYS_REG_ENC_BW(info->cap_info.bw, channel);
+ sys_reg2 |= SYS_REG_ENC_DBW(info->cap_info.dbw, channel);
+ SYS_REG_ENC_CS0_ROW(info->cap_info.cs0_row, sys_reg2, sys_reg3, channel);
+ if (info->cap_info.cs1_row)
+ SYS_REG_ENC_CS1_ROW(info->cap_info.cs1_row, sys_reg2,
+ sys_reg3, channel);
+ sys_reg3 |= SYS_REG_ENC_CS1_COL(info->cap_info.col, channel);
+ sys_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
ddr_msch_regs = dram->chan[channel].msch;
- noc_timing = &sdram_params->ch[channel].noc_timings;
+ noc_timing = ¶ms->ch[channel].noc_timings;
writel(noc_timing->ddrtiminga0,
&ddr_msch_regs->ddrtiminga0);
writel(noc_timing->ddrtimingb0,
&ddr_msch_regs->ddrtimingb0);
- writel(noc_timing->ddrtimingc0,
+ writel(noc_timing->ddrtimingc0.d32,
&ddr_msch_regs->ddrtimingc0);
writel(noc_timing->devtodev0,
&ddr_msch_regs->devtodev0);
- writel(noc_timing->ddrmode,
+ writel(noc_timing->ddrmode.d32,
&ddr_msch_regs->ddrmode);
- /* rank 1 memory clock disable (dfi_dram_clk_disable = 1) */
- if (sdram_params->ch[channel].rank == 1)
+ /**
+ * rank 1 memory clock disable (dfi_dram_clk_disable = 1)
+ *
+ * The hardware for LPDDR4 with
+ * - CLK0P/N connect to lower 16-bits
+ * - CLK1P/N connect to higher 16-bits
+ *
+ * dfi dram clk is configured via CLK1P/N, so disabling
+ * dfi dram clk will disable the CLK1P/N as well for lpddr4.
+ */
+ if (params->ch[channel].cap_info.rank == 1 &&
+ params->base.dramtype != LPDDR4)
setbits_le32(&dram->chan[channel].pctl->denali_ctl[276],
1 << 17);
}
- writel(sys_reg, &dram->pmugrf->os_reg2);
+ writel(sys_reg2, &dram->pmugrf->os_reg2);
+ writel(sys_reg3, &dram->pmugrf->os_reg3);
rk_clrsetreg(&dram->pmusgrf->soc_con4, 0x1f << 10,
- sdram_params->base.stride << 10);
+ params->base.stride << 10);
/* reboot hold register set */
writel(PRESET_SGRF_HOLD(0) | PRESET_GPIO0_HOLD(1) |
@@ -990,12 +1488,30 @@
clrsetbits_le32(&dram->cru->glb_rst_con, 0x3, 0x3);
}
+#if !defined(CONFIG_RAM_RK3399_LPDDR4)
+static int default_data_training(struct dram_info *dram, u32 channel, u8 rank,
+ struct rk3399_sdram_params *params)
+{
+ u8 training_flag = PI_READ_GATE_TRAINING;
+
+ /*
+ * LPDDR3 CA training msut be trigger before
+ * other training.
+ * DDR3 is not have CA training.
+ */
+
+ if (params->base.dramtype == LPDDR3)
+ training_flag |= PI_CA_TRAINING;
+
+ return data_training(dram, channel, params, training_flag);
+}
+
static int switch_to_phy_index1(struct dram_info *dram,
- const struct rk3399_sdram_params *sdram_params)
+ struct rk3399_sdram_params *params)
{
u32 channel;
u32 *denali_phy;
- u32 ch_count = sdram_params->base.num_channels;
+ u32 ch_count = params->base.num_channels;
int ret;
int i = 0;
@@ -1025,9 +1541,8 @@
for (channel = 0; channel < ch_count; channel++) {
denali_phy = dram->chan[channel].publ->denali_phy;
clrsetbits_le32(&denali_phy[896], (0x3 << 8) | 1, 1 << 8);
- ret = data_training(&dram->chan[channel], channel,
- sdram_params, PI_FULL_TRAINING);
- if (ret) {
+ ret = data_training(dram, channel, params, PI_FULL_TRAINING);
+ if (ret < 0) {
debug("index1 training failed\n");
return ret;
}
@@ -1036,12 +1551,979 @@
return 0;
}
-static int sdram_init(struct dram_info *dram,
- const struct rk3399_sdram_params *sdram_params)
-{
- unsigned char dramtype = sdram_params->base.dramtype;
- unsigned int ddr_freq = sdram_params->base.ddr_freq;
- int channel;
+#else
+
+struct rk3399_sdram_params lpddr4_timings[] = {
+ #include "sdram-rk3399-lpddr4-400.inc"
+ #include "sdram-rk3399-lpddr4-800.inc"
+};
+
+static void *get_denali_pi(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, bool reg)
+{
+ return reg ? &chan->pi->denali_pi : ¶ms->pi_regs.denali_pi;
+}
+
+static u32 lpddr4_get_phy(struct rk3399_sdram_params *params, u32 ctl)
+{
+ u32 lpddr4_phy[] = {1, 0, 0xb};
+
+ return lpddr4_phy[ctl];
+}
+
+static u32 lpddr4_get_ctl(struct rk3399_sdram_params *params, u32 phy)
+{
+ u32 lpddr4_ctl[] = {1, 0, 2};
+
+ return lpddr4_ctl[phy];
+}
+
+static u32 get_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf)
+{
+ return ((readl(&pmusgrf->soc_con4) >> 10) & 0x1F);
+}
+
+static void set_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf, u32 stride)
+{
+ rk_clrsetreg(&pmusgrf->soc_con4, 0x1f << 10, stride << 10);
+}
+
+static void set_cap_relate_config(const struct chan_info *chan,
+ struct rk3399_sdram_params *params,
+ unsigned int channel)
+{
+ u32 *denali_ctl = chan->pctl->denali_ctl;
+ u32 tmp;
+ struct rk3399_msch_timings *noc_timing;
+
+ if (params->base.dramtype == LPDDR3) {
+ tmp = (8 << params->ch[channel].cap_info.bw) /
+ (8 << params->ch[channel].cap_info.dbw);
+
+ /**
+ * memdata_ratio
+ * 1 -> 0, 2 -> 1, 4 -> 2
+ */
+ clrsetbits_le32(&denali_ctl[197], 0x7,
+ (tmp >> 1));
+ clrsetbits_le32(&denali_ctl[198], 0x7 << 8,
+ (tmp >> 1) << 8);
+ }
+
+ noc_timing = ¶ms->ch[channel].noc_timings;
+
+ /*
+ * noc timing bw relate timing is 32 bit, and real bw is 16bit
+ * actually noc reg is setting at function dram_all_config
+ */
+ if (params->ch[channel].cap_info.bw == 16 &&
+ noc_timing->ddrmode.b.mwrsize == 2) {
+ if (noc_timing->ddrmode.b.burstsize)
+ noc_timing->ddrmode.b.burstsize -= 1;
+ noc_timing->ddrmode.b.mwrsize -= 1;
+ noc_timing->ddrtimingc0.b.burstpenalty *= 2;
+ noc_timing->ddrtimingc0.b.wrtomwr *= 2;
+ }
+}
+
+static u32 calculate_ddrconfig(struct rk3399_sdram_params *params, u32 channel)
+{
+ unsigned int cs0_row = params->ch[channel].cap_info.cs0_row;
+ unsigned int col = params->ch[channel].cap_info.col;
+ unsigned int bw = params->ch[channel].cap_info.bw;
+ u16 ddr_cfg_2_rbc[] = {
+ /*
+ * [6] highest bit col
+ * [5:3] max row(14+n)
+ * [2] insertion row
+ * [1:0] col(9+n),col, data bus 32bit
+ *
+ * highbitcol, max_row, insertion_row, col
+ */
+ ((0 << 6) | (2 << 3) | (0 << 2) | 0), /* 0 */
+ ((0 << 6) | (2 << 3) | (0 << 2) | 1), /* 1 */
+ ((0 << 6) | (1 << 3) | (0 << 2) | 2), /* 2 */
+ ((0 << 6) | (0 << 3) | (0 << 2) | 3), /* 3 */
+ ((0 << 6) | (2 << 3) | (1 << 2) | 1), /* 4 */
+ ((0 << 6) | (1 << 3) | (1 << 2) | 2), /* 5 */
+ ((1 << 6) | (0 << 3) | (0 << 2) | 2), /* 6 */
+ ((1 << 6) | (1 << 3) | (0 << 2) | 2), /* 7 */
+ };
+ u32 i;
+
+ col -= (bw == 2) ? 0 : 1;
+ col -= 9;
+
+ for (i = 0; i < 4; i++) {
+ if ((col == (ddr_cfg_2_rbc[i] & 0x3)) &&
+ (cs0_row <= (((ddr_cfg_2_rbc[i] >> 3) & 0x7) + 14)))
+ break;
+ }
+
+ if (i >= 4)
+ i = -EINVAL;
+
+ return i;
+}
+
+/**
+ * read mr_num mode register
+ * rank = 1: cs0
+ * rank = 2: cs1
+ */
+static int read_mr(struct rk3399_ddr_pctl_regs *ddr_pctl_regs, u32 rank,
+ u32 mr_num, u32 *buf)
+{
+ s32 timeout = 100;
+
+ writel(((1 << 16) | (((rank == 2) ? 1 : 0) << 8) | mr_num) << 8,
+ &ddr_pctl_regs->denali_ctl[118]);
+
+ while (0 == (readl(&ddr_pctl_regs->denali_ctl[203]) &
+ ((1 << 21) | (1 << 12)))) {
+ udelay(1);
+
+ if (timeout <= 0) {
+ printf("%s: pctl timeout!\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ timeout--;
+ }
+
+ if (!(readl(&ddr_pctl_regs->denali_ctl[203]) & (1 << 12))) {
+ *buf = readl(&ddr_pctl_regs->denali_ctl[119]) & 0xFF;
+ } else {
+ printf("%s: read mr failed with 0x%x status\n", __func__,
+ readl(&ddr_pctl_regs->denali_ctl[17]) & 0x3);
+ *buf = 0;
+ }
+
+ setbits_le32(&ddr_pctl_regs->denali_ctl[205], (1 << 21) | (1 << 12));
+
+ return 0;
+}
+
+static int lpddr4_mr_detect(struct dram_info *dram, u32 channel, u8 rank,
+ struct rk3399_sdram_params *params)
+{
+ u64 cs0_cap;
+ u32 stride;
+ u32 cs = 0, col = 0, bk = 0, bw = 0, row_3_4 = 0;
+ u32 cs0_row = 0, cs1_row = 0, ddrconfig = 0;
+ u32 mr5, mr12, mr14;
+ struct chan_info *chan = &dram->chan[channel];
+ struct rk3399_ddr_pctl_regs *ddr_pctl_regs = chan->pctl;
+ void __iomem *addr = NULL;
+ int ret = 0;
+ u32 val;
+
+ stride = get_ddr_stride(dram->pmusgrf);
+
+ if (params->ch[channel].cap_info.col == 0) {
+ ret = -EPERM;
+ goto end;
+ }
+
+ cs = params->ch[channel].cap_info.rank;
+ col = params->ch[channel].cap_info.col;
+ bk = params->ch[channel].cap_info.bk;
+ bw = params->ch[channel].cap_info.bw;
+ row_3_4 = params->ch[channel].cap_info.row_3_4;
+ cs0_row = params->ch[channel].cap_info.cs0_row;
+ cs1_row = params->ch[channel].cap_info.cs1_row;
+ ddrconfig = params->ch[channel].cap_info.ddrconfig;
+
+ /* 2GB */
+ params->ch[channel].cap_info.rank = 2;
+ params->ch[channel].cap_info.col = 10;
+ params->ch[channel].cap_info.bk = 3;
+ params->ch[channel].cap_info.bw = 2;
+ params->ch[channel].cap_info.row_3_4 = 0;
+ params->ch[channel].cap_info.cs0_row = 15;
+ params->ch[channel].cap_info.cs1_row = 15;
+ params->ch[channel].cap_info.ddrconfig = 1;
+
+ set_memory_map(chan, channel, params);
+ params->ch[channel].cap_info.ddrconfig =
+ calculate_ddrconfig(params, channel);
+ set_ddrconfig(chan, params, channel,
+ params->ch[channel].cap_info.ddrconfig);
+ set_cap_relate_config(chan, params, channel);
+
+ cs0_cap = (1 << (params->ch[channel].cap_info.bw
+ + params->ch[channel].cap_info.col
+ + params->ch[channel].cap_info.bk
+ + params->ch[channel].cap_info.cs0_row));
+
+ if (params->ch[channel].cap_info.row_3_4)
+ cs0_cap = cs0_cap * 3 / 4;
+
+ if (channel == 0)
+ set_ddr_stride(dram->pmusgrf, 0x17);
+ else
+ set_ddr_stride(dram->pmusgrf, 0x18);
+
+ /* read and write data to DRAM, avoid be optimized by compiler. */
+ if (rank == 1)
+ addr = (void __iomem *)0x100;
+ else if (rank == 2)
+ addr = (void __iomem *)(cs0_cap + 0x100);
+
+ val = readl(addr);
+ writel(val + 1, addr);
+
+ read_mr(ddr_pctl_regs, rank, 5, &mr5);
+ read_mr(ddr_pctl_regs, rank, 12, &mr12);
+ read_mr(ddr_pctl_regs, rank, 14, &mr14);
+
+ if (mr5 == 0 || mr12 != 0x4d || mr14 != 0x4d) {
+ ret = -EINVAL;
+ goto end;
+ }
+end:
+ params->ch[channel].cap_info.rank = cs;
+ params->ch[channel].cap_info.col = col;
+ params->ch[channel].cap_info.bk = bk;
+ params->ch[channel].cap_info.bw = bw;
+ params->ch[channel].cap_info.row_3_4 = row_3_4;
+ params->ch[channel].cap_info.cs0_row = cs0_row;
+ params->ch[channel].cap_info.cs1_row = cs1_row;
+ params->ch[channel].cap_info.ddrconfig = ddrconfig;
+
+ set_ddr_stride(dram->pmusgrf, stride);
+
+ return ret;
+}
+
+static void set_lpddr4_dq_odt(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, u32 ctl,
+ bool en, bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 *denali_pi = get_denali_pi(chan, params, ctl_phy_reg);
+ struct io_setting *io;
+ u32 reg_value;
+
+ if (!en)
+ return;
+
+ io = lpddr4_get_io_settings(params, mr5);
+
+ reg_value = io->dq_odt;
+
+ switch (ctl) {
+ case 0:
+ clrsetbits_le32(&denali_ctl[139], 0x7 << 24, reg_value << 24);
+ clrsetbits_le32(&denali_ctl[153], 0x7 << 24, reg_value << 24);
+
+ clrsetbits_le32(&denali_pi[132], 0x7 << 0, (reg_value << 0));
+ clrsetbits_le32(&denali_pi[139], 0x7 << 16, (reg_value << 16));
+ clrsetbits_le32(&denali_pi[147], 0x7 << 0, (reg_value << 0));
+ clrsetbits_le32(&denali_pi[154], 0x7 << 16, (reg_value << 16));
+ break;
+ case 1:
+ clrsetbits_le32(&denali_ctl[140], 0x7 << 0, reg_value << 0);
+ clrsetbits_le32(&denali_ctl[154], 0x7 << 0, reg_value << 0);
+
+ clrsetbits_le32(&denali_pi[129], 0x7 << 16, (reg_value << 16));
+ clrsetbits_le32(&denali_pi[137], 0x7 << 0, (reg_value << 0));
+ clrsetbits_le32(&denali_pi[144], 0x7 << 16, (reg_value << 16));
+ clrsetbits_le32(&denali_pi[152], 0x7 << 0, (reg_value << 0));
+ break;
+ case 2:
+ default:
+ clrsetbits_le32(&denali_ctl[140], 0x7 << 8, (reg_value << 8));
+ clrsetbits_le32(&denali_ctl[154], 0x7 << 8, (reg_value << 8));
+
+ clrsetbits_le32(&denali_pi[127], 0x7 << 0, (reg_value << 0));
+ clrsetbits_le32(&denali_pi[134], 0x7 << 16, (reg_value << 16));
+ clrsetbits_le32(&denali_pi[142], 0x7 << 0, (reg_value << 0));
+ clrsetbits_le32(&denali_pi[149], 0x7 << 16, (reg_value << 16));
+ break;
+ }
+}
+
+static void set_lpddr4_ca_odt(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, u32 ctl,
+ bool en, bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 *denali_pi = get_denali_pi(chan, params, ctl_phy_reg);
+ struct io_setting *io;
+ u32 reg_value;
+
+ if (!en)
+ return;
+
+ io = lpddr4_get_io_settings(params, mr5);
+
+ reg_value = io->ca_odt;
+
+ switch (ctl) {
+ case 0:
+ clrsetbits_le32(&denali_ctl[139], 0x7 << 28, reg_value << 28);
+ clrsetbits_le32(&denali_ctl[153], 0x7 << 28, reg_value << 28);
+
+ clrsetbits_le32(&denali_pi[132], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_pi[139], 0x7 << 20, reg_value << 20);
+ clrsetbits_le32(&denali_pi[147], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_pi[154], 0x7 << 20, reg_value << 20);
+ break;
+ case 1:
+ clrsetbits_le32(&denali_ctl[140], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_ctl[154], 0x7 << 4, reg_value << 4);
+
+ clrsetbits_le32(&denali_pi[129], 0x7 << 20, reg_value << 20);
+ clrsetbits_le32(&denali_pi[137], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_pi[144], 0x7 << 20, reg_value << 20);
+ clrsetbits_le32(&denali_pi[152], 0x7 << 4, reg_value << 4);
+ break;
+ case 2:
+ default:
+ clrsetbits_le32(&denali_ctl[140], 0x7 << 12, (reg_value << 12));
+ clrsetbits_le32(&denali_ctl[154], 0x7 << 12, (reg_value << 12));
+
+ clrsetbits_le32(&denali_pi[127], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_pi[134], 0x7 << 20, reg_value << 20);
+ clrsetbits_le32(&denali_pi[142], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_pi[149], 0x7 << 20, reg_value << 20);
+ break;
+ }
+}
+
+static void set_lpddr4_MR3(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, u32 ctl,
+ bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 *denali_pi = get_denali_pi(chan, params, ctl_phy_reg);
+ struct io_setting *io;
+ u32 reg_value;
+
+ io = lpddr4_get_io_settings(params, mr5);
+
+ reg_value = ((io->pdds << 3) | 1);
+
+ switch (ctl) {
+ case 0:
+ clrsetbits_le32(&denali_ctl[138], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_ctl[152], 0xFFFF, reg_value);
+
+ clrsetbits_le32(&denali_pi[131], 0xFFFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[139], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_pi[146], 0xFFFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[154], 0xFFFF, reg_value);
+ break;
+ case 1:
+ clrsetbits_le32(&denali_ctl[138], 0xFFFF << 16,
+ reg_value << 16);
+ clrsetbits_le32(&denali_ctl[152], 0xFFFF << 16,
+ reg_value << 16);
+
+ clrsetbits_le32(&denali_pi[129], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_pi[136], 0xFFFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[144], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_pi[151], 0xFFFF << 16, reg_value << 16);
+ break;
+ case 2:
+ default:
+ clrsetbits_le32(&denali_ctl[139], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_ctl[153], 0xFFFF, reg_value);
+
+ clrsetbits_le32(&denali_pi[126], 0xFFFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[134], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_pi[141], 0xFFFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[149], 0xFFFF, reg_value);
+ break;
+ }
+}
+
+static void set_lpddr4_MR12(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, u32 ctl,
+ bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 *denali_pi = get_denali_pi(chan, params, ctl_phy_reg);
+ struct io_setting *io;
+ u32 reg_value;
+
+ io = lpddr4_get_io_settings(params, mr5);
+
+ reg_value = io->ca_vref;
+
+ switch (ctl) {
+ case 0:
+ clrsetbits_le32(&denali_ctl[140], 0xFFFF << 16,
+ reg_value << 16);
+ clrsetbits_le32(&denali_ctl[154], 0xFFFF << 16,
+ reg_value << 16);
+
+ clrsetbits_le32(&denali_pi[132], 0xFF << 8, reg_value << 8);
+ clrsetbits_le32(&denali_pi[139], 0xFF << 24, reg_value << 24);
+ clrsetbits_le32(&denali_pi[147], 0xFF << 8, reg_value << 8);
+ clrsetbits_le32(&denali_pi[154], 0xFF << 24, reg_value << 24);
+ break;
+ case 1:
+ clrsetbits_le32(&denali_ctl[141], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_ctl[155], 0xFFFF, reg_value);
+
+ clrsetbits_le32(&denali_pi[129], 0xFF << 24, reg_value << 24);
+ clrsetbits_le32(&denali_pi[137], 0xFF << 8, reg_value << 8);
+ clrsetbits_le32(&denali_pi[144], 0xFF << 24, reg_value << 24);
+ clrsetbits_le32(&denali_pi[152], 0xFF << 8, reg_value << 8);
+ break;
+ case 2:
+ default:
+ clrsetbits_le32(&denali_ctl[141], 0xFFFF << 16,
+ reg_value << 16);
+ clrsetbits_le32(&denali_ctl[155], 0xFFFF << 16,
+ reg_value << 16);
+
+ clrsetbits_le32(&denali_pi[127], 0xFF << 8, reg_value << 8);
+ clrsetbits_le32(&denali_pi[134], 0xFF << 24, reg_value << 24);
+ clrsetbits_le32(&denali_pi[142], 0xFF << 8, reg_value << 8);
+ clrsetbits_le32(&denali_pi[149], 0xFF << 24, reg_value << 24);
+ break;
+ }
+}
+
+static void set_lpddr4_MR14(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, u32 ctl,
+ bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 *denali_pi = get_denali_pi(chan, params, ctl_phy_reg);
+ struct io_setting *io;
+ u32 reg_value;
+
+ io = lpddr4_get_io_settings(params, mr5);
+
+ reg_value = io->dq_vref;
+
+ switch (ctl) {
+ case 0:
+ clrsetbits_le32(&denali_ctl[142], 0xFFFF << 16,
+ reg_value << 16);
+ clrsetbits_le32(&denali_ctl[156], 0xFFFF << 16,
+ reg_value << 16);
+
+ clrsetbits_le32(&denali_pi[132], 0xFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[140], 0xFF << 0, reg_value << 0);
+ clrsetbits_le32(&denali_pi[147], 0xFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[155], 0xFF << 0, reg_value << 0);
+ break;
+ case 1:
+ clrsetbits_le32(&denali_ctl[143], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_ctl[157], 0xFFFF, reg_value);
+
+ clrsetbits_le32(&denali_pi[130], 0xFF << 0, reg_value << 0);
+ clrsetbits_le32(&denali_pi[137], 0xFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[145], 0xFF << 0, reg_value << 0);
+ clrsetbits_le32(&denali_pi[152], 0xFF << 16, reg_value << 16);
+ break;
+ case 2:
+ default:
+ clrsetbits_le32(&denali_ctl[143], 0xFFFF << 16,
+ reg_value << 16);
+ clrsetbits_le32(&denali_ctl[157], 0xFFFF << 16,
+ reg_value << 16);
+
+ clrsetbits_le32(&denali_pi[127], 0xFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[135], 0xFF << 0, reg_value << 0);
+ clrsetbits_le32(&denali_pi[142], 0xFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[150], 0xFF << 0, reg_value << 0);
+ break;
+ }
+}
+
+static void lpddr4_copy_phy(struct dram_info *dram,
+ struct rk3399_sdram_params *params, u32 phy,
+ struct rk3399_sdram_params *timings,
+ u32 channel)
+{
+ u32 *denali_ctl, *denali_phy;
+ u32 *denali_phy_params;
+ u32 speed = 0;
+ u32 ctl, mr5;
+
+ denali_ctl = dram->chan[channel].pctl->denali_ctl;
+ denali_phy = dram->chan[channel].publ->denali_phy;
+ denali_phy_params = timings->phy_regs.denali_phy;
+
+ /* switch index */
+ clrsetbits_le32(&denali_phy_params[896], 0x3 << 8, phy << 8);
+ writel(denali_phy_params[896], &denali_phy[896]);
+
+ /* phy_pll_ctrl_ca, phy_pll_ctrl */
+ writel(denali_phy_params[911], &denali_phy[911]);
+
+ /* phy_low_freq_sel */
+ clrsetbits_le32(&denali_phy[913], 0x1,
+ denali_phy_params[913] & 0x1);
+
+ /* phy_grp_slave_delay_x, phy_cslvl_dly_step */
+ writel(denali_phy_params[916], &denali_phy[916]);
+ writel(denali_phy_params[917], &denali_phy[917]);
+ writel(denali_phy_params[918], &denali_phy[918]);
+
+ /* phy_adrz_sw_wraddr_shift_x */
+ writel(denali_phy_params[512], &denali_phy[512]);
+ clrsetbits_le32(&denali_phy[513], 0xffff,
+ denali_phy_params[513] & 0xffff);
+ writel(denali_phy_params[640], &denali_phy[640]);
+ clrsetbits_le32(&denali_phy[641], 0xffff,
+ denali_phy_params[641] & 0xffff);
+ writel(denali_phy_params[768], &denali_phy[768]);
+ clrsetbits_le32(&denali_phy[769], 0xffff,
+ denali_phy_params[769] & 0xffff);
+
+ writel(denali_phy_params[544], &denali_phy[544]);
+ writel(denali_phy_params[545], &denali_phy[545]);
+ writel(denali_phy_params[546], &denali_phy[546]);
+ writel(denali_phy_params[547], &denali_phy[547]);
+
+ writel(denali_phy_params[672], &denali_phy[672]);
+ writel(denali_phy_params[673], &denali_phy[673]);
+ writel(denali_phy_params[674], &denali_phy[674]);
+ writel(denali_phy_params[675], &denali_phy[675]);
+
+ writel(denali_phy_params[800], &denali_phy[800]);
+ writel(denali_phy_params[801], &denali_phy[801]);
+ writel(denali_phy_params[802], &denali_phy[802]);
+ writel(denali_phy_params[803], &denali_phy[803]);
+
+ /*
+ * phy_adr_master_delay_start_x
+ * phy_adr_master_delay_step_x
+ * phy_adr_master_delay_wait_x
+ */
+ writel(denali_phy_params[548], &denali_phy[548]);
+ writel(denali_phy_params[676], &denali_phy[676]);
+ writel(denali_phy_params[804], &denali_phy[804]);
+
+ /* phy_adr_calvl_dly_step_x */
+ writel(denali_phy_params[549], &denali_phy[549]);
+ writel(denali_phy_params[677], &denali_phy[677]);
+ writel(denali_phy_params[805], &denali_phy[805]);
+
+ /*
+ * phy_clk_wrdm_slave_delay_x
+ * phy_clk_wrdqz_slave_delay_x
+ * phy_clk_wrdqs_slave_delay_x
+ */
+ copy_to_reg((u32 *)&denali_phy[59], (u32 *)&denali_phy_params[59],
+ (63 - 58) * 4);
+ copy_to_reg((u32 *)&denali_phy[187], (u32 *)&denali_phy_params[187],
+ (191 - 186) * 4);
+ copy_to_reg((u32 *)&denali_phy[315], (u32 *)&denali_phy_params[315],
+ (319 - 314) * 4);
+ copy_to_reg((u32 *)&denali_phy[443], (u32 *)&denali_phy_params[443],
+ (447 - 442) * 4);
+
+ /*
+ * phy_dqs_tsel_wr_timing_x 8bits denali_phy_84/212/340/468 offset_8
+ * dqs_tsel_wr_end[7:4] add half cycle
+ * phy_dq_tsel_wr_timing_x 8bits denali_phy_83/211/339/467 offset_8
+ * dq_tsel_wr_end[7:4] add half cycle
+ */
+ writel(denali_phy_params[83] + (0x10 << 16), &denali_phy[83]);
+ writel(denali_phy_params[84] + (0x10 << 8), &denali_phy[84]);
+ writel(denali_phy_params[85], &denali_phy[85]);
+
+ writel(denali_phy_params[211] + (0x10 << 16), &denali_phy[211]);
+ writel(denali_phy_params[212] + (0x10 << 8), &denali_phy[212]);
+ writel(denali_phy_params[213], &denali_phy[213]);
+
+ writel(denali_phy_params[339] + (0x10 << 16), &denali_phy[339]);
+ writel(denali_phy_params[340] + (0x10 << 8), &denali_phy[340]);
+ writel(denali_phy_params[341], &denali_phy[341]);
+
+ writel(denali_phy_params[467] + (0x10 << 16), &denali_phy[467]);
+ writel(denali_phy_params[468] + (0x10 << 8), &denali_phy[468]);
+ writel(denali_phy_params[469], &denali_phy[469]);
+
+ /*
+ * phy_gtlvl_resp_wait_cnt_x
+ * phy_gtlvl_dly_step_x
+ * phy_wrlvl_resp_wait_cnt_x
+ * phy_gtlvl_final_step_x
+ * phy_gtlvl_back_step_x
+ * phy_rdlvl_dly_step_x
+ *
+ * phy_master_delay_step_x
+ * phy_master_delay_wait_x
+ * phy_wrlvl_dly_step_x
+ * phy_rptr_update_x
+ * phy_wdqlvl_dly_step_x
+ */
+ writel(denali_phy_params[87], &denali_phy[87]);
+ writel(denali_phy_params[88], &denali_phy[88]);
+ writel(denali_phy_params[89], &denali_phy[89]);
+ writel(denali_phy_params[90], &denali_phy[90]);
+
+ writel(denali_phy_params[215], &denali_phy[215]);
+ writel(denali_phy_params[216], &denali_phy[216]);
+ writel(denali_phy_params[217], &denali_phy[217]);
+ writel(denali_phy_params[218], &denali_phy[218]);
+
+ writel(denali_phy_params[343], &denali_phy[343]);
+ writel(denali_phy_params[344], &denali_phy[344]);
+ writel(denali_phy_params[345], &denali_phy[345]);
+ writel(denali_phy_params[346], &denali_phy[346]);
+
+ writel(denali_phy_params[471], &denali_phy[471]);
+ writel(denali_phy_params[472], &denali_phy[472]);
+ writel(denali_phy_params[473], &denali_phy[473]);
+ writel(denali_phy_params[474], &denali_phy[474]);
+
+ /*
+ * phy_gtlvl_lat_adj_start_x
+ * phy_gtlvl_rddqs_slv_dly_start_x
+ * phy_rdlvl_rddqs_dq_slv_dly_start_x
+ * phy_wdqlvl_dqdm_slv_dly_start_x
+ */
+ writel(denali_phy_params[80], &denali_phy[80]);
+ writel(denali_phy_params[81], &denali_phy[81]);
+
+ writel(denali_phy_params[208], &denali_phy[208]);
+ writel(denali_phy_params[209], &denali_phy[209]);
+
+ writel(denali_phy_params[336], &denali_phy[336]);
+ writel(denali_phy_params[337], &denali_phy[337]);
+
+ writel(denali_phy_params[464], &denali_phy[464]);
+ writel(denali_phy_params[465], &denali_phy[465]);
+
+ /*
+ * phy_master_delay_start_x
+ * phy_sw_master_mode_x
+ * phy_rddata_en_tsel_dly_x
+ */
+ writel(denali_phy_params[86], &denali_phy[86]);
+ writel(denali_phy_params[214], &denali_phy[214]);
+ writel(denali_phy_params[342], &denali_phy[342]);
+ writel(denali_phy_params[470], &denali_phy[470]);
+
+ /*
+ * phy_rddqz_slave_delay_x
+ * phy_rddqs_dqz_fall_slave_delay_x
+ * phy_rddqs_dqz_rise_slave_delay_x
+ * phy_rddqs_dm_fall_slave_delay_x
+ * phy_rddqs_dm_rise_slave_delay_x
+ * phy_rddqs_gate_slave_delay_x
+ * phy_wrlvl_delay_early_threshold_x
+ * phy_write_path_lat_add_x
+ * phy_rddqs_latency_adjust_x
+ * phy_wrlvl_delay_period_threshold_x
+ * phy_wrlvl_early_force_zero_x
+ */
+ copy_to_reg((u32 *)&denali_phy[64], (u32 *)&denali_phy_params[64],
+ (67 - 63) * 4);
+ clrsetbits_le32(&denali_phy[68], 0xfffffc00,
+ denali_phy_params[68] & 0xfffffc00);
+ copy_to_reg((u32 *)&denali_phy[69], (u32 *)&denali_phy_params[69],
+ (79 - 68) * 4);
+ copy_to_reg((u32 *)&denali_phy[192], (u32 *)&denali_phy_params[192],
+ (195 - 191) * 4);
+ clrsetbits_le32(&denali_phy[196], 0xfffffc00,
+ denali_phy_params[196] & 0xfffffc00);
+ copy_to_reg((u32 *)&denali_phy[197], (u32 *)&denali_phy_params[197],
+ (207 - 196) * 4);
+ copy_to_reg((u32 *)&denali_phy[320], (u32 *)&denali_phy_params[320],
+ (323 - 319) * 4);
+ clrsetbits_le32(&denali_phy[324], 0xfffffc00,
+ denali_phy_params[324] & 0xfffffc00);
+ copy_to_reg((u32 *)&denali_phy[325], (u32 *)&denali_phy_params[325],
+ (335 - 324) * 4);
+
+ copy_to_reg((u32 *)&denali_phy[448], (u32 *)&denali_phy_params[448],
+ (451 - 447) * 4);
+ clrsetbits_le32(&denali_phy[452], 0xfffffc00,
+ denali_phy_params[452] & 0xfffffc00);
+ copy_to_reg((u32 *)&denali_phy[453], (u32 *)&denali_phy_params[453],
+ (463 - 452) * 4);
+
+ /* phy_two_cyc_preamble_x */
+ clrsetbits_le32(&denali_phy[7], 0x3 << 24,
+ denali_phy_params[7] & (0x3 << 24));
+ clrsetbits_le32(&denali_phy[135], 0x3 << 24,
+ denali_phy_params[135] & (0x3 << 24));
+ clrsetbits_le32(&denali_phy[263], 0x3 << 24,
+ denali_phy_params[263] & (0x3 << 24));
+ clrsetbits_le32(&denali_phy[391], 0x3 << 24,
+ denali_phy_params[391] & (0x3 << 24));
+
+ /* speed */
+ if (timings->base.ddr_freq < 400 * MHz)
+ speed = 0x0;
+ else if (timings->base.ddr_freq < 800 * MHz)
+ speed = 0x1;
+ else if (timings->base.ddr_freq < 1200 * MHz)
+ speed = 0x2;
+
+ /* phy_924 phy_pad_fdbk_drive */
+ clrsetbits_le32(&denali_phy[924], 0x3 << 21, speed << 21);
+ /* phy_926 phy_pad_data_drive */
+ clrsetbits_le32(&denali_phy[926], 0x3 << 9, speed << 9);
+ /* phy_927 phy_pad_dqs_drive */
+ clrsetbits_le32(&denali_phy[927], 0x3 << 9, speed << 9);
+ /* phy_928 phy_pad_addr_drive */
+ clrsetbits_le32(&denali_phy[928], 0x3 << 17, speed << 17);
+ /* phy_929 phy_pad_clk_drive */
+ clrsetbits_le32(&denali_phy[929], 0x3 << 17, speed << 17);
+ /* phy_935 phy_pad_cke_drive */
+ clrsetbits_le32(&denali_phy[935], 0x3 << 17, speed << 17);
+ /* phy_937 phy_pad_rst_drive */
+ clrsetbits_le32(&denali_phy[937], 0x3 << 17, speed << 17);
+ /* phy_939 phy_pad_cs_drive */
+ clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17);
+
+ read_mr(dram->chan[channel].pctl, 1, 5, &mr5);
+ set_ds_odt(&dram->chan[channel], timings, true, mr5);
+
+ ctl = lpddr4_get_ctl(timings, phy);
+ set_lpddr4_dq_odt(&dram->chan[channel], timings, ctl, true, true, mr5);
+ set_lpddr4_ca_odt(&dram->chan[channel], timings, ctl, true, true, mr5);
+ set_lpddr4_MR3(&dram->chan[channel], timings, ctl, true, mr5);
+ set_lpddr4_MR12(&dram->chan[channel], timings, ctl, true, mr5);
+ set_lpddr4_MR14(&dram->chan[channel], timings, ctl, true, mr5);
+
+ /*
+ * if phy_sw_master_mode_x not bypass mode,
+ * clear phy_slice_pwr_rdc_disable.
+ * note: need use timings, not ddr_publ_regs
+ */
+ if (!((denali_phy_params[86] >> 8) & (1 << 2))) {
+ clrbits_le32(&denali_phy[10], 1 << 16);
+ clrbits_le32(&denali_phy[138], 1 << 16);
+ clrbits_le32(&denali_phy[266], 1 << 16);
+ clrbits_le32(&denali_phy[394], 1 << 16);
+ }
+
+ /*
+ * when PHY_PER_CS_TRAINING_EN=1, W2W_DIFFCS_DLY_Fx can't
+ * smaller than 8
+ * NOTE: need use timings, not ddr_publ_regs
+ */
+ if ((denali_phy_params[84] >> 16) & 1) {
+ if (((readl(&denali_ctl[217 + ctl]) >> 16) & 0x1f) < 8)
+ clrsetbits_le32(&denali_ctl[217 + ctl],
+ 0x1f << 16, 8 << 16);
+ }
+}
+
+static void lpddr4_set_phy(struct dram_info *dram,
+ struct rk3399_sdram_params *params, u32 phy,
+ struct rk3399_sdram_params *timings)
+{
+ u32 channel;
+
+ for (channel = 0; channel < 2; channel++)
+ lpddr4_copy_phy(dram, params, phy, timings, channel);
+}
+
+static int lpddr4_set_ctl(struct dram_info *dram,
+ struct rk3399_sdram_params *params, u32 ctl, u32 hz)
+{
+ u32 channel;
+ int ret_clk, ret;
+
+ /* cci idle req stall */
+ writel(0x70007, &dram->grf->soc_con0);
+
+ /* enable all clk */
+ setbits_le32(&dram->pmu->pmu_noc_auto_ena, (0x3 << 7));
+
+ /* idle */
+ setbits_le32(&dram->pmu->pmu_bus_idle_req, (0x3 << 18));
+ while ((readl(&dram->pmu->pmu_bus_idle_st) & (0x3 << 18))
+ != (0x3 << 18))
+ ;
+
+ /* change freq */
+ writel((((0x3 << 4) | (1 << 2) | 1) << 16) |
+ (ctl << 4) | (1 << 2) | 1, &dram->cic->cic_ctrl0);
+ while (!(readl(&dram->cic->cic_status0) & (1 << 2)))
+ ;
+
+ ret_clk = clk_set_rate(&dram->ddr_clk, hz);
+ if (ret_clk < 0) {
+ printf("%s clk set failed %d\n", __func__, ret_clk);
+ return ret_clk;
+ }
+
+ writel(0x20002, &dram->cic->cic_ctrl0);
+ while (!(readl(&dram->cic->cic_status0) & (1 << 0)))
+ ;
+
+ /* deidle */
+ clrbits_le32(&dram->pmu->pmu_bus_idle_req, (0x3 << 18));
+ while (readl(&dram->pmu->pmu_bus_idle_st) & (0x3 << 18))
+ ;
+
+ /* clear enable all clk */
+ clrbits_le32(&dram->pmu->pmu_noc_auto_ena, (0x3 << 7));
+
+ /* lpddr4 ctl2 can not do training, all training will fail */
+ if (!(params->base.dramtype == LPDDR4 && ctl == 2)) {
+ for (channel = 0; channel < 2; channel++) {
+ if (!(params->ch[channel].cap_info.col))
+ continue;
+ ret = data_training(dram, channel, params,
+ PI_FULL_TRAINING);
+ if (ret)
+ printf("%s: channel %d training failed!\n",
+ __func__, channel);
+ else
+ debug("%s: channel %d training pass\n",
+ __func__, channel);
+ }
+ }
+
+ return 0;
+}
+
+static int lpddr4_set_rate(struct dram_info *dram,
+ struct rk3399_sdram_params *params)
+{
+ u32 ctl;
+ u32 phy;
+
+ for (ctl = 0; ctl < 2; ctl++) {
+ phy = lpddr4_get_phy(params, ctl);
+
+ lpddr4_set_phy(dram, params, phy, &lpddr4_timings[ctl]);
+ lpddr4_set_ctl(dram, params, ctl,
+ lpddr4_timings[ctl].base.ddr_freq);
+
+ debug("%s: change freq to %d mhz %d, %d\n", __func__,
+ lpddr4_timings[ctl].base.ddr_freq / MHz, ctl, phy);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_RAM_RK3399_LPDDR4 */
+
+static unsigned char calculate_stride(struct rk3399_sdram_params *params)
+{
+ unsigned int stride = params->base.stride;
+ unsigned int channel, chinfo = 0;
+ unsigned int ch_cap[2] = {0, 0};
+ u64 cap;
+
+ for (channel = 0; channel < 2; channel++) {
+ unsigned int cs0_cap = 0;
+ unsigned int cs1_cap = 0;
+ struct sdram_cap_info *cap_info = ¶ms->ch[channel].cap_info;
+
+ if (cap_info->col == 0)
+ continue;
+
+ cs0_cap = (1 << (cap_info->cs0_row + cap_info->col +
+ cap_info->bk + cap_info->bw - 20));
+ if (cap_info->rank > 1)
+ cs1_cap = cs0_cap >> (cap_info->cs0_row
+ - cap_info->cs1_row);
+ if (cap_info->row_3_4) {
+ cs0_cap = cs0_cap * 3 / 4;
+ cs1_cap = cs1_cap * 3 / 4;
+ }
+ ch_cap[channel] = cs0_cap + cs1_cap;
+ chinfo |= 1 << channel;
+ }
+
+ /* stride calculation for 1 channel */
+ if (params->base.num_channels == 1 && chinfo & 1)
+ return 0x17; /* channel a */
+
+ /* stride calculation for 2 channels, default gstride type is 256B */
+ if (ch_cap[0] == ch_cap[1]) {
+ cap = ch_cap[0] + ch_cap[1];
+ switch (cap) {
+ /* 512MB */
+ case 512:
+ stride = 0;
+ break;
+ /* 1GB */
+ case 1024:
+ stride = 0x5;
+ break;
+ /*
+ * 768MB + 768MB same as total 2GB memory
+ * useful space: 0-768MB 1GB-1792MB
+ */
+ case 1536:
+ /* 2GB */
+ case 2048:
+ stride = 0x9;
+ break;
+ /* 1536MB + 1536MB */
+ case 3072:
+ stride = 0x11;
+ break;
+ /* 4GB */
+ case 4096:
+ stride = 0xD;
+ break;
+ default:
+ printf("%s: Unable to calculate stride for ", __func__);
+ print_size((cap * (1 << 20)), " capacity\n");
+ break;
+ }
+ }
+
+ sdram_print_stride(stride);
+
+ return stride;
+}
+
+static void clear_channel_params(struct rk3399_sdram_params *params, u8 channel)
+{
+ params->ch[channel].cap_info.rank = 0;
+ params->ch[channel].cap_info.col = 0;
+ params->ch[channel].cap_info.bk = 0;
+ params->ch[channel].cap_info.bw = 32;
+ params->ch[channel].cap_info.dbw = 32;
+ params->ch[channel].cap_info.row_3_4 = 0;
+ params->ch[channel].cap_info.cs0_row = 0;
+ params->ch[channel].cap_info.cs1_row = 0;
+ params->ch[channel].cap_info.ddrconfig = 0;
+}
+
+static int pctl_init(struct dram_info *dram, struct rk3399_sdram_params *params)
+{
+ int channel;
+ int ret;
+
+ for (channel = 0; channel < 2; channel++) {
+ const struct chan_info *chan = &dram->chan[channel];
+ struct rk3399_cru *cru = dram->cru;
+ struct rk3399_ddr_publ_regs *publ = chan->publ;
+
+ phy_pctrl_reset(cru, channel);
+ phy_dll_bypass_set(publ, params->base.ddr_freq);
+
+ ret = pctl_cfg(dram, chan, channel, params);
+ if (ret < 0) {
+ printf("%s: pctl config failed\n", __func__);
+ return ret;
+ }
+
+ /* start to trigger initialization */
+ pctl_start(dram, channel);
+ }
+
+ return 0;
+}
+
+static int sdram_init(struct dram_info *dram,
+ struct rk3399_sdram_params *params)
+{
+ unsigned char dramtype = params->base.dramtype;
+ unsigned int ddr_freq = params->base.ddr_freq;
+ int channel, ch, rank;
+ int ret;
debug("Starting SDRAM initialization...\n");
@@ -1052,35 +2534,78 @@
return -E2BIG;
}
+ for (ch = 0; ch < 2; ch++) {
+ params->ch[ch].cap_info.rank = 2;
+ for (rank = 2; rank != 0; rank--) {
+ ret = pctl_init(dram, params);
+ if (ret < 0) {
+ printf("%s: pctl init failed\n", __func__);
+ return ret;
+ }
+
+ /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
+ if (dramtype == LPDDR3)
+ udelay(10);
+
+ params->ch[ch].cap_info.rank = rank;
+
+ ret = dram->ops->data_training(dram, ch, rank, params);
+ if (!ret) {
+ debug("%s: data trained for rank %d, ch %d\n",
+ __func__, rank, ch);
+ break;
+ }
+ }
+ /* Computed rank with associated channel number */
+ params->ch[ch].cap_info.rank = rank;
+ }
+
+ params->base.num_channels = 0;
for (channel = 0; channel < 2; channel++) {
const struct chan_info *chan = &dram->chan[channel];
- struct rk3399_ddr_publ_regs *publ = chan->publ;
-
- phy_dll_bypass_set(publ, ddr_freq);
+ struct sdram_cap_info *cap_info = ¶ms->ch[channel].cap_info;
+ u8 training_flag = PI_FULL_TRAINING;
- if (channel >= sdram_params->base.num_channels)
+ if (cap_info->rank == 0) {
+ clear_channel_params(params, channel);
continue;
-
- if (pctl_cfg(chan, channel, sdram_params) != 0) {
- printf("pctl_cfg fail, reset\n");
- return -EIO;
+ } else {
+ params->base.num_channels++;
}
- /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
- if (dramtype == LPDDR3)
- udelay(10);
+ debug("Channel ");
+ debug(channel ? "1: " : "0: ");
+
+ /* LPDDR3 should have write and read gate training */
+ if (params->base.dramtype == LPDDR3)
+ training_flag = PI_WRITE_LEVELING |
+ PI_READ_GATE_TRAINING;
- if (data_training(chan, channel,
- sdram_params, PI_FULL_TRAINING)) {
- printf("SDRAM initialization failed, reset\n");
- return -EIO;
+ if (params->base.dramtype != LPDDR4) {
+ ret = data_training(dram, channel, params,
+ training_flag);
+ if (!ret) {
+ debug("%s: data train failed for channel %d\n",
+ __func__, ret);
+ continue;
+ }
}
- set_ddrconfig(chan, sdram_params, channel,
- sdram_params->ch[channel].ddrconfig);
+ sdram_print_ddr_info(cap_info, ¶ms->base);
+
+ set_ddrconfig(chan, params, channel, cap_info->ddrconfig);
+ }
+
+ if (params->base.num_channels == 0) {
+ printf("%s: ", __func__);
+ sdram_print_dram_type(params->base.dramtype);
+ printf(" - %dMHz failed!\n", params->base.ddr_freq);
+ return -EINVAL;
}
- dram_all_config(dram, sdram_params);
- switch_to_phy_index1(dram, sdram_params);
+
+ params->base.stride = calculate_stride(params);
+ dram_all_config(dram, params);
+ dram->ops->set_rate(dram, params);
debug("Finish SDRAM initialization...\n");
return 0;
@@ -1116,8 +2641,8 @@
int ret;
ret = regmap_init_mem_platdata(dev, dtplat->reg,
- ARRAY_SIZE(dtplat->reg) / 2,
- &plat->map);
+ ARRAY_SIZE(dtplat->reg) / 2,
+ &plat->map);
if (ret)
return ret;
@@ -1125,6 +2650,16 @@
}
#endif
+static const struct sdram_rk3399_ops rk3399_ops = {
+#if !defined(CONFIG_RAM_RK3399_LPDDR4)
+ .data_training = default_data_training,
+ .set_rate = switch_to_phy_index1,
+#else
+ .data_training = lpddr4_mr_detect,
+ .set_rate = lpddr4_set_rate,
+#endif
+};
+
static int rk3399_dmc_init(struct udevice *dev)
{
struct dram_info *priv = dev_get_priv(dev);
@@ -1142,7 +2677,10 @@
return ret;
#endif
+ priv->ops = &rk3399_ops;
priv->cic = syscon_get_first_range(ROCKCHIP_SYSCON_CIC);
+ priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU);
priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
priv->pmusgrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUSGRF);
priv->pmucru = rockchip_get_pmucru();
@@ -1161,8 +2699,9 @@
priv->chan[0].publ, priv->chan[0].msch,
priv->chan[1].pctl, priv->chan[1].pi,
priv->chan[1].publ, priv->chan[1].msch);
- debug("cru %p, cic %p, grf %p, sgrf %p, pmucru %p\n", priv->cru,
- priv->cic, priv->pmugrf, priv->pmusgrf, priv->pmucru);
+ debug("cru %p, cic %p, grf %p, sgrf %p, pmucru %p, pmu %p\n", priv->cru,
+ priv->cic, priv->pmugrf, priv->pmusgrf, priv->pmucru, priv->pmu);
+
#if CONFIG_IS_ENABLED(OF_PLATDATA)
ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->ddr_clk);
#else
@@ -1172,14 +2711,16 @@
printf("%s clk get failed %d\n", __func__, ret);
return ret;
}
+
ret = clk_set_rate(&priv->ddr_clk, params->base.ddr_freq * MHz);
if (ret < 0) {
printf("%s clk set failed %d\n", __func__, ret);
return ret;
}
+
ret = sdram_init(priv, params);
if (ret < 0) {
- printf("%s DRAM init failed%d\n", __func__, ret);
+ printf("%s DRAM init failed %d\n", __func__, ret);
return ret;
}
@@ -1197,10 +2738,10 @@
struct dram_info *priv = dev_get_priv(dev);
priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
- debug("%s: pmugrf=%p\n", __func__, priv->pmugrf);
+ debug("%s: pmugrf = %p\n", __func__, priv->pmugrf);
priv->info.base = CONFIG_SYS_SDRAM_BASE;
- priv->info.size = rockchip_sdram_size(
- (phys_addr_t)&priv->pmugrf->os_reg2);
+ priv->info.size =
+ rockchip_sdram_size((phys_addr_t)&priv->pmugrf->os_reg2);
#endif
return 0;
}
@@ -1218,7 +2759,6 @@
.get_info = rk3399_dmc_get_info,
};
-
static const struct udevice_id rk3399_dmc_ids[] = {
{ .compatible = "rockchip,rk3399-dmc" },
{ }
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 9eb532b..fa6f111 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -40,6 +40,16 @@
Say 'y' here to add support for test processor which does dummy
operations for sandbox platform.
+config REMOTEPROC_STM32_COPRO
+ bool "Support for STM32 coprocessor"
+ select REMOTEPROC
+ depends on DM
+ depends on ARCH_STM32MP
+ depends on OF_CONTROL
+ help
+ Say 'y' here to add support for STM32 Cortex-M4 coprocessors via the
+ remoteproc framework.
+
config REMOTEPROC_TI_POWER
bool "Support for TI Power processor"
select REMOTEPROC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 77eb708..b9a06ac 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -4,10 +4,11 @@
# Texas Instruments Incorporated - http://www.ti.com/
#
-obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o
+obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
# Remote proc drivers - Please keep this list alphabetically sorted.
obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
obj-$(CONFIG_REMOTEPROC_K3) += k3_rproc.o
obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
+obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o
diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c
new file mode 100644
index 0000000..67937a7
--- /dev/null
+++ b/drivers/remoteproc/rproc-elf-loader.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+#include <common.h>
+#include <dm.h>
+#include <elf.h>
+#include <remoteproc.h>
+
+/* Basic function to verify ELF32 image format */
+int rproc_elf32_sanity_check(ulong addr, ulong size)
+{
+ Elf32_Ehdr *ehdr;
+ char class;
+
+ if (!addr) {
+ pr_debug("Invalid fw address?\n");
+ return -EFAULT;
+ }
+
+ if (size < sizeof(Elf32_Ehdr)) {
+ pr_debug("Image is too small\n");
+ return -ENOSPC;
+ }
+
+ ehdr = (Elf32_Ehdr *)addr;
+ class = ehdr->e_ident[EI_CLASS];
+
+ if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
+ pr_debug("Not an executable ELF32 image\n");
+ return -EPROTONOSUPPORT;
+ }
+
+ /* We assume the firmware has the same endianness as the host */
+# ifdef __LITTLE_ENDIAN
+ if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+# else /* BIG ENDIAN */
+ if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+# endif
+ pr_debug("Unsupported firmware endianness\n");
+ return -EILSEQ;
+ }
+
+ if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
+ pr_debug("Image is too small\n");
+ return -ENOSPC;
+ }
+
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+ pr_debug("Image is corrupted (bad magic)\n");
+ return -EBADF;
+ }
+
+ if (ehdr->e_phnum == 0) {
+ pr_debug("No loadable segments\n");
+ return -ENOEXEC;
+ }
+
+ if (ehdr->e_phoff > size) {
+ pr_debug("Firmware size is too small\n");
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+/* A very simple elf loader, assumes the image is valid */
+int rproc_elf32_load_image(struct udevice *dev, unsigned long addr)
+{
+ Elf32_Ehdr *ehdr; /* Elf header structure pointer */
+ Elf32_Phdr *phdr; /* Program header structure pointer */
+ const struct dm_rproc_ops *ops;
+ unsigned int i;
+
+ ehdr = (Elf32_Ehdr *)addr;
+ phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
+
+ ops = rproc_get_ops(dev);
+
+ /* Load each program header */
+ for (i = 0; i < ehdr->e_phnum; ++i) {
+ void *dst = (void *)(uintptr_t)phdr->p_paddr;
+ void *src = (void *)addr + phdr->p_offset;
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ if (ops->device_to_virt)
+ dst = ops->device_to_virt(dev, (ulong)dst);
+
+ dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
+ i, dst, phdr->p_filesz);
+ if (phdr->p_filesz)
+ memcpy(dst, src, phdr->p_filesz);
+ if (phdr->p_filesz != phdr->p_memsz)
+ memset(dst + phdr->p_filesz, 0x00,
+ phdr->p_memsz - phdr->p_filesz);
+ flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
+ roundup((unsigned long)dst + phdr->p_filesz,
+ ARCH_DMA_MINALIGN) -
+ rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+ ++phdr;
+ }
+
+ return 0;
+}
diff --git a/drivers/remoteproc/sandbox_testproc.c b/drivers/remoteproc/sandbox_testproc.c
index 51a67e6..5f35119 100644
--- a/drivers/remoteproc/sandbox_testproc.c
+++ b/drivers/remoteproc/sandbox_testproc.c
@@ -8,6 +8,7 @@
#include <dm.h>
#include <errno.h>
#include <remoteproc.h>
+#include <asm/io.h>
/**
* enum sandbox_state - different device states
@@ -300,6 +301,23 @@
return ret;
}
+#define SANDBOX_RPROC_DEV_TO_PHY_OFFSET 0x1000
+/**
+ * sandbox_testproc_device_to_virt() - Convert device address to virtual address
+ * @dev: device to operate upon
+ * @da: device address
+ * @return converted virtual address
+ */
+static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da)
+{
+ u64 paddr;
+
+ /* Use a simple offset conversion */
+ paddr = da + SANDBOX_RPROC_DEV_TO_PHY_OFFSET;
+
+ return phys_to_virt(paddr);
+}
+
static const struct dm_rproc_ops sandbox_testproc_ops = {
.init = sandbox_testproc_init,
.reset = sandbox_testproc_reset,
@@ -308,6 +326,7 @@
.stop = sandbox_testproc_stop,
.is_running = sandbox_testproc_is_running,
.ping = sandbox_testproc_ping,
+ .device_to_virt = sandbox_testproc_device_to_virt,
};
static const struct udevice_id sandbox_ids[] = {
diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c
new file mode 100644
index 0000000..de3b972
--- /dev/null
+++ b/drivers/remoteproc/stm32_copro.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <regmap.h>
+#include <remoteproc.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/io.h>
+
+#define RCC_GCR_HOLD_BOOT 0
+#define RCC_GCR_RELEASE_BOOT 1
+
+/**
+ * struct stm32_copro_privdata - power processor private data
+ * @reset_ctl: reset controller handle
+ * @hold_boot_regmap: regmap for remote processor reset hold boot
+ * @hold_boot_offset: offset of the register controlling the hold boot setting
+ * @hold_boot_mask: bitmask of the register for the hold boot field
+ * @is_running: is the remote processor running
+ */
+struct stm32_copro_privdata {
+ struct reset_ctl reset_ctl;
+ struct regmap *hold_boot_regmap;
+ uint hold_boot_offset;
+ uint hold_boot_mask;
+ bool is_running;
+};
+
+/**
+ * stm32_copro_probe() - Basic probe
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_probe(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+ struct regmap *regmap;
+ const fdt32_t *cell;
+ int len, ret;
+
+ priv = dev_get_priv(dev);
+
+ regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscfg-holdboot");
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "unable to find holdboot regmap (%ld)\n",
+ PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ cell = dev_read_prop(dev, "st,syscfg-holdboot", &len);
+ if (len < 3 * sizeof(fdt32_t)) {
+ dev_err(dev, "holdboot offset and mask not available\n");
+ return -EINVAL;
+ }
+
+ priv->hold_boot_regmap = regmap;
+ priv->hold_boot_offset = fdtdec_get_number(cell + 1, 1);
+ priv->hold_boot_mask = fdtdec_get_number(cell + 2, 1);
+
+ ret = reset_get_by_index(dev, 0, &priv->reset_ctl);
+ if (ret) {
+ dev_err(dev, "failed to get reset (%d)\n", ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "probed\n");
+
+ return 0;
+}
+
+/**
+ * stm32_copro_set_hold_boot() - Hold boot bit management
+ * @dev: corresponding STM32 remote processor device
+ * @hold: hold boot value
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_set_hold_boot(struct udevice *dev, bool hold)
+{
+ struct stm32_copro_privdata *priv;
+ uint val;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ val = hold ? RCC_GCR_HOLD_BOOT : RCC_GCR_RELEASE_BOOT;
+
+ /*
+ * Note: shall run an SMC call (STM32_SMC_RCC) if platform is secured.
+ * To be updated when the code for this SMC service is available which
+ * is not the case for the time being.
+ */
+ ret = regmap_update_bits(priv->hold_boot_regmap, priv->hold_boot_offset,
+ priv->hold_boot_mask, val);
+ if (ret)
+ dev_err(dev, "failed to set hold boot\n");
+
+ return ret;
+}
+
+/**
+ * stm32_copro_device_to_virt() - Convert device address to virtual address
+ * @dev: corresponding STM32 remote processor device
+ * @da: device address
+ * @return converted virtual address
+ */
+static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da)
+{
+ fdt32_t in_addr = cpu_to_be32(da);
+ u64 paddr;
+
+ paddr = dev_translate_dma_address(dev, &in_addr);
+ if (paddr == OF_BAD_ADDR) {
+ dev_err(dev, "Unable to convert address %ld\n", da);
+ return NULL;
+ }
+
+ return phys_to_virt(paddr);
+}
+
+/**
+ * stm32_copro_load() - Loadup the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @addr: Address in memory where image is stored
+ * @size: Size in bytes of the image
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct stm32_copro_privdata *priv;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ ret = stm32_copro_set_hold_boot(dev, true);
+ if (ret)
+ return ret;
+
+ ret = reset_assert(&priv->reset_ctl);
+ if (ret) {
+ dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
+ return ret;
+ }
+
+ /* Support only ELF32 image */
+ ret = rproc_elf32_sanity_check(addr, size);
+ if (ret) {
+ dev_err(dev, "Invalid ELF32 image (%d)\n", ret);
+ return ret;
+ }
+
+ return rproc_elf32_load_image(dev, addr);
+}
+
+/**
+ * stm32_copro_start() - Start the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_start(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ /* move hold boot from true to false start the copro */
+ ret = stm32_copro_set_hold_boot(dev, false);
+ if (ret)
+ return ret;
+
+ /*
+ * Once copro running, reset hold boot flag to avoid copro
+ * rebooting autonomously
+ */
+ ret = stm32_copro_set_hold_boot(dev, true);
+ priv->is_running = !ret;
+ return ret;
+}
+
+/**
+ * stm32_copro_reset() - Reset the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_reset(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ ret = stm32_copro_set_hold_boot(dev, true);
+ if (ret)
+ return ret;
+
+ ret = reset_assert(&priv->reset_ctl);
+ if (ret) {
+ dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
+ return ret;
+ }
+
+ priv->is_running = false;
+
+ return 0;
+}
+
+/**
+ * stm32_copro_stop() - Stop the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_stop(struct udevice *dev)
+{
+ return stm32_copro_reset(dev);
+}
+
+/**
+ * stm32_copro_is_running() - Is the STM32 remote processor running
+ * @dev: corresponding STM32 remote processor device
+ * @return 1 if the remote processor is running, 0 otherwise
+ */
+static int stm32_copro_is_running(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+
+ priv = dev_get_priv(dev);
+ return priv->is_running;
+}
+
+static const struct dm_rproc_ops stm32_copro_ops = {
+ .load = stm32_copro_load,
+ .start = stm32_copro_start,
+ .stop = stm32_copro_stop,
+ .reset = stm32_copro_reset,
+ .is_running = stm32_copro_is_running,
+ .device_to_virt = stm32_copro_device_to_virt,
+};
+
+static const struct udevice_id stm32_copro_ids[] = {
+ {.compatible = "st,stm32mp1-rproc"},
+ {}
+};
+
+U_BOOT_DRIVER(stm32_copro) = {
+ .name = "stm32_m4_proc",
+ .of_match = stm32_copro_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &stm32_copro_ops,
+ .probe = stm32_copro_probe,
+ .priv_auto_alloc_size = sizeof(struct stm32_copro_privdata),
+};
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 532e94d..0b58a18 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -120,4 +120,10 @@
Enable driver for ST's M41T62 compatible RTC devices (like RV-4162).
It is a serial (I2C) real-time clock (RTC) with alarm.
+config RTC_STM32
+ bool "Enable STM32 RTC driver"
+ depends on DM_RTC
+ help
+ Enable STM32 RTC driver. This driver supports the rtc that is present
+ on some STM32 SoCs.
endmenu
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 915adb8..f97a669 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -51,5 +51,6 @@
obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o
obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o
obj-$(CONFIG_RTC_S35392A) += s35392a.o
+obj-$(CONFIG_RTC_STM32) += stm32_rtc.o
obj-$(CONFIG_SANDBOX) += sandbox_rtc.o
obj-$(CONFIG_RTC_X1205) += x1205.o
diff --git a/drivers/rtc/ds3231.c b/drivers/rtc/ds3231.c
index 9352ff8..79b026a 100644
--- a/drivers/rtc/ds3231.c
+++ b/drivers/rtc/ds3231.c
@@ -2,6 +2,9 @@
/*
* (C) Copyright 2006
* Markus Klotzbuecher, mk@denx.de
+ *
+ * (C) Copyright 2019 NXP
+ * Chuanhua Han <chuanhua.han@nxp.com>
*/
/*
@@ -13,6 +16,7 @@
#include <common.h>
#include <command.h>
+#include <dm.h>
#include <rtc.h>
#include <i2c.h>
@@ -50,6 +54,7 @@
#define RTC_STAT_BIT_EN32KHZ 0x8 /* Enable 32KHz Output */
+#if !CONFIG_IS_ENABLED(DM_RTC)
static uchar rtc_read (uchar reg);
static void rtc_write (uchar reg, uchar val);
@@ -164,3 +169,105 @@
{
i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
}
+#else
+static int ds3231_rtc_get(struct udevice *dev, struct rtc_time *tmp)
+{
+ uchar sec, min, hour, mday, wday, mon_cent, year, status;
+
+ status = dm_i2c_reg_read(dev, RTC_STAT_REG_ADDR);
+ sec = dm_i2c_reg_read(dev, RTC_SEC_REG_ADDR);
+ min = dm_i2c_reg_read(dev, RTC_MIN_REG_ADDR);
+ hour = dm_i2c_reg_read(dev, RTC_HR_REG_ADDR);
+ wday = dm_i2c_reg_read(dev, RTC_DAY_REG_ADDR);
+ mday = dm_i2c_reg_read(dev, RTC_DATE_REG_ADDR);
+ mon_cent = dm_i2c_reg_read(dev, RTC_MON_REG_ADDR);
+ year = dm_i2c_reg_read(dev, RTC_YR_REG_ADDR);
+
+ if (status & RTC_STAT_BIT_OSF) {
+ printf("### Warning: RTC oscillator has stopped\n");
+ /* clear the OSF flag */
+ dm_i2c_reg_write(dev, RTC_STAT_REG_ADDR,
+ dm_i2c_reg_read(dev, RTC_STAT_REG_ADDR)
+ & ~RTC_STAT_BIT_OSF);
+ return -EINVAL;
+ }
+
+ tmp->tm_sec = bcd2bin(sec & 0x7F);
+ tmp->tm_min = bcd2bin(min & 0x7F);
+ tmp->tm_hour = bcd2bin(hour & 0x3F);
+ tmp->tm_mday = bcd2bin(mday & 0x3F);
+ tmp->tm_mon = bcd2bin(mon_cent & 0x1F);
+ tmp->tm_year = bcd2bin(year) + ((mon_cent & 0x80) ? 2000 : 1900);
+ tmp->tm_wday = bcd2bin((wday - 1) & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+static int ds3231_rtc_set(struct udevice *dev, const struct rtc_time *tmp)
+{
+ uchar century;
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ dm_i2c_reg_write(dev, RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100));
+
+ century = (tmp->tm_year >= 2000) ? 0x80 : 0;
+ dm_i2c_reg_write(dev, RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon) | century);
+
+ dm_i2c_reg_write(dev, RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday + 1));
+ dm_i2c_reg_write(dev, RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday));
+ dm_i2c_reg_write(dev, RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour));
+ dm_i2c_reg_write(dev, RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min));
+ dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec));
+
+ return 0;
+}
+
+static int ds3231_rtc_reset(struct udevice *dev)
+{
+ int ret;
+
+ ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR,
+ RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int ds3231_probe(struct udevice *dev)
+{
+ i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
+ DM_I2C_CHIP_WR_ADDRESS);
+
+ return 0;
+}
+
+static const struct rtc_ops ds3231_rtc_ops = {
+ .get = ds3231_rtc_get,
+ .set = ds3231_rtc_set,
+ .reset = ds3231_rtc_reset,
+};
+
+static const struct udevice_id ds3231_rtc_ids[] = {
+ { .compatible = "dallas,ds3231" },
+ { .compatible = "dallas,ds3232" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_ds3231) = {
+ .name = "rtc-ds3231",
+ .id = UCLASS_RTC,
+ .probe = ds3231_probe,
+ .of_match = ds3231_rtc_ids,
+ .ops = &ds3231_rtc_ops,
+};
+#endif
diff --git a/drivers/rtc/stm32_rtc.c b/drivers/rtc/stm32_rtc.c
new file mode 100644
index 0000000..abd3390
--- /dev/null
+++ b/drivers/rtc/stm32_rtc.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <linux/iopoll.h>
+
+#define STM32_RTC_TR 0x00
+#define STM32_RTC_DR 0x04
+#define STM32_RTC_ISR 0x0C
+#define STM32_RTC_PRER 0x10
+#define STM32_RTC_CR 0x18
+#define STM32_RTC_WPR 0x24
+
+/* STM32_RTC_TR bit fields */
+#define STM32_RTC_SEC_SHIFT 0
+#define STM32_RTC_SEC GENMASK(6, 0)
+#define STM32_RTC_MIN_SHIFT 8
+#define STM32_RTC_MIN GENMASK(14, 8)
+#define STM32_RTC_HOUR_SHIFT 16
+#define STM32_RTC_HOUR GENMASK(21, 16)
+
+/* STM32_RTC_DR bit fields */
+#define STM32_RTC_DATE_SHIFT 0
+#define STM32_RTC_DATE GENMASK(5, 0)
+#define STM32_RTC_MONTH_SHIFT 8
+#define STM32_RTC_MONTH GENMASK(12, 8)
+#define STM32_RTC_WDAY_SHIFT 13
+#define STM32_RTC_WDAY GENMASK(15, 13)
+#define STM32_RTC_YEAR_SHIFT 16
+#define STM32_RTC_YEAR GENMASK(23, 16)
+
+/* STM32_RTC_CR bit fields */
+#define STM32_RTC_CR_FMT BIT(6)
+
+/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
+#define STM32_RTC_ISR_INITS BIT(4)
+#define STM32_RTC_ISR_RSF BIT(5)
+#define STM32_RTC_ISR_INITF BIT(6)
+#define STM32_RTC_ISR_INIT BIT(7)
+
+/* STM32_RTC_PRER bit fields */
+#define STM32_RTC_PRER_PRED_S_SHIFT 0
+#define STM32_RTC_PRER_PRED_S GENMASK(14, 0)
+#define STM32_RTC_PRER_PRED_A_SHIFT 16
+#define STM32_RTC_PRER_PRED_A GENMASK(22, 16)
+
+/* STM32_RTC_WPR key constants */
+#define RTC_WPR_1ST_KEY 0xCA
+#define RTC_WPR_2ND_KEY 0x53
+#define RTC_WPR_WRONG_KEY 0xFF
+
+struct stm32_rtc_priv {
+ fdt_addr_t base;
+};
+
+static int stm32_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 tr, dr;
+
+ tr = readl(priv->base + STM32_RTC_TR);
+ dr = readl(priv->base + STM32_RTC_DR);
+
+ tm->tm_sec = bcd2bin((tr & STM32_RTC_SEC) >> STM32_RTC_SEC_SHIFT);
+ tm->tm_min = bcd2bin((tr & STM32_RTC_MIN) >> STM32_RTC_MIN_SHIFT);
+ tm->tm_hour = bcd2bin((tr & STM32_RTC_HOUR) >> STM32_RTC_HOUR_SHIFT);
+
+ tm->tm_mday = bcd2bin((dr & STM32_RTC_DATE) >> STM32_RTC_DATE_SHIFT);
+ tm->tm_mon = bcd2bin((dr & STM32_RTC_MONTH) >> STM32_RTC_MONTH_SHIFT);
+ tm->tm_year = bcd2bin((dr & STM32_RTC_YEAR) >> STM32_RTC_YEAR_SHIFT);
+ tm->tm_wday = bcd2bin((dr & STM32_RTC_WDAY) >> STM32_RTC_WDAY_SHIFT);
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ dev_dbg(dev, "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+static void stm32_rtc_unlock(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+
+ writel(RTC_WPR_1ST_KEY, priv->base + STM32_RTC_WPR);
+ writel(RTC_WPR_2ND_KEY, priv->base + STM32_RTC_WPR);
+}
+
+static void stm32_rtc_lock(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+
+ writel(RTC_WPR_WRONG_KEY, priv->base + STM32_RTC_WPR);
+}
+
+static int stm32_rtc_enter_init_mode(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ if (!(isr & STM32_RTC_ISR_INITF)) {
+ isr |= STM32_RTC_ISR_INIT;
+ writel(isr, priv->base + STM32_RTC_ISR);
+
+ return readl_poll_timeout(priv->base + STM32_RTC_ISR,
+ isr,
+ (isr & STM32_RTC_ISR_INITF),
+ 100000);
+ }
+
+ return 0;
+}
+
+static int stm32_rtc_wait_sync(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ isr &= ~STM32_RTC_ISR_RSF;
+ writel(isr, priv->base + STM32_RTC_ISR);
+
+ /*
+ * Wait for RSF to be set to ensure the calendar registers are
+ * synchronised, it takes around 2 rtc_ck clock cycles
+ */
+ return readl_poll_timeout(priv->base + STM32_RTC_ISR,
+ isr, (isr & STM32_RTC_ISR_RSF),
+ 100000);
+}
+
+static void stm32_rtc_exit_init_mode(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ isr &= ~STM32_RTC_ISR_INIT;
+ writel(isr, priv->base + STM32_RTC_ISR);
+}
+
+static int stm32_rtc_set_time(struct udevice *dev, u32 time, u32 date)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ stm32_rtc_unlock(dev);
+
+ ret = stm32_rtc_enter_init_mode(dev);
+ if (ret)
+ goto lock;
+
+ writel(time, priv->base + STM32_RTC_TR);
+ writel(date, priv->base + STM32_RTC_DR);
+
+ stm32_rtc_exit_init_mode(dev);
+
+ ret = stm32_rtc_wait_sync(dev);
+
+lock:
+ stm32_rtc_lock(dev);
+ return ret;
+}
+
+static int stm32_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ u32 t, d;
+
+ dev_dbg(dev, "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ /* Time in BCD format */
+ t = (bin2bcd(tm->tm_sec) << STM32_RTC_SEC_SHIFT) & STM32_RTC_SEC;
+ t |= (bin2bcd(tm->tm_min) << STM32_RTC_MIN_SHIFT) & STM32_RTC_MIN;
+ t |= (bin2bcd(tm->tm_hour) << STM32_RTC_HOUR_SHIFT) & STM32_RTC_HOUR;
+
+ /* Date in BCD format */
+ d = (bin2bcd(tm->tm_mday) << STM32_RTC_DATE_SHIFT) & STM32_RTC_DATE;
+ d |= (bin2bcd(tm->tm_mon) << STM32_RTC_MONTH_SHIFT) & STM32_RTC_MONTH;
+ d |= (bin2bcd(tm->tm_year) << STM32_RTC_YEAR_SHIFT) & STM32_RTC_YEAR;
+ d |= (bin2bcd(tm->tm_wday) << STM32_RTC_WDAY_SHIFT) & STM32_RTC_WDAY;
+
+ return stm32_rtc_set_time(dev, t, d);
+}
+
+static int stm32_rtc_reset(struct udevice *dev)
+{
+ dev_dbg(dev, "Reset DATE\n");
+
+ return stm32_rtc_set_time(dev, 0, 0);
+}
+
+static int stm32_rtc_init(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
+ unsigned int rate;
+ struct clk clk;
+ int ret;
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ if (isr & STM32_RTC_ISR_INITS)
+ return 0;
+
+ ret = clk_get_by_index(dev, 1, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ clk_free(&clk);
+ return ret;
+ }
+
+ rate = clk_get_rate(&clk);
+
+ /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
+ pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
+ pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
+
+ for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) {
+ pred_s = (rate / (pred_a + 1)) - 1;
+
+ if (((pred_s + 1) * (pred_a + 1)) == rate)
+ break;
+ }
+
+ /*
+ * Can't find a 1Hz, so give priority to RTC power consumption
+ * by choosing the higher possible value for prediv_a
+ */
+ if (pred_s > pred_s_max || pred_a > pred_a_max) {
+ pred_a = pred_a_max;
+ pred_s = (rate / (pred_a + 1)) - 1;
+ }
+
+ stm32_rtc_unlock(dev);
+
+ ret = stm32_rtc_enter_init_mode(dev);
+ if (ret) {
+ dev_err(dev,
+ "Can't enter in init mode. Prescaler config failed.\n");
+ goto unlock;
+ }
+
+ prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
+ prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
+ writel(prer, priv->base + STM32_RTC_PRER);
+
+ /* Force 24h time format */
+ cr = readl(priv->base + STM32_RTC_CR);
+ cr &= ~STM32_RTC_CR_FMT;
+ writel(cr, priv->base + STM32_RTC_CR);
+
+ stm32_rtc_exit_init_mode(dev);
+
+ ret = stm32_rtc_wait_sync(dev);
+
+unlock:
+ stm32_rtc_lock(dev);
+
+ if (ret) {
+ clk_disable(&clk);
+ clk_free(&clk);
+ }
+
+ return ret;
+}
+
+static int stm32_rtc_probe(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ int ret;
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ clk_free(&clk);
+ return ret;
+ }
+
+ ret = stm32_rtc_init(dev);
+
+ if (ret) {
+ clk_disable(&clk);
+ clk_free(&clk);
+ }
+
+ return ret;
+}
+
+static const struct rtc_ops stm32_rtc_ops = {
+ .get = stm32_rtc_get,
+ .set = stm32_rtc_set,
+ .reset = stm32_rtc_reset,
+};
+
+static const struct udevice_id stm32_rtc_ids[] = {
+ { .compatible = "st,stm32mp1-rtc" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_stm32) = {
+ .name = "rtc-stm32",
+ .id = UCLASS_RTC,
+ .probe = stm32_rtc_probe,
+ .of_match = stm32_rtc_ids,
+ .ops = &stm32_rtc_ops,
+ .priv_auto_alloc_size = sizeof(struct stm32_rtc_priv),
+};
diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c
index 8d612f2..958c394 100644
--- a/drivers/spi/stm32_qspi.c
+++ b/drivers/spi/stm32_qspi.c
@@ -526,7 +526,6 @@
};
static const struct udevice_id stm32_qspi_ids[] = {
- { .compatible = "st,stm32-qspi" },
{ .compatible = "st,stm32f469-qspi" },
{ }
};
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c
index 12ee6eb..97a4c74 100644
--- a/drivers/timer/timer-uclass.c
+++ b/drivers/timer/timer-uclass.c
@@ -48,6 +48,10 @@
int err;
ulong ret;
+ /* It is possible that a timer device has a null ofnode */
+ if (!dev_of_valid(dev))
+ return 0;
+
err = clk_get_by_index(dev, 0, &timer_clk);
if (!err) {
ret = clk_get_rate(&timer_clk);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index b1188bc..ac68aa2 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -24,6 +24,7 @@
config USB_XHCI_DWC3_OF_SIMPLE
bool "DesignWare USB3 DRD Generic OF Simple Glue Layer"
depends on DM_USB
+ default y if ARCH_ROCKCHIP
default y if DRA7XX
help
Support USB2/3 functionality in simple SoC integrations with
diff --git a/drivers/usb/host/dwc3-of-simple.c b/drivers/usb/host/dwc3-of-simple.c
index b118997..45df614 100644
--- a/drivers/usb/host/dwc3-of-simple.c
+++ b/drivers/usb/host/dwc3-of-simple.c
@@ -92,6 +92,7 @@
static const struct udevice_id dwc3_of_simple_ids[] = {
{ .compatible = "amlogic,meson-gxl-dwc3" },
+ { .compatible = "rockchip,rk3399-dwc3" },
{ .compatible = "ti,dwc3" },
{ }
};
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c
index 83b9f11..9e8cae7 100644
--- a/drivers/usb/host/xhci-dwc3.c
+++ b/drivers/usb/host/xhci-dwc3.c
@@ -118,6 +118,8 @@
struct dwc3 *dwc3_reg;
enum usb_dr_mode dr_mode;
struct xhci_dwc3_platdata *plat = dev_get_platdata(dev);
+ const char *phy;
+ u32 reg;
int ret;
hccr = (struct xhci_hccr *)((uintptr_t)dev_read_addr(dev));
@@ -132,6 +134,24 @@
dwc3_core_init(dwc3_reg);
+ /* Set dwc3 usb2 phy config */
+ reg = readl(&dwc3_reg->g_usb2phycfg[0]);
+
+ phy = dev_read_string(dev, "phy_type");
+ if (phy && strcmp(phy, "utmi_wide") == 0) {
+ reg |= DWC3_GUSB2PHYCFG_PHYIF;
+ reg &= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK;
+ reg |= DWC3_GUSB2PHYCFG_USBTRDTIM_16BIT;
+ }
+
+ if (dev_read_bool(dev, "snps,dis_enblslpm-quirk"))
+ reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+
+ if (dev_read_bool(dev, "snps,dis-u2-freeclk-exists-quirk"))
+ reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
+ writel(reg, &dwc3_reg->g_usb2phycfg[0]);
+
dr_mode = usb_get_dr_mode(dev_of_offset(dev));
if (dr_mode == USB_DR_MODE_UNKNOWN)
/* by default set dual role mode to HOST */
diff --git a/drivers/usb/host/xhci-rockchip.c b/drivers/usb/host/xhci-rockchip.c
index f19bea3..e7b0dbc 100644
--- a/drivers/usb/host/xhci-rockchip.c
+++ b/drivers/usb/host/xhci-rockchip.c
@@ -167,7 +167,6 @@
}
static const struct udevice_id xhci_usb_ids[] = {
- { .compatible = "rockchip,rk3399-xhci" },
{ .compatible = "rockchip,rk3328-xhci" },
{ }
};
@@ -187,7 +186,6 @@
};
static const struct udevice_id usb_phy_ids[] = {
- { .compatible = "rockchip,rk3399-usb3-phy" },
{ .compatible = "rockchip,rk3328-usb3-phy" },
{ }
};
diff --git a/drivers/video/rockchip/rk3288_hdmi.c b/drivers/video/rockchip/rk3288_hdmi.c
index 315d3ad..3d25ce9 100644
--- a/drivers/video/rockchip/rk3288_hdmi.c
+++ b/drivers/video/rockchip/rk3288_hdmi.c
@@ -33,7 +33,7 @@
/* hdmi data from vop id */
rk_clrsetreg(&grf->soc_con6, 1 << 4, (vop_id == 1) ? (1 << 4) : 0);
- return 0;
+ return dw_hdmi_enable(&priv->hdmi, edid);
}
static int rk3288_hdmi_ofdata_to_platdata(struct udevice *dev)
diff --git a/env/env.c b/env/env.c
index 4b417b9..d3cbe2f 100644
--- a/env/env.c
+++ b/env/env.c
@@ -24,6 +24,8 @@
entry->load += gd->reloc_off;
if (entry->save)
entry->save += gd->reloc_off;
+ if (entry->erase)
+ entry->erase += gd->reloc_off;
if (entry->init)
entry->init += gd->reloc_off;
}
@@ -254,6 +256,34 @@
return -ENODEV;
}
+int env_erase(void)
+{
+ struct env_driver *drv;
+
+ drv = env_driver_lookup(ENVOP_ERASE, gd->env_load_prio);
+ if (drv) {
+ int ret;
+
+ if (!drv->erase)
+ return -ENODEV;
+
+ if (!env_has_inited(drv->location))
+ return -ENODEV;
+
+ printf("Erasing Environment on %s... ", drv->name);
+ ret = drv->erase();
+ if (ret)
+ printf("Failed (%d)\n", ret);
+ else
+ printf("OK\n");
+
+ if (!ret)
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
int env_init(void)
{
struct env_driver *drv;
diff --git a/env/mmc.c b/env/mmc.c
index c3cf35d..b7b833f 100644
--- a/env/mmc.c
+++ b/env/mmc.c
@@ -242,6 +242,54 @@
fini_mmc_for_env(mmc);
return ret;
}
+
+#if defined(CONFIG_CMD_ERASEENV)
+static inline int erase_env(struct mmc *mmc, unsigned long size,
+ unsigned long offset)
+{
+ uint blk_start, blk_cnt, n;
+ struct blk_desc *desc = mmc_get_blk_desc(mmc);
+
+ blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
+ blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
+
+ n = blk_derase(desc, blk_start, blk_cnt);
+ printf("%d blocks erased: %s\n", n, (n == blk_cnt) ? "OK" : "ERROR");
+
+ return (n == blk_cnt) ? 0 : 1;
+}
+
+static int env_mmc_erase(void)
+{
+ int dev = mmc_get_env_dev();
+ struct mmc *mmc = find_mmc_device(dev);
+ int ret, copy = 0;
+ u32 offset;
+ const char *errmsg;
+
+ errmsg = init_mmc_for_env(mmc);
+ if (errmsg) {
+ printf("%s\n", errmsg);
+ return 1;
+ }
+
+ if (mmc_get_env_addr(mmc, copy, &offset))
+ return CMD_RET_FAILURE;
+
+ ret = erase_env(mmc, CONFIG_ENV_SIZE, offset);
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+ copy = 1;
+
+ if (mmc_get_env_addr(mmc, copy, &offset))
+ return CMD_RET_FAILURE;
+
+ ret |= erase_env(mmc, CONFIG_ENV_SIZE, offset);
+#endif
+
+ return ret;
+}
+#endif /* CONFIG_CMD_ERASEENV */
#endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
static inline int read_env(struct mmc *mmc, unsigned long size,
@@ -351,5 +399,8 @@
.load = env_mmc_load,
#ifndef CONFIG_SPL_BUILD
.save = env_save_ptr(env_mmc_save),
+#if defined(CONFIG_CMD_ERASEENV)
+ .erase = env_mmc_erase,
+#endif
#endif
};
diff --git a/fs/cbfs/cbfs.c b/fs/cbfs/cbfs.c
index 7b2513c..af4d3c5 100644
--- a/fs/cbfs/cbfs.c
+++ b/fs/cbfs/cbfs.c
@@ -55,7 +55,7 @@
memcpy(&dest->magic, &src->magic, sizeof(dest->magic));
dest->len = be32_to_cpu(src->len);
dest->type = be32_to_cpu(src->type);
- dest->checksum = be32_to_cpu(src->checksum);
+ dest->attributes_offset = be32_to_cpu(src->attributes_offset);
dest->offset = be32_to_cpu(src->offset);
}
@@ -108,7 +108,7 @@
newNode->name = (char *)fileHeader +
sizeof(struct cbfs_fileheader);
newNode->name_length = name_len;
- newNode->checksum = header.checksum;
+ newNode->attributes_offset = header.attributes_offset;
step = header.len;
if (step % align)
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
index 464c33d..5bf78b5 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -570,7 +570,7 @@
g_parent_inode->size = cpu_to_le32(new_size);
new_blockcnt = le32_to_cpu(g_parent_inode->blockcnt);
- new_blockcnt += fs->sect_perblk;
+ new_blockcnt += fs->blksz >> LOG2_SECTOR_SIZE;
g_parent_inode->blockcnt = cpu_to_le32(new_blockcnt);
if (ext4fs_put_metadata
@@ -1571,8 +1571,12 @@
int log2blksz = get_fs()->dev_desc->log2blksz;
int desc_size = get_fs()->gdsize;
+ if (desc_size == 0)
+ return 0;
desc_per_blk = EXT2_BLOCK_SIZE(data) / desc_size;
+ if (desc_per_blk == 0)
+ return 0;
blkno = le32_to_cpu(data->sblock.first_data_block) + 1 +
group / desc_per_blk;
blkoff = (group % desc_per_blk) * desc_size;
@@ -1602,6 +1606,10 @@
/* It is easier to calculate if the first inode is 0. */
ino--;
+ if ( le32_to_cpu(sblock->inodes_per_group) == 0 || fs->inodesz == 0) {
+ free(blkgrp);
+ return 0;
+ }
status = ext4fs_blockgroup(data, ino / le32_to_cpu
(sblock->inodes_per_group), blkgrp);
if (status == 0) {
@@ -1610,6 +1618,10 @@
}
inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
+ if ( inodes_per_block == 0 ) {
+ free(blkgrp);
+ return 0;
+ }
blkno = ext4fs_bg_get_inode_table_id(blkgrp, fs) +
(ino % le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
blkoff = (ino % inodes_per_block) * fs->inodesz;
diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c
index 6adbab9..3559daf 100644
--- a/fs/ext4/ext4_journal.c
+++ b/fs/ext4/ext4_journal.c
@@ -645,6 +645,10 @@
struct ext_filesystem *fs = get_fs();
long int blknr;
int i;
+
+ if (!(fs->sb->feature_compatibility & EXT4_FEATURE_COMPAT_HAS_JOURNAL))
+ return;
+
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
update_descriptor_block(blknr);
diff --git a/fs/ext4/ext4_journal.h b/fs/ext4/ext4_journal.h
index c9cf195..43fb8e7 100644
--- a/fs/ext4/ext4_journal.h
+++ b/fs/ext4/ext4_journal.h
@@ -17,6 +17,8 @@
#ifndef __EXT4_JRNL__
#define __EXT4_JRNL__
+#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+
#define EXT2_JOURNAL_INO 8 /* Journal inode */
#define EXT2_JOURNAL_SUPERBLOCK 0 /* Journal Superblock number */
diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
index 504d23a..3368bd8 100644
--- a/fs/ext4/ext4_write.c
+++ b/fs/ext4/ext4_write.c
@@ -957,7 +957,7 @@
ext4fs_allocate_blocks(file_inode, blocks_remaining,
&blks_reqd_for_file);
file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >>
- fs->dev_desc->log2blksz);
+ LOG2_SECTOR_SIZE);
temp_ptr = zalloc(fs->blksz);
if (!temp_ptr)
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
index 26db677..37b31d9 100644
--- a/fs/ext4/ext4fs.c
+++ b/fs/ext4/ext4fs.c
@@ -61,18 +61,21 @@
lbaint_t delayed_skipfirst = 0;
lbaint_t delayed_next = 0;
char *delayed_buf = NULL;
+ char *start_buf = buf;
short status;
struct ext_block_cache cache;
ext_cache_init(&cache);
- if (blocksize <= 0)
- return -1;
-
/* Adjust len so it we can't read past the end of the file. */
if (len + pos > filesize)
len = (filesize - pos);
+ if (blocksize <= 0 || len <= 0) {
+ ext_cache_fini(&cache);
+ return -1;
+ }
+
blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize);
for (i = lldiv(pos, blocksize); i < blockcnt; i++) {
@@ -137,6 +140,7 @@
}
} else {
int n;
+ int n_left;
if (previous_block_number != -1) {
/* spill */
status = ext4fs_devread(delayed_start,
@@ -151,8 +155,9 @@
}
/* Zero no more than `len' bytes. */
n = blocksize - skipfirst;
- if (n > len)
- n = len;
+ n_left = len - ( buf - start_buf );
+ if (n > n_left)
+ n = n_left;
memset(buf, 0, n);
}
buf += blocksize - skipfirst;
@@ -286,7 +291,7 @@
if (!cache->buf)
return 0;
if (!ext4fs_devread(block, 0, size, cache->buf)) {
- free(cache->buf);
+ ext_cache_fini(cache);
return 0;
}
cache->block = block;
diff --git a/include/android_ab.h b/include/android_ab.h
new file mode 100644
index 0000000..810906d
--- /dev/null
+++ b/include/android_ab.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ */
+
+#ifndef __ANDROID_AB_H
+#define __ANDROID_AB_H
+
+#include <common.h>
+
+/* Android standard boot slot names are 'a', 'b', 'c', ... */
+#define BOOT_SLOT_NAME(slot_num) ('a' + (slot_num))
+
+/* Number of slots */
+#define NUM_SLOTS 2
+
+/**
+ * Select the slot where to boot from.
+ *
+ * On Android devices with more than one boot slot (multiple copies of the
+ * kernel and system images) selects which slot should be used to boot from and
+ * registers the boot attempt. This is used in by the new A/B update model where
+ * one slot is updated in the background while running from the other slot. If
+ * the selected slot did not successfully boot in the past, a boot attempt is
+ * registered before returning from this function so it isn't selected
+ * indefinitely.
+ *
+ * @param[in] dev_desc Place to store the device description pointer
+ * @param[in] part_info Place to store the partition information
+ * @return The slot number (>= 0) on success, or a negative on error
+ */
+int ab_select_slot(struct blk_desc *dev_desc, disk_partition_t *part_info);
+
+#endif /* __ANDROID_AB_H */
diff --git a/include/asm-generic/pe.h b/include/asm-generic/pe.h
index faae534..b247519 100644
--- a/include/asm-generic/pe.h
+++ b/include/asm-generic/pe.h
@@ -29,6 +29,22 @@
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
+/* Machine types */
+#define IMAGE_FILE_MACHINE_I386 0x014c
+#define IMAGE_FILE_MACHINE_ARM 0x01c0
+#define IMAGE_FILE_MACHINE_THUMB 0x01c2
+#define IMAGE_FILE_MACHINE_ARMNT 0x01c4
+#define IMAGE_FILE_MACHINE_AMD64 0x8664
+#define IMAGE_FILE_MACHINE_ARM64 0xaa64
+#define IMAGE_FILE_MACHINE_RISCV32 0x5032
+#define IMAGE_FILE_MACHINE_RISCV64 0x5064
+
+/* Header magic constants */
+#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b
+#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b
+#define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */
+#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
+
/* Subsystem type */
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
diff --git a/include/cbfs.h b/include/cbfs.h
index bd1bf75..b8d1dab 100644
--- a/include/cbfs.h
+++ b/include/cbfs.h
@@ -40,6 +40,17 @@
CBFS_TYPE_CMOS_LAYOUT = 0x01aa
};
+enum {
+ CBFS_HEADER_MAGIC = 0x4f524243,
+};
+
+/**
+ * struct cbfs_header - header at the start of a CBFS region
+ *
+ * All fields use big-endian format.
+ *
+ * @magic: Magic number (CBFS_HEADER_MAGIC)
+ */
struct cbfs_header {
u32 magic;
u32 version;
@@ -54,7 +65,8 @@
u8 magic[8];
u32 len;
u32 type;
- u32 checksum;
+ /* offset to struct cbfs_file_attribute or 0 */
+ u32 attributes_offset;
u32 offset;
} __packed;
@@ -65,7 +77,7 @@
u32 data_length;
char *name;
u32 name_length;
- u32 checksum;
+ u32 attributes_offset;
} __packed;
extern enum cbfs_result file_cbfs_result;
diff --git a/include/charset.h b/include/charset.h
index 4f7ae8f..020f8a9 100644
--- a/include/charset.h
+++ b/include/charset.h
@@ -178,7 +178,7 @@
* ReturnValue: number of non-zero words.
* This is not the number of utf-16 letters!
*/
-size_t u16_strlen(const u16 *in);
+size_t u16_strlen(const void *in);
/**
* u16_strlen - count non-zero words
@@ -214,7 +214,7 @@
* @src: source buffer (null terminated)
* Return: allocated new buffer on success, NULL on failure
*/
-u16 *u16_strdup(const u16 *src);
+u16 *u16_strdup(const void *src);
/**
* utf16_to_utf8() - Convert an utf16 string to utf8
diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index 26e61ef..3570a32 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -254,11 +254,11 @@
#endif
#if defined(CONFIG_DM_PCI)
-#define BOOTENV_RUN_NET_PCI_ENUM "run boot_net_pci_enum; "
+#define BOOTENV_RUN_PCI_ENUM "run boot_pci_enum; "
#define BOOTENV_SHARED_PCI \
- "boot_net_pci_enum=pci enum\0"
+ "boot_pci_enum=pci enum\0"
#else
-#define BOOTENV_RUN_NET_PCI_ENUM
+#define BOOTENV_RUN_PCI_ENUM
#define BOOTENV_SHARED_PCI
#endif
@@ -281,10 +281,24 @@
#endif
#ifdef CONFIG_CMD_VIRTIO
-#define BOOTENV_SHARED_VIRTIO BOOTENV_SHARED_BLKDEV(virtio)
+#define BOOTENV_RUN_VIRTIO_INIT "run virtio_init; "
+#define BOOTENV_SET_VIRTIO_NEED_INIT "virtio_need_init=; "
+#define BOOTENV_SHARED_VIRTIO \
+ "virtio_init=" \
+ "if ${virtio_need_init}; then " \
+ "virtio_need_init=false; " \
+ "virtio scan; " \
+ "fi\0" \
+ \
+ "virtio_boot=" \
+ BOOTENV_RUN_PCI_ENUM \
+ BOOTENV_RUN_VIRTIO_INIT \
+ BOOTENV_SHARED_BLKDEV_BODY(virtio)
#define BOOTENV_DEV_VIRTIO BOOTENV_DEV_BLKDEV
#define BOOTENV_DEV_NAME_VIRTIO BOOTENV_DEV_NAME_BLKDEV
#else
+#define BOOTENV_RUN_VIRTIO_INIT
+#define BOOTENV_SET_VIRTIO_NEED_INIT
#define BOOTENV_SHARED_VIRTIO
#define BOOTENV_DEV_VIRTIO \
BOOT_TARGET_DEVICES_references_VIRTIO_without_CONFIG_CMD_VIRTIO
@@ -350,7 +364,7 @@
#define BOOTENV_DEV_DHCP(devtypeu, devtypel, instance) \
"bootcmd_dhcp=" \
BOOTENV_RUN_NET_USB_START \
- BOOTENV_RUN_NET_PCI_ENUM \
+ BOOTENV_RUN_PCI_ENUM \
"if dhcp ${scriptaddr} ${boot_script_dhcp}; then " \
"source ${scriptaddr}; " \
"fi;" \
@@ -369,7 +383,7 @@
#define BOOTENV_DEV_PXE(devtypeu, devtypel, instance) \
"bootcmd_pxe=" \
BOOTENV_RUN_NET_USB_START \
- BOOTENV_RUN_NET_PCI_ENUM \
+ BOOTENV_RUN_PCI_ENUM \
"dhcp; " \
"if pxe get; then " \
"pxe boot; " \
@@ -465,6 +479,7 @@
"distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT \
BOOTENV_SET_NVME_NEED_INIT \
BOOTENV_SET_IDE_NEED_INIT \
+ BOOTENV_SET_VIRTIO_NEED_INIT \
"for target in ${boot_targets}; do " \
"run bootcmd_${target}; " \
"done\0"
diff --git a/include/configs/am65x_evm.h b/include/configs/am65x_evm.h
index b043bf8..1415bb1 100644
--- a/include/configs/am65x_evm.h
+++ b/include/configs/am65x_evm.h
@@ -19,6 +19,32 @@
#define CONFIG_SYS_SDRAM_BASE1 0x880000000
/* SPL Loader Configuration */
+#ifdef CONFIG_TARGET_AM654_A53_EVM
+#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SPL_TEXT_BASE + \
+ CONFIG_SYS_K3_NON_SECURE_MSRAM_SIZE)
+#else
+/*
+ * Maximum size in memory allocated to the SPL BSS. Keep it as tight as
+ * possible (to allow the build to go through), as this directly affects
+ * our memory footprint. The less we use for BSS the more we have available
+ * for everything else.
+ */
+#define CONFIG_SPL_BSS_MAX_SIZE 0x5000
+/*
+ * Link BSS to be within SPL in a dedicated region located near the top of
+ * the MCU SRAM, this way making it available also before relocation. Note
+ * that we are not using the actual top of the MCU SRAM as there is a memory
+ * location filled in by the boot ROM that we want to read out without any
+ * interference from the C context.
+ */
+#define CONFIG_SPL_BSS_START_ADDR (CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX -\
+ CONFIG_SPL_BSS_MAX_SIZE)
+/* Set the stack right below the SPL BSS section */
+#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SPL_BSS_START_ADDR
+/* Configure R5 SPL post-relocation malloc pool in DDR */
+#define CONFIG_SYS_SPL_MALLOC_START 0x84000000
+#define CONFIG_SYS_SPL_MALLOC_SIZE SZ_16M
+#endif
#ifdef CONFIG_SYS_K3_SPL_ATF
#define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "tispl.bin"
@@ -29,26 +55,26 @@
#endif
#define CONFIG_SPL_MAX_SIZE CONFIG_SYS_K3_MAX_DOWNLODABLE_IMAGE_SIZE
-#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SPL_TEXT_BASE + \
- CONFIG_SYS_K3_NON_SECURE_MSRAM_SIZE - 4)
#define CONFIG_SYS_BOOTM_LEN SZ_64M
+#define PARTS_DEFAULT \
+ /* Linux partitions */ \
+ "name=rootfs,start=0,size=-,uuid=${uuid_gpt_rootfs}\0"
+
/* U-Boot general configuration */
#define EXTRA_ENV_AM65X_BOARD_SETTINGS \
"findfdt=" \
- "if test $board_name = am65x; then " \
- "setenv name_fdt k3-am654-base-board.dtb; " \
- "else if test $name_fdt = undefined; then " \
- "echo WARNING: Could not determine device tree to use;"\
- "fi; fi; " \
- "setenv fdtfile ${name_fdt}\0" \
+ "setenv name_fdt k3-am654-base-board.dtb;" \
+ "setenv fdtfile ${name_fdt};" \
+ "setenv overlay_files ${name_overlays}\0" \
"loadaddr=0x80080000\0" \
"fdtaddr=0x82000000\0" \
+ "overlayaddr=0x83000000\0" \
"name_kern=Image\0" \
"console=ttyS2,115200n8\0" \
"args_all=setenv optargs earlycon=ns16550a,mmio32,0x02800000\0" \
- "run_kern=booti ${loadaddr} ${rd_spec} ${fdtaddr}\0"
+ "run_kern=booti ${loadaddr} ${rd_spec} ${fdtaddr}\0" \
/* U-Boot MMC-specific configuration */
#define EXTRA_ENV_AM65X_BOARD_SETTINGS_MMC \
@@ -59,8 +85,17 @@
"rd_spec=-\0" \
"init_mmc=run args_all args_mmc\0" \
"get_fdt_mmc=load mmc ${bootpart} ${fdtaddr} ${bootdir}/${name_fdt}\0" \
+ "get_overlay_mmc=" \
+ "fdt address ${fdtaddr};" \
+ "fdt resize 0x100000;" \
+ "for overlay in $overlay_files;" \
+ "do;" \
+ "load mmc ${bootpart} ${overlayaddr} ${bootdir}/${overlay};" \
+ "fdt apply ${overlayaddr};" \
+ "done;\0" \
"get_kern_mmc=load mmc ${bootpart} ${loadaddr} " \
- "${bootdir}/${name_kern}\0"
+ "${bootdir}/${name_kern}\0" \
+ "partitions=" PARTS_DEFAULT
/* Incorporate settings into the U-Boot environment */
#define CONFIG_EXTRA_ENV_SETTINGS \
@@ -68,6 +103,18 @@
EXTRA_ENV_AM65X_BOARD_SETTINGS \
EXTRA_ENV_AM65X_BOARD_SETTINGS_MMC
+/* MMC ENV related defines */
+#ifdef CONFIG_ENV_IS_IN_MMC
+#define CONFIG_SYS_MMC_ENV_DEV 0
+#define CONFIG_SYS_MMC_ENV_PART 1
+#define CONFIG_ENV_SIZE (128 << 10)
+#define CONFIG_ENV_OFFSET 0x680000
+#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)
+#define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+#endif
+
+#define CONFIG_SUPPORT_EMMC_BOOT
+
/* Now for the remaining common defines */
#include <configs/ti_armv7_common.h>
diff --git a/include/configs/ls1021atsn.h b/include/configs/ls1021atsn.h
new file mode 100644
index 0000000..b011cb2
--- /dev/null
+++ b/include/configs/ls1021atsn.h
@@ -0,0 +1,250 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright 2016-2018 NXP Semiconductors
+ * Copyright 2019 Vladimir Oltean <olteanv@gmail.com>
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_ARMV7_SECURE_BASE OCRAM_BASE_S_ADDR
+
+#define CONFIG_SYS_FSL_CLK
+
+#define CONFIG_DEEP_SLEEP
+
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 16 * 1024 * 1024)
+
+#define CONFIG_SYS_INIT_RAM_ADDR OCRAM_BASE_ADDR
+#define CONFIG_SYS_INIT_RAM_SIZE OCRAM_SIZE
+
+/* XHCI Support - enabled by default */
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+
+#define CONFIG_SYS_CLK_FREQ 100000000
+#define CONFIG_DDR_CLK_FREQ 100000000
+
+#define DDR_SDRAM_CFG 0x470c0008
+#define DDR_CS0_BNDS 0x008000bf
+#define DDR_CS0_CONFIG 0x80014302
+#define DDR_TIMING_CFG_0 0x50550004
+#define DDR_TIMING_CFG_1 0xbcb38c56
+#define DDR_TIMING_CFG_2 0x0040d120
+#define DDR_TIMING_CFG_3 0x010e1000
+#define DDR_TIMING_CFG_4 0x00000001
+#define DDR_TIMING_CFG_5 0x03401400
+#define DDR_SDRAM_CFG_2 0x00401010
+#define DDR_SDRAM_MODE 0x00061c60
+#define DDR_SDRAM_MODE_2 0x00180000
+#define DDR_SDRAM_INTERVAL 0x18600618
+#define DDR_DDR_WRLVL_CNTL 0x8655f605
+#define DDR_DDR_WRLVL_CNTL_2 0x05060607
+#define DDR_DDR_WRLVL_CNTL_3 0x05050505
+#define DDR_DDR_CDR1 0x80040000
+#define DDR_DDR_CDR2 0x00000001
+#define DDR_SDRAM_CLK_CNTL 0x02000000
+#define DDR_DDR_ZQ_CNTL 0x89080600
+#define DDR_CS0_CONFIG_2 0
+#define DDR_SDRAM_CFG_MEM_EN 0x80000000
+#define SDRAM_CFG2_D_INIT 0x00000010
+#define DDR_CDR2_VREF_TRAIN_EN 0x00000080
+#define SDRAM_CFG2_FRC_SR 0x80000000
+#define SDRAM_CFG_BI 0x00000001
+
+#ifdef CONFIG_RAMBOOT_PBL
+#define CONFIG_SYS_FSL_PBL_PBI \
+ "board/freescale/ls1021atsn/ls102xa_pbi.cfg"
+#endif
+
+#ifdef CONFIG_SD_BOOT
+#define CONFIG_SYS_FSL_PBL_RCW \
+ "board/freescale/ls1021atsn/ls102xa_rcw_sd.cfg"
+
+#ifdef CONFIG_SECURE_BOOT
+#define CONFIG_U_BOOT_HDR_SIZE (16 << 10)
+#endif /* ifdef CONFIG_SECURE_BOOT */
+
+#define CONFIG_SPL_MAX_SIZE 0x1a000
+#define CONFIG_SPL_STACK 0x1001d000
+#define CONFIG_SPL_PAD_TO 0x1c000
+
+#define CONFIG_SYS_SPL_MALLOC_START (CONFIG_SYS_TEXT_BASE + \
+ CONFIG_SYS_MONITOR_LEN)
+#define CONFIG_SYS_SPL_MALLOC_SIZE 0x100000
+#define CONFIG_SPL_BSS_START_ADDR 0x80100000
+#define CONFIG_SPL_BSS_MAX_SIZE 0x80000
+
+#ifdef CONFIG_U_BOOT_HDR_SIZE
+/*
+ * HDR would be appended at end of image and copied to DDR along
+ * with U-Boot image. Here u-boot max. size is 512K. So if binary
+ * size increases then increase this size in case of secure boot as
+ * it uses raw U-Boot image instead of FIT image.
+ */
+#define CONFIG_SYS_MONITOR_LEN (0x100000 + CONFIG_U_BOOT_HDR_SIZE)
+#else
+#define CONFIG_SYS_MONITOR_LEN 0x100000
+#endif /* ifdef CONFIG_U_BOOT_HDR_SIZE */
+#endif
+
+#define CONFIG_NR_DRAM_BANKS 1
+#define PHYS_SDRAM 0x80000000
+#define PHYS_SDRAM_SIZE (1u * 1024 * 1024 * 1024)
+
+#define CONFIG_SYS_DDR_SDRAM_BASE 0x80000000UL
+#define CONFIG_SYS_SDRAM_BASE CONFIG_SYS_DDR_SDRAM_BASE
+
+#define CONFIG_CHIP_SELECTS_PER_CTRL 4
+
+/* Serial Port */
+#define CONFIG_CONS_INDEX 1
+#define CONFIG_SYS_NS16550_SERIAL
+#ifndef CONFIG_DM_SERIAL
+#define CONFIG_SYS_NS16550_REG_SIZE 1
+#endif
+#define CONFIG_SYS_NS16550_CLK get_serial_clock()
+
+#define CONFIG_BAUDRATE 115200
+
+/* I2C */
+#define CONFIG_SYS_I2C
+#define CONFIG_SYS_I2C_MXC
+#define CONFIG_SYS_I2C_MXC_I2C1 /* enable I2C bus 1 */
+#define CONFIG_SYS_I2C_MXC_I2C2 /* enable I2C bus 2 */
+#define CONFIG_SYS_I2C_MXC_I2C3 /* enable I2C bus 3 */
+
+/* EEPROM */
+#define CONFIG_ID_EEPROM
+#define CONFIG_SYS_I2C_EEPROM_NXID
+#define CONFIG_SYS_EEPROM_BUS_NUM 0
+#define CONFIG_SYS_I2C_EEPROM_ADDR 0x51
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2
+
+/* QSPI */
+#define FSL_QSPI_FLASH_SIZE (1 << 24)
+#define FSL_QSPI_FLASH_NUM 2
+
+/* PCIe */
+#define CONFIG_PCIE1 /* PCIE controller 1 */
+#define CONFIG_PCIE2 /* PCIE controller 2 */
+#define FSL_PCIE_COMPAT "fsl,ls1021a-pcie"
+#ifdef CONFIG_PCI
+#define CONFIG_PCI_SCAN_SHOW
+#endif
+
+#define CONFIG_LAYERSCAPE_NS_ACCESS
+#define COUNTER_FREQUENCY 12500000
+
+#define CONFIG_HWCONFIG
+#define HWCONFIG_BUFFER_SIZE 256
+
+#define CONFIG_FSL_DEVICE_DISABLE
+
+#define BOOT_TARGET_DEVICES(func) \
+ func(MMC, mmc, 0) \
+ func(USB, usb, 0) \
+ func(DHCP, dhcp, na)
+#include <config_distro_bootcmd.h>
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "bootargs=root=/dev/ram0 rw console=ttyS0,115200\0" \
+ "initrd_high=0xffffffff\0" \
+ "fdt_high=0xffffffff\0" \
+ "fdt_addr=0x64f00000\0" \
+ "kernel_addr=0x61000000\0" \
+ "kernelheader_addr=0x60800000\0" \
+ "scriptaddr=0x80000000\0" \
+ "scripthdraddr=0x80080000\0" \
+ "fdtheader_addr_r=0x80100000\0" \
+ "kernelheader_addr_r=0x80200000\0" \
+ "kernel_addr_r=0x80008000\0" \
+ "kernelheader_size=0x40000\0" \
+ "fdt_addr_r=0x8f000000\0" \
+ "ramdisk_addr_r=0xa0000000\0" \
+ "load_addr=0x80008000\0" \
+ "kernel_size=0x2800000\0" \
+ "kernel_addr_sd=0x8000\0" \
+ "kernel_size_sd=0x14000\0" \
+ "kernelhdr_addr_sd=0x4000\0" \
+ "kernelhdr_size_sd=0x10\0" \
+ BOOTENV \
+ "boot_scripts=ls1021atsn_boot.scr\0" \
+ "boot_script_hdr=hdr_ls1021atsn_bs.out\0" \
+ "scan_dev_for_boot_part=" \
+ "part list ${devtype} ${devnum} devplist; " \
+ "env exists devplist || setenv devplist 1; " \
+ "for distro_bootpart in ${devplist}; do " \
+ "if fstype ${devtype} " \
+ "${devnum}:${distro_bootpart} " \
+ "bootfstype; then " \
+ "run scan_dev_for_boot; " \
+ "fi; " \
+ "done\0" \
+ "scan_dev_for_boot=" \
+ "echo Scanning ${devtype} " \
+ "${devnum}:${distro_bootpart}...; " \
+ "for prefix in ${boot_prefixes}; do " \
+ "run scan_dev_for_scripts; " \
+ "run scan_dev_for_extlinux; " \
+ "done;" \
+ "\0" \
+ "boot_a_script=" \
+ "load ${devtype} ${devnum}:${distro_bootpart} " \
+ "${scriptaddr} ${prefix}${script}; " \
+ "env exists secureboot && load ${devtype} " \
+ "${devnum}:${distro_bootpart} " \
+ "${scripthdraddr} ${prefix}${boot_script_hdr} " \
+ "&& esbc_validate ${scripthdraddr};" \
+ "source ${scriptaddr}\0" \
+ "qspi_bootcmd=echo Trying load from qspi..;" \
+ "sf probe && sf read $load_addr " \
+ "$kernel_addr $kernel_size; env exists secureboot " \
+ "&& sf read $kernelheader_addr_r $kernelheader_addr " \
+ "$kernelheader_size && esbc_validate ${kernelheader_addr_r}; " \
+ "bootm $load_addr#$board\0" \
+ "sd_bootcmd=echo Trying load from SD ..;" \
+ "mmcinfo && mmc read $load_addr " \
+ "$kernel_addr_sd $kernel_size_sd && " \
+ "env exists secureboot && mmc read $kernelheader_addr_r " \
+ "$kernelhdr_addr_sd $kernelhdr_size_sd " \
+ " && esbc_validate ${kernelheader_addr_r};" \
+ "bootm $load_addr#$board\0"
+
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+ (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_MAXARGS 16 /* max number of command args */
+#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
+
+#define CONFIG_SYS_LOAD_ADDR 0x82000000
+
+#define CONFIG_LS102XA_STREAM_ID
+
+#define CONFIG_SYS_INIT_SP_OFFSET \
+ (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
+#define CONFIG_SYS_INIT_SP_ADDR \
+ (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
+
+#ifdef CONFIG_SPL_BUILD
+#define CONFIG_SYS_MONITOR_BASE CONFIG_SPL_TEXT_BASE
+#else
+#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE /* start of monitor */
+#endif
+
+/* Environment */
+#define CONFIG_ENV_OVERWRITE
+
+#if defined(CONFIG_SD_BOOT)
+#define CONFIG_ENV_OFFSET 0x300000
+#define CONFIG_SYS_MMC_ENV_DEV 0
+#define CONFIG_ENV_SIZE 0x20000
+#elif defined(CONFIG_QSPI_BOOT)
+#define CONFIG_ENV_SIZE 0x2000
+#define CONFIG_ENV_OFFSET 0x300000
+#define CONFIG_ENV_SECT_SIZE 0x40000
+#endif
+
+#define CONFIG_SYS_BOOTM_LEN 0x8000000 /* 128 MB */
+
+#endif
diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h
index de0c9c7..31abee8 100644
--- a/include/configs/ls1021atwr.h
+++ b/include/configs/ls1021atwr.h
@@ -260,33 +260,7 @@
*/
#ifdef CONFIG_TSEC_ENET
-#define CONFIG_MII_DEFAULT_TSEC 1
-#define CONFIG_TSEC1 1
-#define CONFIG_TSEC1_NAME "eTSEC1"
-#define CONFIG_TSEC2 1
-#define CONFIG_TSEC2_NAME "eTSEC2"
-#define CONFIG_TSEC3 1
-#define CONFIG_TSEC3_NAME "eTSEC3"
-
-#define TSEC1_PHY_ADDR 2
-#define TSEC2_PHY_ADDR 0
-#define TSEC3_PHY_ADDR 1
-
-#define TSEC1_FLAGS (TSEC_GIGABIT | TSEC_REDUCED)
-#define TSEC2_FLAGS (TSEC_GIGABIT | TSEC_REDUCED)
-#define TSEC3_FLAGS (TSEC_GIGABIT | TSEC_REDUCED)
-
-#define TSEC1_PHYIDX 0
-#define TSEC2_PHYIDX 0
-#define TSEC3_PHYIDX 0
-
-#define CONFIG_ETHPRIME "eTSEC1"
-
-#define CONFIG_PHY_ATHEROS
-
-#define CONFIG_HAS_ETH0
-#define CONFIG_HAS_ETH1
-#define CONFIG_HAS_ETH2
+#define CONFIG_ETHPRIME "ethernet@2d10000"
#endif
/* PCIe */
@@ -444,7 +418,7 @@
#undef CONFIG_BOOTCOMMAND
#if defined(CONFIG_QSPI_BOOT) || defined(CONFIG_SD_BOOT_QSPI)
-#define CONFIG_BOOTCOMMAND "run distro_bootcmd; run qspi_bootcmd" \
+#define CONFIG_BOOTCOMMAND "run distro_bootcmd; run qspi_bootcmd; " \
"env exists secureboot && esbc_halt"
#elif defined(CONFIG_SD_BOOT)
#define CONFIG_BOOTCOMMAND "run distro_bootcmd; run sd_bootcmd; " \
diff --git a/include/configs/ls1028a_common.h b/include/configs/ls1028a_common.h
index 896d7a3..a6c7c37 100644
--- a/include/configs/ls1028a_common.h
+++ b/include/configs/ls1028a_common.h
@@ -194,4 +194,8 @@
#include <asm/fsl_secure_boot.h>
#endif
+/* Ethernet */
+/* smallest ENETC BD ring has 8 entries */
+#define CONFIG_SYS_RX_ETH_BUFFER 8
+
#endif /* __L1028A_COMMON_H */
diff --git a/include/configs/qemu-arm.h b/include/configs/qemu-arm.h
index 65fdb1e..35e3c5a 100644
--- a/include/configs/qemu-arm.h
+++ b/include/configs/qemu-arm.h
@@ -46,8 +46,13 @@
#define CONFIG_SYS_CBSIZE 512
#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
+#ifdef CONFIG_TFABOOT
+#define CONFIG_SYS_FLASH_BASE 0x4000000
+#define CONFIG_SYS_MAX_FLASH_BANKS 1
+#else
#define CONFIG_SYS_FLASH_BASE 0x0
#define CONFIG_SYS_MAX_FLASH_BANKS 2
+#endif
#define CONFIG_SYS_MAX_FLASH_SECT 256 /* Sector: 256K, Bank: 64M */
#endif /* __CONFIG_H */
diff --git a/include/configs/rk3036_common.h b/include/configs/rk3036_common.h
index f5d09d1..73be079 100644
--- a/include/configs/rk3036_common.h
+++ b/include/configs/rk3036_common.h
@@ -12,9 +12,10 @@
#define CONFIG_SYS_CBSIZE 1024
#define CONFIG_SKIP_LOWLEVEL_INIT
-#define CONFIG_SYS_TIMER_RATE (24 * 1000 * 1000)
-#define CONFIG_SYS_TIMER_BASE 0x200440a0 /* TIMER5 */
-#define CONFIG_SYS_TIMER_COUNTER (CONFIG_SYS_TIMER_BASE + 8)
+#define CONFIG_ROCKCHIP_STIMER_BASE 0x200440a0
+#define COUNTER_FREQUENCY 24000000
+#define CONFIG_SYS_ARCH_TIMER
+#define CONFIG_SYS_HZ_CLOCK 24000000
#define CONFIG_SYS_INIT_SP_ADDR 0x60100000
#define CONFIG_SYS_LOAD_ADDR 0x60800800
diff --git a/include/configs/rk3128_common.h b/include/configs/rk3128_common.h
index 0c08d7a..20d6243 100644
--- a/include/configs/rk3128_common.h
+++ b/include/configs/rk3128_common.h
@@ -14,9 +14,10 @@
#define CONFIG_SYS_CBSIZE 1024
#define CONFIG_SKIP_LOWLEVEL_INIT
-#define CONFIG_SYS_TIMER_RATE (24 * 1000 * 1000)
-#define CONFIG_SYS_TIMER_BASE 0x200440a0 /* TIMER5 */
-#define CONFIG_SYS_TIMER_COUNTER (CONFIG_SYS_TIMER_BASE + 8)
+#define CONFIG_ROCKCHIP_STIMER_BASE 0x200440a0
+#define COUNTER_FREQUENCY 24000000
+#define CONFIG_SYS_ARCH_TIMER
+#define CONFIG_SYS_HZ_CLOCK 24000000
#define CONFIG_SYS_INIT_SP_ADDR 0x60100000
#define CONFIG_SYS_LOAD_ADDR 0x60800800
diff --git a/include/configs/rk322x_common.h b/include/configs/rk322x_common.h
index 15bb8d6..cc08699 100644
--- a/include/configs/rk322x_common.h
+++ b/include/configs/rk322x_common.h
@@ -13,9 +13,10 @@
#define CONFIG_SYS_CBSIZE 1024
#define CONFIG_SYS_BOOTM_LEN (64 << 20) /* 64M */
-#define CONFIG_SYS_TIMER_RATE (24 * 1000 * 1000)
-#define CONFIG_SYS_TIMER_BASE 0x110c00a0 /* TIMER5 */
-#define CONFIG_SYS_TIMER_COUNTER (CONFIG_SYS_TIMER_BASE + 8)
+#define CONFIG_ROCKCHIP_STIMER_BASE 0x110d0020
+#define COUNTER_FREQUENCY 24000000
+#define CONFIG_SYS_ARCH_TIMER
+#define CONFIG_SYS_HZ_CLOCK 24000000
#define CONFIG_SYS_INIT_SP_ADDR 0x61100000
#define CONFIG_SYS_LOAD_ADDR 0x61800800
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h
index 7c79ed6..5472a90 100644
--- a/include/configs/rk3288_common.h
+++ b/include/configs/rk3288_common.h
@@ -13,9 +13,10 @@
#define CONFIG_SYS_MALLOC_LEN (32 << 20)
#define CONFIG_SYS_CBSIZE 1024
-#define CONFIG_SYS_TIMER_RATE (24 * 1000 * 1000)
-#define CONFIG_SYS_TIMER_BASE 0xff810020 /* TIMER7 */
-#define CONFIG_SYS_TIMER_COUNTER (CONFIG_SYS_TIMER_BASE + 8)
+#define CONFIG_ROCKCHIP_STIMER_BASE 0xff810020
+#define COUNTER_FREQUENCY 24000000
+#define CONFIG_SYS_ARCH_TIMER
+#define CONFIG_SYS_HZ_CLOCK 24000000
#ifdef CONFIG_SPL_ROCKCHIP_BACK_TO_BROM
/* Bootrom will load u-boot binary to 0x0 once return from SPL */
@@ -35,6 +36,8 @@
#define SDRAM_BANK_SIZE (2UL << 30)
#define SDRAM_MAX_SIZE 0xfe000000
+#define CONFIG_SYS_MONITOR_LEN (600 * 1024)
+
#ifndef CONFIG_SPL_BUILD
/* usb otg */
diff --git a/include/configs/rk3368_common.h b/include/configs/rk3368_common.h
index 13630ba..8a1e311 100644
--- a/include/configs/rk3368_common.h
+++ b/include/configs/rk3368_common.h
@@ -20,7 +20,8 @@
#define CONFIG_SYS_CBSIZE 1024
#define CONFIG_SKIP_LOWLEVEL_INIT
-#define COUNTER_FREQUENCY 24000000
+#define CONFIG_ROCKCHIP_STIMER_BASE 0xff830020
+#define COUNTER_FREQUENCY 24000000
#define CONFIG_SYS_NS16550_MEM32
diff --git a/include/configs/rk3399_common.h b/include/configs/rk3399_common.h
index f31f265..8df0180 100644
--- a/include/configs/rk3399_common.h
+++ b/include/configs/rk3399_common.h
@@ -13,6 +13,7 @@
#define CONFIG_SKIP_LOWLEVEL_INIT
#define COUNTER_FREQUENCY 24000000
+#define CONFIG_ROCKCHIP_STIMER_BASE 0xff8680a0
#define CONFIG_SYS_NS16550_MEM32
diff --git a/include/configs/sifive-fu540.h b/include/configs/sifive-fu540.h
index 7007b5f..858b7a7 100644
--- a/include/configs/sifive-fu540.h
+++ b/include/configs/sifive-fu540.h
@@ -18,12 +18,12 @@
#define CONFIG_SYS_MALLOC_LEN SZ_8M
-#define CONFIG_SYS_BOOTM_LEN SZ_16M
+#define CONFIG_SYS_BOOTM_LEN SZ_64M
#define CONFIG_STANDALONE_LOAD_ADDR 0x80200000
/* Environment options */
-#define CONFIG_ENV_SIZE SZ_4K
+#define CONFIG_ENV_SIZE SZ_128K
#define BOOT_TARGET_DEVICES(func) \
func(DHCP, dhcp, na)
@@ -33,11 +33,15 @@
#define CONFIG_EXTRA_ENV_SETTINGS \
"fdt_high=0xffffffffffffffff\0" \
"initrd_high=0xffffffffffffffff\0" \
- "kernel_addr_r=0x80600000\0" \
- "fdt_addr_r=0x82200000\0" \
- "scriptaddr=0x82300000\0" \
- "pxefile_addr_r=0x82400000\0" \
- "ramdisk_addr_r=0x82500000\0" \
+ "kernel_addr_r=0x84000000\0" \
+ "fdt_addr_r=0x88000000\0" \
+ "scriptaddr=0x88100000\0" \
+ "pxefile_addr_r=0x88200000\0" \
+ "ramdisk_addr_r=0x88300000\0" \
BOOTENV
+#define CONFIG_PREBOOT \
+ "setenv fdt_addr ${fdtcontroladdr};" \
+ "fdt addr ${fdtcontroladdr};"
+
#endif /* __CONFIG_H */
diff --git a/include/configs/tinker_rk3288.h b/include/configs/tinker_rk3288.h
index 32057b3..5adae68 100644
--- a/include/configs/tinker_rk3288.h
+++ b/include/configs/tinker_rk3288.h
@@ -18,6 +18,5 @@
func(DHCP, dchp, na)
#define CONFIG_SYS_MMC_ENV_DEV 1
-#define CONFIG_SYS_MONITOR_LEN (600 * 1024)
#endif
diff --git a/include/debug_uart.h b/include/debug_uart.h
index 34e8b2f..cd70ae1 100644
--- a/include/debug_uart.h
+++ b/include/debug_uart.h
@@ -104,6 +104,13 @@
*/
void printhex8(uint value);
+/**
+ * printdec() - Output a decimalism value
+ *
+ * @value: Value to output
+ */
+void printdec(uint value);
+
#ifdef CONFIG_DEBUG_UART_ANNOUNCE
#define _DEBUG_UART_ANNOUNCE printascii("<debug_uart> ");
#else
@@ -171,6 +178,18 @@
printhex(value, 8); \
} \
\
+ void printdec(uint value) \
+ { \
+ if (value > 10) { \
+ printdec(value / 10); \
+ value %= 10; \
+ } else if (value == 10) { \
+ _debug_uart_putc('1'); \
+ value = 0; \
+ } \
+ _debug_uart_putc('0' + value); \
+ } \
+\
void debug_uart_init(void) \
{ \
board_debug_uart_init(); \
diff --git a/include/dm/of_addr.h b/include/dm/of_addr.h
index 12b1a99..3fa1ffc 100644
--- a/include/dm/of_addr.h
+++ b/include/dm/of_addr.h
@@ -27,6 +27,24 @@
u64 of_translate_address(const struct device_node *no, const __be32 *in_addr);
/**
+ * of_translate_dma_address() - translate a device-tree DMA address to a CPU
+ * address
+ *
+ * Translate a DMA address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the way.
+ *
+ * Note: We consider that crossing any level with #size-cells == 0 to mean
+ * that translation is impossible (that is we are not dealing with a value
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ *
+ * @np: node to check
+ * @in_addr: pointer to input DMA address
+ * @return translated DMA address or OF_BAD_ADDR on error
+ */
+u64 of_translate_dma_address(const struct device_node *no, const __be32 *in_addr);
+
+/**
* of_get_address() - obtain an address from a node
*
* Extract an address from a node, returns the region size and the address
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 704f915..4f89db44 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -767,7 +767,7 @@
node = ofnode_next_subnode(node))
/**
- * ofnode_translate_address() - Tranlate a device-tree address
+ * ofnode_translate_address() - Translate a device-tree address
*
* Translate an address from the device-tree into a CPU physical address. This
* function walks up the tree and applies the various bus mappings along the
@@ -781,6 +781,20 @@
u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr);
/**
+ * ofnode_translate_dma_address() - Translate a device-tree DMA address
+ *
+ * Translate a DMA address from the device-tree into a CPU physical address.
+ * This function walks up the tree and applies the various bus mappings along
+ * the way.
+ *
+ * @ofnode: Device tree node giving the context in which to translate the
+ * DMA address
+ * @in_addr: pointer to the DMA address to translate
+ * @return the translated DMA address; OF_BAD_ADDR on error
+ */
+u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr);
+
+/**
* ofnode_device_is_compatible() - check if the node is compatible with compat
*
* This allows to check whether the node is comaptible with the compat.
diff --git a/include/dm/read.h b/include/dm/read.h
index 60b727c..6ecd062 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -227,7 +227,7 @@
/**
* dev_read_name() - get the name of a device's node
*
- * @node: valid node to look up
+ * @dev: Device to read from
* @return name of node
*/
const char *dev_read_name(struct udevice *dev);
@@ -499,7 +499,7 @@
struct resource *res);
/**
- * dev_translate_address() - Tranlate a device-tree address
+ * dev_translate_address() - Translate a device-tree address
*
* Translate an address from the device-tree into a CPU physical address. This
* function walks up the tree and applies the various bus mappings along the
@@ -512,6 +512,19 @@
u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_addr);
/**
+ * dev_translate_dma_address() - Translate a device-tree DMA address
+ *
+ * Translate a DMA address from the device-tree into a CPU physical address.
+ * This function walks up the tree and applies the various bus mappings along
+ * the way.
+ *
+ * @dev: device giving the context in which to translate the DMA address
+ * @in_addr: pointer to the DMA address to translate
+ * @return the translated DMA address; OF_BAD_ADDR on error
+ */
+u64 dev_translate_dma_address(struct udevice *dev, const fdt32_t *in_addr);
+
+/**
* dev_read_alias_highest_id - Get highest alias id for the given stem
* @stem: Alias stem to be examined
*
@@ -751,6 +764,11 @@
return ofnode_translate_address(dev_ofnode(dev), in_addr);
}
+static inline u64 dev_translate_dma_address(struct udevice *dev, const fdt32_t *in_addr)
+{
+ return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
+}
+
static inline int dev_read_alias_highest_id(const char *stem)
{
return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index f9300a6..d4d9610 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -59,6 +59,7 @@
UCLASS_MAILBOX, /* Mailbox controller */
UCLASS_MASS_STORAGE, /* Mass storage device */
UCLASS_MDIO, /* MDIO bus */
+ UCLASS_MDIO_MUX, /* MDIO MUX/switch */
UCLASS_MISC, /* Miscellaneous device */
UCLASS_MMC, /* SD / MMC card or chip */
UCLASS_MOD_EXP, /* RSA Mod Exp device */
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 1bc62d5..484d166 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -297,7 +297,7 @@
*
* The device returned is probed if necessary, and ready for use
*
- * This function is useful to start iterating through a list of devices which
+ * This function is useful to iterate through a list of devices which
* are functioning correctly and can be probed.
*
* @devp: On entry, pointer to device to lookup. On exit, returns pointer
diff --git a/include/dt-bindings/clk/sifive-fu540-prci.h b/include/dt-bindings/clk/sifive-fu540-prci.h
deleted file mode 100644
index 531523e..0000000
--- a/include/dt-bindings/clk/sifive-fu540-prci.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2019 Western Digital Corporation or its affiliates.
- *
- * Copyright (C) 2018 SiFive, Inc.
- * Wesley Terpstra
- * Paul Walmsley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __LINUX_CLK_SIFIVE_FU540_PRCI_H
-#define __LINUX_CLK_SIFIVE_FU540_PRCI_H
-
-/* Clock indexes for use by Device Tree data */
-
-#define PRCI_CLK_COREPLL 0
-#define PRCI_CLK_DDRPLL 1
-#define PRCI_CLK_GEMGXLPLL 2
-#define PRCI_CLK_TLCLK 3
-
-#endif
diff --git a/include/dt-bindings/clock/sifive-fu540-prci.h b/include/dt-bindings/clock/sifive-fu540-prci.h
new file mode 100644
index 0000000..6a0b70a
--- /dev/null
+++ b/include/dt-bindings/clock/sifive-fu540-prci.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_SIFIVE_FU540_PRCI_H
+#define __DT_BINDINGS_CLOCK_SIFIVE_FU540_PRCI_H
+
+/* Clock indexes for use by Device Tree data and the PRCI driver */
+
+#define PRCI_CLK_COREPLL 0
+#define PRCI_CLK_DDRPLL 1
+#define PRCI_CLK_GEMGXLPLL 2
+#define PRCI_CLK_TLCLK 3
+
+#endif
diff --git a/include/efi_loader.h b/include/efi_loader.h
index db4763f..5298ea7 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -476,8 +476,8 @@
efi_uintn_t *descriptor_size,
uint32_t *descriptor_version);
/* Adds a range into the EFI memory map */
-uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
- bool overlap_only_ram);
+efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
+ bool overlap_only_ram);
/* Called by board init to initialize the EFI drivers */
efi_status_t efi_driver_init(void);
/* Called by board init to initialize the EFI memory map */
@@ -567,7 +567,7 @@
*unicode = 0;
}
-static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2)
+static inline int guidcmp(const void *g1, const void *g2)
{
return memcmp(g1, g2, sizeof(efi_guid_t));
}
diff --git a/include/environment.h b/include/environment.h
index cd96676..de67cf4 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -200,6 +200,7 @@
ENVOP_INIT, /* we want to call the init function */
ENVOP_LOAD, /* we want to call the load function */
ENVOP_SAVE, /* we want to call the save function */
+ ENVOP_ERASE, /* we want to call the erase function */
};
struct env_driver {
@@ -226,6 +227,15 @@
int (*save)(void);
/**
+ * erase() - Erase the environment on storage
+ *
+ * This method is optional and required for 'eraseenv' to work.
+ *
+ * @return 0 if OK, -ve on error
+ */
+ int (*erase)(void);
+
+ /**
* init() - Set up the initial pre-relocation environment
*
* This method is optional.
@@ -304,6 +314,13 @@
int env_save(void);
/**
+ * env_erase() - Erase the environment on storage
+ *
+ * @return 0 if OK, -ve on error
+ */
+int env_erase(void);
+
+/**
* env_fix_drivers() - Updates envdriver as per relocation
*/
void env_fix_drivers(void);
diff --git a/include/environment/ti/boot.h b/include/environment/ti/boot.h
index 05bdbbc..54e9b2d 100644
--- a/include/environment/ti/boot.h
+++ b/include/environment/ti/boot.h
@@ -23,6 +23,18 @@
#define VBMETA_PART ""
#endif
+#if defined(CONFIG_CMD_AB_SELECT)
+#define COMMON_PARTS \
+ "name=boot_a,size=20M,uuid=${uuid_gpt_boot_a};" \
+ "name=boot_b,size=20M,uuid=${uuid_gpt_boot_b};" \
+ "name=system_a,size=1024M,uuid=${uuid_gpt_system_a};" \
+ "name=system_b,size=1024M,uuid=${uuid_gpt_system_b};"
+#else
+#define COMMON_PARTS \
+ "name=boot,size=20M,uuid=${uuid_gpt_boot};" \
+ "name=system,size=1024M,uuid=${uuid_gpt_system};"
+#endif
+
#ifndef PARTS_DEFAULT
/* Define the default GPT table for eMMC */
#define PARTS_DEFAULT \
@@ -38,8 +50,7 @@
"name=uboot-env,start=2432K,size=256K,uuid=${uuid_gpt_reserved};" \
"name=misc,size=128K,uuid=${uuid_gpt_misc};" \
"name=recovery,size=40M,uuid=${uuid_gpt_recovery};" \
- "name=boot,size=10M,uuid=${uuid_gpt_boot};" \
- "name=system,size=1024M,uuid=${uuid_gpt_system};" \
+ COMMON_PARTS \
"name=vendor,size=256M,uuid=${uuid_gpt_vendor};" \
VBMETA_PART \
"name=userdata,size=-,uuid=${uuid_gpt_userdata}"
@@ -58,6 +69,35 @@
#define AVB_VERIFY_CMD ""
#endif
+#define CONTROL_PARTITION "misc"
+
+#if defined(CONFIG_CMD_AB_SELECT)
+#define AB_SELECT \
+ "if part number mmc 1 " CONTROL_PARTITION " control_part_number; " \
+ "then " \
+ "echo " CONTROL_PARTITION \
+ " partition number:${control_part_number};" \
+ "ab_select slot_name mmc ${mmcdev}:${control_part_number};" \
+ "else " \
+ "echo " CONTROL_PARTITION " partition not found;" \
+ "exit;" \
+ "fi;" \
+ "setenv slot_suffix _${slot_name};" \
+ "if part number mmc ${mmcdev} system${slot_suffix} " \
+ "system_part_number; then " \
+ "setenv bootargs_ab " \
+ "ro root=/dev/mmcblk${mmcdev}p${system_part_number} " \
+ "rootwait init=/init skip_initramfs " \
+ "androidboot.slot_suffix=${slot_suffix};" \
+ "echo A/B cmdline addition: ${bootargs_ab};" \
+ "setenv bootargs ${bootargs} ${bootargs_ab};" \
+ "else " \
+ "echo system${slot_suffix} partition not found;" \
+ "fi;"
+#else
+#define AB_SELECT ""
+#endif
+
#define DEFAULT_COMMON_BOOT_TI_ARGS \
"console=" CONSOLEDEV ",115200n8\0" \
"fdtfile=undefined\0" \
@@ -86,10 +126,16 @@
"mmc dev $mmcdev; " \
"mmc rescan; " \
AVB_VERIFY_CHECK \
- "part start mmc ${mmcdev} boot boot_start; " \
- "part size mmc ${mmcdev} boot boot_size; " \
- "mmc read ${loadaddr} ${boot_start} ${boot_size}; " \
- "bootm ${loadaddr}#${fdtfile};\0 "
+ AB_SELECT \
+ "if part start mmc ${mmcdev} boot${slot_suffix} boot_start; " \
+ "then " \
+ "part size mmc ${mmcdev} boot${slot_suffix} " \
+ "boot_size; " \
+ "mmc read ${loadaddr} ${boot_start} ${boot_size}; " \
+ "bootm ${loadaddr}#${fdtfile}; " \
+ "else " \
+ "echo boot${slot_suffix} partition not found; " \
+ "fi;\0"
#ifdef CONFIG_OMAP54XX
diff --git a/include/ext_common.h b/include/ext_common.h
index 17c92f1..1c10c50 100644
--- a/include/ext_common.h
+++ b/include/ext_common.h
@@ -21,6 +21,7 @@
#define __EXT_COMMON__
#include <command.h>
#define SECTOR_SIZE 0x200
+#define LOG2_SECTOR_SIZE 9
/* Magic value used to identify an ext2 filesystem. */
#define EXT2_MAGIC 0xEF53
diff --git a/include/fdt_support.h b/include/fdt_support.h
index 27fe564..cefb2b2 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -218,8 +218,32 @@
#endif
void fdt_del_node_and_alias(void *blob, const char *alias);
+
+/**
+ * Translate an address from the DT into a CPU physical address
+ *
+ * The translation relies on the "ranges" property.
+ *
+ * @param blob Pointer to device tree blob
+ * @param node_offset Node DT offset
+ * @param in_addr Pointer to the address to translate
+ * @return translated address or OF_BAD_ADDR on error
+ */
u64 fdt_translate_address(const void *blob, int node_offset,
const __be32 *in_addr);
+/**
+ * Translate a DMA address from the DT into a CPU physical address
+ *
+ * The translation relies on the "dma-ranges" property.
+ *
+ * @param blob Pointer to device tree blob
+ * @param node_offset Node DT offset
+ * @param in_addr Pointer to the DMA address to translate
+ * @return translated DMA address or OF_BAD_ADDR on error
+ */
+u64 fdt_translate_dma_address(const void *blob, int node_offset,
+ const __be32 *in_addr);
+
int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
phys_addr_t compat_off);
int fdt_alloc_phandle(void *blob);
diff --git a/include/linux/clk/analogbits-wrpll-cln28hpc.h b/include/linux/clk/analogbits-wrpll-cln28hpc.h
new file mode 100644
index 0000000..0327909
--- /dev/null
+++ b/include/linux/clk/analogbits-wrpll-cln28hpc.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ */
+
+#ifndef __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
+#define __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
+
+#include <linux/types.h>
+
+/* DIVQ_VALUES: number of valid DIVQ values */
+#define DIVQ_VALUES 6
+
+/*
+ * Bit definitions for struct wrpll_cfg.flags
+ *
+ * WRPLL_FLAGS_BYPASS_FLAG: if set, the PLL is either in bypass, or should be
+ * programmed to enter bypass
+ * WRPLL_FLAGS_RESET_FLAG: if set, the PLL is in reset
+ * WRPLL_FLAGS_INT_FEEDBACK_FLAG: if set, the PLL is configured for internal
+ * feedback mode
+ * WRPLL_FLAGS_EXT_FEEDBACK_FLAG: if set, the PLL is configured for external
+ * feedback mode (not yet supported by this driver)
+ */
+#define WRPLL_FLAGS_BYPASS_SHIFT 0
+#define WRPLL_FLAGS_BYPASS_MASK BIT(WRPLL_FLAGS_BYPASS_SHIFT)
+#define WRPLL_FLAGS_RESET_SHIFT 1
+#define WRPLL_FLAGS_RESET_MASK BIT(WRPLL_FLAGS_RESET_SHIFT)
+#define WRPLL_FLAGS_INT_FEEDBACK_SHIFT 2
+#define WRPLL_FLAGS_INT_FEEDBACK_MASK BIT(WRPLL_FLAGS_INT_FEEDBACK_SHIFT)
+#define WRPLL_FLAGS_EXT_FEEDBACK_SHIFT 3
+#define WRPLL_FLAGS_EXT_FEEDBACK_MASK BIT(WRPLL_FLAGS_EXT_FEEDBACK_SHIFT)
+
+/**
+ * struct wrpll_cfg - WRPLL configuration values
+ * @divr: reference divider value (6 bits), as presented to the PLL signals
+ * @divf: feedback divider value (9 bits), as presented to the PLL signals
+ * @divq: output divider value (3 bits), as presented to the PLL signals
+ * @flags: PLL configuration flags. See above for more information
+ * @range: PLL loop filter range. See below for more information
+ * @output_rate_cache: cached output rates, swept across DIVQ
+ * @parent_rate: PLL refclk rate for which values are valid
+ * @max_r: maximum possible R divider value, given @parent_rate
+ * @init_r: initial R divider value to start the search from
+ *
+ * @divr, @divq, @divq, @range represent what the PLL expects to see
+ * on its input signals. Thus @divr and @divf are the actual divisors
+ * minus one. @divq is a power-of-two divider; for example, 1 =
+ * divide-by-2 and 6 = divide-by-64. 0 is an invalid @divq value.
+ *
+ * When initially passing a struct wrpll_cfg record, the
+ * record should be zero-initialized with the exception of the @flags
+ * field. The only flag bits that need to be set are either
+ * WRPLL_FLAGS_INT_FEEDBACK or WRPLL_FLAGS_EXT_FEEDBACK.
+ */
+struct wrpll_cfg {
+ u8 divr;
+ u8 divq;
+ u8 range;
+ u8 flags;
+ u16 divf;
+/* private: */
+ u32 output_rate_cache[DIVQ_VALUES];
+ unsigned long parent_rate;
+ u8 max_r;
+ u8 init_r;
+};
+
+int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
+ unsigned long parent_rate);
+
+unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c);
+
+unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
+ unsigned long parent_rate);
+
+#endif /* __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H */
diff --git a/include/miiphy.h b/include/miiphy.h
index e6dd441..9b97d09 100644
--- a/include/miiphy.h
+++ b/include/miiphy.h
@@ -167,4 +167,24 @@
#endif
+#ifdef CONFIG_DM_MDIO_MUX
+
+/* indicates none of the child buses is selected */
+#define MDIO_MUX_SELECT_NONE -1
+
+/**
+ * struct mdio_mux_ops - MDIO MUX operations
+ *
+ * @select: Selects a child bus
+ * @deselect: Clean up selection. Optional, can be NULL
+ */
+struct mdio_mux_ops {
+ int (*select)(struct udevice *mux, int cur, int sel);
+ int (*deselect)(struct udevice *mux, int sel);
+};
+
+#define mdio_mux_get_ops(dev) ((struct mdio_mux_ops *)(dev)->driver->ops)
+
+#endif
+
#endif
diff --git a/include/net.h b/include/net.h
index 44b3238..7684076 100644
--- a/include/net.h
+++ b/include/net.h
@@ -728,7 +728,7 @@
}
/* return ulong *in network byteorder* */
-static inline u32 net_read_u32(u32 *from)
+static inline u32 net_read_u32(void *from)
{
u32 l;
@@ -749,7 +749,7 @@
}
/* copy ulong */
-static inline void net_copy_u32(u32 *to, u32 *from)
+static inline void net_copy_u32(void *to, void *from)
{
memcpy((void *)to, (void *)from, sizeof(u32));
}
diff --git a/include/netdev.h b/include/netdev.h
index 0a1a3a2..a40c4ad 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -30,7 +30,6 @@
int bfin_EMAC_initialize(bd_t *bis);
int calxedaxgmac_initialize(u32 id, ulong base_addr);
int cs8900_initialize(u8 dev_num, int base_addr);
-int davinci_emac_initialize(void);
int dc21x4x_initialize(bd_t *bis);
int designware_initialize(ulong base_addr, u32 interface);
int dm9000_initialize(bd_t *bis);
diff --git a/include/part.h b/include/part.h
index ebca546..0b5cf3d 100644
--- a/include/part.h
+++ b/include/part.h
@@ -202,6 +202,27 @@
const char *name, disk_partition_t *info);
/**
+ * Get partition info from dev number + part name, or dev number + part number.
+ *
+ * Parse a device number and partition description (either name or number)
+ * in the form of device number plus partition name separated by a "#"
+ * (like "device_num#partition_name") or a device number plus a partition number
+ * separated by a ":". For example both "0#misc" and "0:1" can be valid
+ * partition descriptions for a given interface. If the partition is found, sets
+ * dev_desc and part_info accordingly with the information of the partition.
+ *
+ * @param[in] dev_iface Device interface
+ * @param[in] dev_part_str Input partition description, like "0#misc" or "0:1"
+ * @param[out] dev_desc Place to store the device description pointer
+ * @param[out] part_info Place to store the partition information
+ * @return 0 on success, or a negative on error
+ */
+int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
+ const char *dev_part_str,
+ struct blk_desc **dev_desc,
+ disk_partition_t *part_info);
+
+/**
* part_set_generic_name() - create generic partition like hda1 or sdb2
*
* Helper function for partition tables, which don't hold partition names
diff --git a/include/pe.h b/include/pe.h
index 36e1908..bff3b0a 100644
--- a/include/pe.h
+++ b/include/pe.h
@@ -34,22 +34,6 @@
uint32_t e_lfanew; /* 3c: Offset to extended header */
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
-#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
-#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
-
-#define IMAGE_FILE_MACHINE_I386 0x014c
-#define IMAGE_FILE_MACHINE_ARM 0x01c0
-#define IMAGE_FILE_MACHINE_THUMB 0x01c2
-#define IMAGE_FILE_MACHINE_ARMNT 0x01c4
-#define IMAGE_FILE_MACHINE_AMD64 0x8664
-#define IMAGE_FILE_MACHINE_ARM64 0xaa64
-#define IMAGE_FILE_MACHINE_RISCV32 0x5032
-#define IMAGE_FILE_MACHINE_RISCV64 0x5064
-
-#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
-#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
-#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
-
typedef struct _IMAGE_FILE_HEADER {
uint16_t Machine;
uint16_t NumberOfSections;
diff --git a/include/phy.h b/include/phy.h
index d01435d..f4530fa 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -246,15 +246,71 @@
#endif
+/**
+ * phy_init() - Initializes the PHY drivers
+ *
+ * This function registers all available PHY drivers
+ *
+ * @return 0 if OK, -ve on error
+ */
int phy_init(void);
+
+/**
+ * phy_reset() - Resets the specified PHY
+ *
+ * Issues a reset of the PHY and waits for it to complete
+ *
+ * @phydev: PHY to reset
+ * @return 0 if OK, -ve on error
+ */
int phy_reset(struct phy_device *phydev);
+
+/**
+ * phy_find_by_mask() - Searches for a PHY on the specified MDIO bus
+ *
+ * The function checks the PHY addresses flagged in phy_mask and returns a
+ * phy_device pointer if it detects a PHY.
+ * This function should only be called if just one PHY is expected to be present
+ * in the set of addresses flagged in phy_mask. If multiple PHYs are present,
+ * it is undefined which of these PHYs is returned.
+ *
+ * @bus: MII/MDIO bus to scan
+ * @phy_mask: bitmap of PYH addresses to scan
+ * @interface: type of MAC-PHY interface
+ * @return pointer to phy_device if a PHY is found, or NULL otherwise
+ */
struct phy_device *phy_find_by_mask(struct mii_dev *bus, unsigned phy_mask,
phy_interface_t interface);
+
#ifdef CONFIG_DM_ETH
+
+/**
+ * phy_connect_dev() - Associates the given pair of PHY and Ethernet devices
+ * @phydev: PHY device
+ * @dev: Ethernet device
+ */
void phy_connect_dev(struct phy_device *phydev, struct udevice *dev);
+
+/**
+ * phy_connect() - Creates a PHY device for the Ethernet interface
+ *
+ * Creates a PHY device for the PHY at the given address, if one doesn't exist
+ * already, and associates it with the Ethernet device.
+ * The function may be called with addr <= 0, in this case addr value is ignored
+ * and the bus is scanned to detect a PHY. Scanning should only be used if only
+ * one PHY is expected to be present on the MDIO bus, otherwise it is undefined
+ * which PHY is returned.
+ *
+ * @bus: MII/MDIO bus that hosts the PHY
+ * @addr: PHY address on MDIO bus
+ * @dev: Ethernet device to associate to the PHY
+ * @interface: type of MAC-PHY interface
+ * @return pointer to phy_device if a PHY is found, or NULL otherwise
+ */
struct phy_device *phy_connect(struct mii_dev *bus, int addr,
struct udevice *dev,
phy_interface_t interface);
+
static inline ofnode phy_get_ofnode(struct phy_device *phydev)
{
if (ofnode_valid(phydev->node))
@@ -263,10 +319,34 @@
return dev_ofnode(phydev->dev);
}
#else
+
+/**
+ * phy_connect_dev() - Associates the given pair of PHY and Ethernet devices
+ * @phydev: PHY device
+ * @dev: Ethernet device
+ */
void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev);
+
+/**
+ * phy_connect() - Creates a PHY device for the Ethernet interface
+ *
+ * Creates a PHY device for the PHY at the given address, if one doesn't exist
+ * already, and associates it with the Ethernet device.
+ * The function may be called with addr <= 0, in this case addr value is ignored
+ * and the bus is scanned to detect a PHY. Scanning should only be used if only
+ * one PHY is expected to be present on the MDIO bus, otherwise it is undefined
+ * which PHY is returned.
+ *
+ * @bus: MII/MDIO bus that hosts the PHY
+ * @addr: PHY address on MDIO bus
+ * @dev: Ethernet device to associate to the PHY
+ * @interface: type of MAC-PHY interface
+ * @return pointer to phy_device if a PHY is found, or NULL otherwise
+ */
struct phy_device *phy_connect(struct mii_dev *bus, int addr,
struct eth_device *dev,
phy_interface_t interface);
+
static inline ofnode phy_get_ofnode(struct phy_device *phydev)
{
return ofnode_null();
diff --git a/include/power-domain.h b/include/power-domain.h
index 0099605..0737070 100644
--- a/include/power-domain.h
+++ b/include/power-domain.h
@@ -151,7 +151,7 @@
#endif
/**
- * power_domain_off - Disable power ot a power domain.
+ * power_domain_off - Disable power to a power domain.
*
* @power_domain: A power domain struct that was previously successfully
* requested by power_domain_get().
diff --git a/include/regmap.h b/include/regmap.h
index 3cd7a66..0854200 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -330,6 +330,8 @@
int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
struct regmap **mapp);
+int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index);
+
/**
* regmap_get_range() - Obtain the base memory address of a regmap range
*
diff --git a/include/remoteproc.h b/include/remoteproc.h
index a59dba8..4987194 100644
--- a/include/remoteproc.h
+++ b/include/remoteproc.h
@@ -45,117 +45,181 @@
};
/**
- * struct dm_rproc_ops - Operations that are provided by remote proc driver
- * @init: Initialize the remoteproc device invoked after probe (optional)
- * Return 0 on success, -ve error on fail
- * @load: Load the remoteproc device using data provided(mandatory)
- * This takes the following additional arguments.
- * addr- Address of the binary image to be loaded
- * size- Size of the binary image to be loaded
- * Return 0 on success, -ve error on fail
- * @start: Start the remoteproc device (mandatory)
- * Return 0 on success, -ve error on fail
- * @stop: Stop the remoteproc device (optional)
- * Return 0 on success, -ve error on fail
- * @reset: Reset the remote proc device (optional)
- * Return 0 on success, -ve error on fail
- * @is_running: Check if the remote processor is running(optional)
- * Return 0 on success, 1 if not running, -ve on others errors
- * @ping: Ping the remote device for basic communication check(optional)
- * Return 0 on success, 1 if not responding, -ve on other errors
+ * struct dm_rproc_ops - Driver model remote proc operations.
+ *
+ * This defines the operations provided by remote proc driver.
*/
struct dm_rproc_ops {
+ /**
+ * init() - Initialize the remoteproc device (optional)
+ *
+ * This is called after the probe is completed allowing the remote
+ * processor drivers to split up the initializations between probe and
+ * init if needed.
+ *
+ * @dev: Remote proc device
+ * @return 0 if all ok, else appropriate error value.
+ */
int (*init)(struct udevice *dev);
+
+ /**
+ * load() - Load the remoteproc device using data provided (mandatory)
+ *
+ * Load the remoteproc device with an image, do not start the device.
+ *
+ * @dev: Remote proc device
+ * @addr: Address of the image to be loaded
+ * @size: Size of the image to be loaded
+ * @return 0 if all ok, else appropriate error value.
+ */
int (*load)(struct udevice *dev, ulong addr, ulong size);
+
+ /**
+ * start() - Start the remoteproc device (mandatory)
+ *
+ * @dev: Remote proc device
+ * @return 0 if all ok, else appropriate error value.
+ */
int (*start)(struct udevice *dev);
+
+ /**
+ * stop() - Stop the remoteproc device (optional)
+ *
+ * @dev: Remote proc device
+ * @return 0 if all ok, else appropriate error value.
+ */
int (*stop)(struct udevice *dev);
+
+ /**
+ * reset() - Reset the remoteproc device (optional)
+ *
+ * @dev: Remote proc device
+ * @return 0 if all ok, else appropriate error value.
+ */
int (*reset)(struct udevice *dev);
+
+ /**
+ * is_running() - Check if the remote processor is running (optional)
+ *
+ * @dev: Remote proc device
+ * @return 0 if running, 1 if not running, -ve on error.
+ */
int (*is_running)(struct udevice *dev);
+
+ /**
+ * ping() - Ping the remote device for basic communication (optional)
+ *
+ * @dev: Remote proc device
+ * @return 0 on success, 1 if not responding, -ve on other errors.
+ */
int (*ping)(struct udevice *dev);
+
+ /**
+ * device_to_virt() - Return translated virtual address (optional)
+ *
+ * Translate a device address (remote processor view) to virtual
+ * address (main processor view).
+ *
+ * @dev: Remote proc device
+ * @da: Device address
+ * @return virtual address.
+ */
+ void * (*device_to_virt)(struct udevice *dev, ulong da);
};
/* Accessor */
#define rproc_get_ops(dev) ((struct dm_rproc_ops *)(dev)->driver->ops)
-#ifdef CONFIG_REMOTEPROC
+#if CONFIG_IS_ENABLED(REMOTEPROC)
/**
* rproc_init() - Initialize all bound remote proc devices
- *
- * Return: 0 if all ok, else appropriate error value.
+ * @return 0 if all ok, else appropriate error value.
*/
int rproc_init(void);
/**
* rproc_dev_init() - Initialize a remote proc device based on id
* @id: id of the remote processor
- *
- * Return: 0 if all ok, else appropriate error value.
+ * @return 0 if all ok, else appropriate error value.
*/
int rproc_dev_init(int id);
/**
* rproc_is_initialized() - check to see if remoteproc devices are initialized
- *
- * Return: 0 if all devices are initialized, else appropriate error value.
+ * @return true if all devices are initialized, false otherwise.
*/
bool rproc_is_initialized(void);
/**
- * rproc_load() - load binary to a remote processor
+ * rproc_load() - load binary or elf to a remote processor
* @id: id of the remote processor
- * @addr: address in memory where the binary image is located
- * @size: size of the binary image
- *
- * Return: 0 if all ok, else appropriate error value.
+ * @addr: address in memory where the image is located
+ * @size: size of the image
+ * @return 0 if all ok, else appropriate error value.
*/
int rproc_load(int id, ulong addr, ulong size);
/**
* rproc_start() - Start a remote processor
* @id: id of the remote processor
- *
- * Return: 0 if all ok, else appropriate error value.
+ * @return 0 if all ok, else appropriate error value.
*/
int rproc_start(int id);
/**
* rproc_stop() - Stop a remote processor
* @id: id of the remote processor
- *
- * Return: 0 if all ok, else appropriate error value.
+ * @return 0 if all ok, else appropriate error value.
*/
int rproc_stop(int id);
/**
* rproc_reset() - reset a remote processor
* @id: id of the remote processor
- *
- * Return: 0 if all ok, else appropriate error value.
+ * @return 0 if all ok, else appropriate error value.
*/
int rproc_reset(int id);
/**
* rproc_ping() - ping a remote processor to check if it can communicate
* @id: id of the remote processor
+ * @return 0 if all ok, else appropriate error value.
*
* NOTE: this might need communication path available, which is not implemented
* as part of remoteproc framework - hook on to appropriate bus architecture to
* do the same
- *
- * Return: 0 if all ok, else appropriate error value.
*/
int rproc_ping(int id);
/**
* rproc_is_running() - check to see if remote processor is running
* @id: id of the remote processor
+ * @return 0 if running, 1 if not running, -ve on error.
*
* NOTE: this may not involve actual communication capability of the remote
* processor, but just ensures that it is out of reset and executing code.
- *
- * Return: 0 if all ok, else appropriate error value.
*/
int rproc_is_running(int id);
+
+/**
+ * rproc_elf32_sanity_check() - Verify if an image is a valid ELF32 one
+ *
+ * Check if a valid ELF32 image exists at the given memory location. Verify
+ * basic ELF32 format requirements like magic number and sections size.
+ *
+ * @addr: address of the image to verify
+ * @size: size of the image
+ * @return 0 if the image looks good, else appropriate error value.
+ */
+int rproc_elf32_sanity_check(ulong addr, ulong size);
+
+/**
+ * rproc_elf32_load_image() - load an ELF32 image
+ * @dev: device loading the ELF32 image
+ * @addr: valid ELF32 image address
+ * @return 0 if the image is successfully loaded, else appropriate error value.
+ */
+int rproc_elf32_load_image(struct udevice *dev, unsigned long addr);
#else
static inline int rproc_init(void) { return -ENOSYS; }
static inline int rproc_dev_init(int id) { return -ENOSYS; }
@@ -166,6 +230,10 @@
static inline int rproc_reset(int id) { return -ENOSYS; }
static inline int rproc_ping(int id) { return -ENOSYS; }
static inline int rproc_is_running(int id) { return -ENOSYS; }
+static inline int rproc_elf32_sanity_check(ulong addr,
+ ulong size) { return -ENOSYS; }
+static inline int rproc_elf32_load_image(struct udevice *dev,
+ unsigned long addr) { return -ENOSYS; }
#endif
#endif /* _RPROC_H_ */
diff --git a/include/sdhci.h b/include/sdhci.h
index eee493a..01addb7 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -144,7 +144,23 @@
#define SDHCI_ACMD12_ERR 0x3C
-/* 3E-3F reserved */
+#define SDHCI_HOST_CONTROL2 0x3E
+#define SDHCI_CTRL_UHS_MASK 0x0007
+#define SDHCI_CTRL_UHS_SDR12 0x0000
+#define SDHCI_CTRL_UHS_SDR25 0x0001
+#define SDHCI_CTRL_UHS_SDR50 0x0002
+#define SDHCI_CTRL_UHS_SDR104 0x0003
+#define SDHCI_CTRL_UHS_DDR50 0x0004
+#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */
+#define SDHCI_CTRL_VDD_180 0x0008
+#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
+#define SDHCI_CTRL_DRV_TYPE_B 0x0000
+#define SDHCI_CTRL_DRV_TYPE_A 0x0010
+#define SDHCI_CTRL_DRV_TYPE_C 0x0020
+#define SDHCI_CTRL_DRV_TYPE_D 0x0030
+#define SDHCI_CTRL_EXEC_TUNING 0x0040
+#define SDHCI_CTRL_TUNED_CLK 0x0080
+#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
#define SDHCI_CAPABILITIES 0x40
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
@@ -247,7 +263,7 @@
#endif
int (*get_cd)(struct sdhci_host *host);
void (*set_control_reg)(struct sdhci_host *host);
- void (*set_ios_post)(struct sdhci_host *host);
+ int (*set_ios_post)(struct sdhci_host *host);
void (*set_clock)(struct sdhci_host *host, u32 div);
int (*platform_execute_tuning)(struct mmc *host, u8 opcode);
void (*set_delay)(struct sdhci_host *host);
@@ -467,9 +483,11 @@
int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min);
#endif /* !CONFIG_BLK */
+void sdhci_set_uhs_timing(struct sdhci_host *host);
#ifdef CONFIG_DM_MMC
/* Export the operations to drivers */
int sdhci_probe(struct udevice *dev);
+int sdhci_set_clock(struct mmc *mmc, unsigned int clock);
extern const struct dm_mmc_ops sdhci_ops;
#else
#endif
diff --git a/include/spl.h b/include/spl.h
index a9aaef3..a90f971 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -109,6 +109,15 @@
binman_sym_extern(ulong, u_boot_any, image_pos);
/**
+ * spl_load_simple_fit_skip_processing() - Hook to allow skipping the FIT
+ * image processing during spl_load_simple_fit().
+ *
+ * Return true to skip FIT processing, false to preserve the full code flow
+ * of spl_load_simple_fit().
+ */
+bool spl_load_simple_fit_skip_processing(void);
+
+/**
* spl_load_simple_fit() - Loads a fit image from a device.
* @spl_image: Image description to set up
* @info: Structure containing the information required to load data.
@@ -331,6 +340,23 @@
struct spl_boot_device *bootdev);
/**
+ * spl_mmc_load() - Load an image file from MMC/SD media
+ *
+ * @param spl_image Image data filled in by loading process
+ * @param bootdev Describes which device to load from
+ * @param filename Name of file to load (in FS mode)
+ * @param raw_part Partition to load from (in RAW mode)
+ * @param raw_sect Sector to load from (in RAW mode)
+ *
+ * @return 0 on success, otherwise error code
+ */
+int spl_mmc_load(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev,
+ const char *filename,
+ int raw_part,
+ unsigned long raw_sect);
+
+/**
* spl_invoke_atf - boot using an ARM trusted firmware image
*/
void spl_invoke_atf(struct spl_image_info *spl_image);
diff --git a/include/tsec.h b/include/tsec.h
index e900951..b17fa95 100644
--- a/include/tsec.h
+++ b/include/tsec.h
@@ -17,6 +17,8 @@
#include <config.h>
#include <phy.h>
+#define TSEC_MDIO_REGS_OFFSET 0x520
+
#ifndef CONFIG_DM_ETH
#ifdef CONFIG_ARCH_LS1021A
@@ -27,7 +29,7 @@
#define TSEC_MDIO_OFFSET 0x01000
#endif
-#define CONFIG_SYS_MDIO_BASE_ADDR (MDIO_BASE_ADDR + 0x520)
+#define CONFIG_SYS_MDIO_BASE_ADDR (MDIO_BASE_ADDR + TSEC_MDIO_REGS_OFFSET)
#define TSEC_GET_REGS(num, offset) \
(struct tsec __iomem *)\
diff --git a/lib/charset.c b/lib/charset.c
index 5e349ed..72d745d 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -335,11 +335,16 @@
return ret;
}
-size_t u16_strlen(const u16 *in)
+size_t u16_strlen(const void *in)
{
- size_t i;
- for (i = 0; in[i]; i++);
- return i;
+ const char *pos = in;
+ size_t ret;
+
+ for (; pos[0] || pos[1]; pos += 2)
+ ;
+ ret = pos - (char *)in;
+ ret >>= 1;
+ return ret;
}
size_t u16_strnlen(const u16 *in, size_t count)
@@ -362,18 +367,18 @@
return tmp;
}
-u16 *u16_strdup(const u16 *src)
+u16 *u16_strdup(const void *src)
{
u16 *new;
+ size_t len;
if (!src)
return NULL;
-
- new = malloc((u16_strlen(src) + 1) * sizeof(u16));
+ len = (u16_strlen(src) + 1) * sizeof(u16);
+ new = malloc(len);
if (!new)
return NULL;
-
- u16_strcpy(new, src);
+ memcpy(new, src, len);
return new;
}
diff --git a/lib/efi_driver/efi_block_device.c b/lib/efi_driver/efi_block_device.c
index 3f147cf..cf02341 100644
--- a/lib/efi_driver/efi_block_device.c
+++ b/lib/efi_driver/efi_block_device.c
@@ -43,14 +43,14 @@
struct efi_block_io *io;
};
-/*
+/**
* Read from block device
*
- * @dev device
- * @blknr first block to be read
- * @blkcnt number of blocks to read
- * @buffer output buffer
- * @return number of blocks transferred
+ * @dev: device
+ * @blknr: first block to be read
+ * @blkcnt: number of blocks to read
+ * @buffer: output buffer
+ * Return: number of blocks transferred
*/
static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *buffer)
@@ -72,14 +72,14 @@
return blkcnt;
}
-/*
+/**
* Write to block device
*
- * @dev device
- * @blknr first block to be write
- * @blkcnt number of blocks to write
- * @buffer input buffer
- * @return number of blocks transferred
+ * @dev: device
+ * @blknr: first block to be write
+ * @blkcnt: number of blocks to write
+ * @buffer: input buffer
+ * Return: number of blocks transferred
*/
static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
const void *buffer)
@@ -102,11 +102,12 @@
return blkcnt;
}
-/*
+/**
* Create partions for the block device.
*
- * @handle EFI handle of the block device
- * @dev udevice of the block device
+ * @handle: EFI handle of the block device
+ * @dev: udevice of the block device
+ * Return: number of partitions created
*/
static int efi_bl_bind_partitions(efi_handle_t handle, struct udevice *dev)
{
@@ -120,12 +121,12 @@
desc->devnum, dev->name);
}
-/*
+/**
* Create a block device for a handle
*
- * @handle handle
- * @interface block io protocol
- * @return 0 = success
+ * @handle: handle
+ * @interface: block io protocol
+ * Return: 0 = success
*/
static int efi_bl_bind(efi_handle_t handle, void *interface)
{
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index b2102c5..2ea2144 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -27,7 +27,15 @@
*/
-/* Parse serialized data and transform it into efi_load_option structure */
+/**
+ * efi_deserialize_load_option() - parse serialized data
+ *
+ * Parse serialized data describing a load option and transform it to the
+ * efi_load_option structure.
+ *
+ * @lo: pointer to target
+ * @data: serialized data
+ */
void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data)
{
lo->attributes = get_unaligned_le32(data);
@@ -47,9 +55,14 @@
lo->optional_data = data;
}
-/*
+/**
+ * efi_serialize_load_option() - serialize load option
+ *
* Serialize efi_load_option structure into byte stream for BootXXXX.
- * Return a size of allocated data.
+ *
+ * @data: buffer for serialized data
+ * @lo: load option
+ * Return: size of allocated buffer
*/
unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
{
@@ -92,7 +105,16 @@
return size;
}
-/* free() the result */
+/**
+ * get_var() - get UEFI variable
+ *
+ * It is the caller's duty to free the returned buffer.
+ *
+ * @name: name of variable
+ * @vendor: vendor GUID of variable
+ * @size: size of allocated buffer
+ * Return: buffer with variable data or NULL
+ */
static void *get_var(u16 *name, const efi_guid_t *vendor,
efi_uintn_t *size)
{
@@ -116,10 +138,16 @@
return buf;
}
-/*
+/**
+ * try_load_entry() - try to load image for boot option
+ *
* Attempt to load load-option number 'n', returning device_path and file_path
- * if successful. This checks that the EFI_LOAD_OPTION is active (enabled)
+ * if successful. This checks that the EFI_LOAD_OPTION is active (enabled)
* and that the specified file to boot exists.
+ *
+ * @n: number of the boot option, e.g. 0x0a13 for Boot0A13
+ * @handle: on return handle for the newly installed image
+ * Return: status code
*/
static efi_status_t try_load_entry(u16 n, efi_handle_t *handle)
{
@@ -180,10 +208,15 @@
return ret;
}
-/*
+/**
+ * efi_bootmgr_load() - try to load from BootNext or BootOrder
+ *
* Attempt to load from BootNext or in the order specified by BootOrder
* EFI variable, the available load-options, finding and returning
* the first one that can be loaded successfully.
+ *
+ * @handle: on return handle for the newly installed image
+ * Return: status code
*/
efi_status_t efi_bootmgr_load(efi_handle_t *handle)
{
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index c2f8980..4f6e8d1 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -25,7 +25,7 @@
LIST_HEAD(efi_obj_list);
/* List of all events */
-LIST_HEAD(efi_events);
+__efi_runtime_data LIST_HEAD(efi_events);
/* List of queued events */
LIST_HEAD(efi_event_queue);
@@ -596,7 +596,7 @@
/**
* efi_delete_handle() - delete handle
*
- * @obj: handle to delete
+ * @handle: handle to delete
*/
void efi_delete_handle(efi_handle_t handle)
{
@@ -628,6 +628,7 @@
/**
* efi_create_event() - create an event
+ *
* @type: type of the event to create
* @notify_tpl: task priority level of the event
* @notify_function: notification function of the event
@@ -650,6 +651,8 @@
struct efi_event **event)
{
struct efi_event *evt;
+ efi_status_t ret;
+ int pool_type;
if (event == NULL)
return EFI_INVALID_PARAMETER;
@@ -662,7 +665,10 @@
case EVT_NOTIFY_WAIT:
case EVT_TIMER | EVT_NOTIFY_WAIT:
case EVT_SIGNAL_EXIT_BOOT_SERVICES:
+ pool_type = EFI_BOOT_SERVICES_DATA;
+ break;
case EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE:
+ pool_type = EFI_RUNTIME_SERVICES_DATA;
break;
default:
return EFI_INVALID_PARAMETER;
@@ -672,9 +678,11 @@
(!notify_function || is_valid_tpl(notify_tpl) != EFI_SUCCESS))
return EFI_INVALID_PARAMETER;
- evt = calloc(1, sizeof(struct efi_event));
- if (!evt)
- return EFI_OUT_OF_RESOURCES;
+ ret = efi_allocate_pool(pool_type, sizeof(struct efi_event),
+ (void **)&evt);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ memset(evt, 0, sizeof(struct efi_event));
evt->type = type;
evt->notify_tpl = notify_tpl;
evt->notify_function = notify_function;
@@ -982,7 +990,7 @@
list_del(&event->queue_link);
list_del(&event->link);
- free(event);
+ efi_free_pool(event);
return EFI_EXIT(EFI_SUCCESS);
}
@@ -1411,9 +1419,9 @@
/**
* efi_search() - determine if an EFI handle implements a protocol
+ *
* @search_type: selection criterion
* @protocol: GUID of the protocol
- * @search_key: registration key
* @handle: handle
*
* See the documentation of the LocateHandle service in the UEFI specification.
@@ -1675,7 +1683,7 @@
* Initialize a loaded_image_info and loaded_image_info object with correct
* protocols, boot-device, etc.
*
- * In case of an error *handle_ptr and *info_ptr are set to NULL and an error
+ * In case of an error \*handle_ptr and \*info_ptr are set to NULL and an error
* code is returned.
*
* @device_path: device path of the loaded image
@@ -1932,7 +1940,7 @@
static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
efi_uintn_t map_key)
{
- struct efi_event *evt;
+ struct efi_event *evt, *next_event;
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %zx", image_handle, map_key);
@@ -1971,6 +1979,12 @@
/* Notify variable services */
efi_variables_boot_exit_notify();
+ /* Remove all events except EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
+ list_for_each_entry_safe(evt, next_event, &efi_events, link) {
+ if (evt->type != EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)
+ list_del(&evt->link);
+ }
+
board_quiesce_devices();
/* Patch out unsupported runtime function */
@@ -3034,9 +3048,9 @@
/**
* efi_update_exit_data() - fill exit data parameters of StartImage()
*
- * @image_obj image handle
- * @exit_data_size size of the exit data buffer
- * @exit_data buffer with data returned by UEFI payload
+ * @image_obj: image handle
+ * @exit_data_size: size of the exit data buffer
+ * @exit_data: buffer with data returned by UEFI payload
* Return: status code
*/
static efi_status_t efi_update_exit_data(struct efi_loaded_image_obj *image_obj,
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 10f890f..eeeb806 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -12,6 +12,7 @@
#include <mmc.h>
#include <efi_loader.h>
#include <part.h>
+#include <asm-generic/unaligned.h>
/* template END node: */
static const struct efi_device_path END = {
@@ -793,16 +794,36 @@
return buf;
}
-/* convert path to an UEFI style path (i.e. DOS style backslashes and UTF-16) */
-static void path_to_uefi(u16 *uefi, const char *path)
+/**
+ * path_to_uefi() - convert UTF-8 path to an UEFI style path
+ *
+ * Convert UTF-8 path to a UEFI style path (i.e. with backslashes as path
+ * separators and UTF-16).
+ *
+ * @src: source buffer
+ * @uefi: target buffer, possibly unaligned
+ */
+static void path_to_uefi(void *uefi, const char *src)
{
- while (*path) {
- char c = *(path++);
- if (c == '/')
- c = '\\';
- *(uefi++) = c;
+ u16 *pos = uefi;
+
+ /*
+ * efi_set_bootdev() calls this routine indirectly before the UEFI
+ * subsystem is initialized. So we cannot assume unaligned access to be
+ * enabled.
+ */
+ allow_unaligned();
+
+ while (*src) {
+ s32 code = utf8_get(&src);
+
+ if (code < 0)
+ code = '?';
+ else if (code == '/')
+ code = '\\';
+ utf16_put(code, &pos);
}
- *uefi = '\0';
+ *pos = 0;
}
/*
@@ -819,7 +840,8 @@
if (desc)
dpsize = dp_part_size(desc, part);
- fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
+ fpsize = sizeof(struct efi_device_path) +
+ 2 * (utf8_utf16_strlen(path) + 1);
dpsize += fpsize;
start = buf = dp_alloc(dpsize + sizeof(END));
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index 36ca719..f4ca569 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -755,6 +755,7 @@
struct efi_device_path_file_path *fdp =
container_of(fp, struct efi_device_path_file_path, dp);
struct efi_file_handle *f2;
+ u16 *filename;
if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {
printf("bad file path!\n");
@@ -762,8 +763,12 @@
return NULL;
}
- EFI_CALL(ret = f->open(f, &f2, fdp->str,
+ filename = u16_strdup(fdp->str);
+ if (!filename)
+ return NULL;
+ EFI_CALL(ret = f->open(f, &f2, filename,
EFI_FILE_MODE_READ, 0));
+ free(filename);
if (ret != EFI_SUCCESS)
return NULL;
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index 2737938..b5775e0 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -37,17 +37,21 @@
#endif
/**
- * efi_pool_allocation - memory block allocated from pool
+ * struct efi_pool_allocation - memory block allocated from pool
*
* @num_pages: number of pages allocated
* @checksum: checksum
+ * @data: allocated pool memory
*
- * U-Boot services each EFI AllocatePool request as a separate
- * (multiple) page allocation. We have to track the number of pages
+ * U-Boot services each UEFI AllocatePool() request as a separate
+ * (multiple) page allocation. We have to track the number of pages
* to be able to free the correct amount later.
+ *
+ * The checksum calculated in function checksum() is used in FreePool() to avoid
+ * freeing memory not allocated by AllocatePool() and duplicate freeing.
+ *
* EFI requires 8 byte alignment for pool allocations, so we can
- * prepend each allocation with an 64 bit header tracking the
- * allocation size, and hand out the remainder to the caller.
+ * prepend each allocation with these header fields.
*/
struct efi_pool_allocation {
u64 num_pages;
@@ -223,8 +227,17 @@
return EFI_CARVE_LOOP_AGAIN;
}
-uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
- bool overlap_only_ram)
+/**
+ * efi_add_memory_map() - add memory area to the memory map
+ *
+ * @start: start address, must be a multiple of EFI_PAGE_SIZE
+ * @pages: number of pages to add
+ * @memory_type: type of memory added
+ * @overlap_only_ram: the memory area must overlap existing
+ * Return: status code
+ */
+efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
+ bool overlap_only_ram)
{
struct list_head *lhandle;
struct efi_mem_list *newlist;
@@ -239,7 +252,7 @@
return EFI_INVALID_PARAMETER;
if (!pages)
- return start;
+ return EFI_SUCCESS;
++efi_memory_map_key;
newlist = calloc(1, sizeof(*newlist));
@@ -277,7 +290,7 @@
* The user requested to only have RAM overlaps,
* but we hit a non-RAM region. Error out.
*/
- return 0;
+ return EFI_NO_MAPPING;
case EFI_CARVE_NO_OVERLAP:
/* Just ignore this list entry */
break;
@@ -307,7 +320,7 @@
* The payload wanted to have RAM overlaps, but we overlapped
* with an unallocated region. Error out.
*/
- return 0;
+ return EFI_NO_MAPPING;
}
/* Add our new map */
@@ -326,7 +339,7 @@
}
}
- return start;
+ return EFI_SUCCESS;
}
/**
@@ -455,7 +468,7 @@
}
/* Reserve that map in our memory maps */
- if (efi_add_memory_map(addr, pages, memory_type, true) != addr)
+ if (efi_add_memory_map(addr, pages, memory_type, true) != EFI_SUCCESS)
/* Map would overlap, bail out */
return EFI_OUT_OF_RESOURCES;
@@ -487,7 +500,6 @@
*/
efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
{
- uint64_t r = 0;
efi_status_t ret;
ret = efi_check_allocated(memory, true);
@@ -501,13 +513,13 @@
return EFI_INVALID_PARAMETER;
}
- r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
+ ret = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
/* Merging of adjacent free regions is missing */
- if (r == memory)
- return EFI_SUCCESS;
+ if (ret != EFI_SUCCESS)
+ return EFI_NOT_FOUND;
- return EFI_NOT_FOUND;
+ return ret;
}
/**
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 7a64dd4..8b56ab0 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -391,8 +391,10 @@
*/
static bool efi_is_runtime_service_pointer(void *p)
{
- return p >= (void *)&efi_runtime_services.get_time &&
- p <= (void *)&efi_runtime_services.query_variable_info;
+ return (p >= (void *)&efi_runtime_services.get_time &&
+ p <= (void *)&efi_runtime_services.query_variable_info) ||
+ p == (void *)&efi_events.prev ||
+ p == (void *)&efi_events.next;
}
/**
@@ -424,7 +426,7 @@
* @virtmap: virtual address mapping information
* Return: status code EFI_UNSUPPORTED
*/
-static efi_status_t EFIAPI efi_set_virtual_address_map_runtime(
+static __efi_runtime efi_status_t EFIAPI efi_set_virtual_address_map_runtime(
unsigned long memory_map_size,
unsigned long descriptor_size,
uint32_t descriptor_version,
@@ -577,6 +579,7 @@
int n = memory_map_size / descriptor_size;
int i;
int rt_code_sections = 0;
+ struct efi_event *event;
EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
descriptor_version, virtmap);
@@ -610,6 +613,13 @@
return EFI_EXIT(EFI_INVALID_PARAMETER);
}
+ /* Notify EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
+ list_for_each_entry(event, &efi_events, link) {
+ if (event->notify_function)
+ EFI_CALL_VOID(event->notify_function(
+ event, event->notify_context));
+ }
+
/* Rebind mmio pointers */
for (i = 0; i < n; i++) {
struct efi_mem_desc *map = (void*)virtmap +
@@ -684,10 +694,10 @@
struct efi_runtime_mmio_list *newmmio;
u64 pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
uint64_t addr = *(uintptr_t *)mmio_ptr;
- uint64_t retaddr;
+ efi_status_t ret;
- retaddr = efi_add_memory_map(addr, pages, EFI_MMAP_IO, false);
- if (retaddr != addr)
+ ret = efi_add_memory_map(addr, pages, EFI_MMAP_IO, false);
+ if (ret != EFI_SUCCESS)
return EFI_OUT_OF_RESOURCES;
newmmio = calloc(1, sizeof(*newmmio));
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index bc8ed67..889a7f2 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -263,8 +263,8 @@
* is the size of variable name including NULL.
*
* Return: EFI_SUCCESS if parsing is OK, EFI_NOT_FOUND when
- the entire variable list has been returned,
- otherwise non-zero status code
+ * the entire variable list has been returned,
+ * otherwise non-zero status code
*/
static efi_status_t parse_uboot_variable(char *variable,
efi_uintn_t *variable_name_size,
@@ -315,6 +315,7 @@
/**
* efi_get_next_variable_name() - enumerate the current variable names
+ *
* @variable_name_size: size of variable_name buffer in byte
* @variable_name: name of uefi variable's name in u16
* @vendor: vendor's guid
@@ -322,8 +323,7 @@
* This function implements the GetNextVariableName service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
- * details: http://wiki.phoenix.com/wiki/index.php/
- * EFI_RUNTIME_SERVICES#GetNextVariableName.28.29
+ * details.
*
* Return: status code
*/
@@ -550,6 +550,13 @@
/**
* efi_get_variable_runtime() - runtime implementation of GetVariable()
+ *
+ * @variable_name: name of the variable
+ * @vendor: vendor GUID
+ * @attributes: attributes of the variable
+ * @data_size: size of the buffer to which the variable value is copied
+ * @data: buffer to which the variable value is copied
+ * Return: status code
*/
static efi_status_t __efi_runtime EFIAPI
efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
@@ -561,6 +568,11 @@
/**
* efi_get_next_variable_name_runtime() - runtime implementation of
* GetNextVariable()
+ *
+ * @variable_name_size: size of variable_name buffer in byte
+ * @variable_name: name of uefi variable's name in u16
+ * @vendor: vendor's guid
+ * Return: status code
*/
static efi_status_t __efi_runtime EFIAPI
efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
@@ -571,6 +583,13 @@
/**
* efi_set_variable_runtime() - runtime implementation of SetVariable()
+ *
+ * @variable_name: name of the variable
+ * @vendor: vendor GUID
+ * @attributes: attributes of the variable
+ * @data_size: size of the buffer with the variable value
+ * @data: buffer with the variable value
+ * Return: status code
*/
static efi_status_t __efi_runtime EFIAPI
efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 8867875..5d7a164 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -28,6 +28,7 @@
efi_selftest_memory.o \
efi_selftest_open_protocol.o \
efi_selftest_register_notify.o \
+efi_selftest_set_virtual_address_map.o \
efi_selftest_snp.o \
efi_selftest_textinput.o \
efi_selftest_textinputex.o \
diff --git a/lib/efi_selftest/efi_selftest_exitbootservices.c b/lib/efi_selftest/efi_selftest_exitbootservices.c
index f1a1360..4fecd1b 100644
--- a/lib/efi_selftest/efi_selftest_exitbootservices.c
+++ b/lib/efi_selftest/efi_selftest_exitbootservices.c
@@ -56,28 +56,6 @@
}
/*
- * Tear down unit test.
- *
- * Close the event created in setup.
- *
- * @return: EFI_ST_SUCCESS for success
- */
-static int teardown(void)
-{
- efi_status_t ret;
-
- if (event_notify) {
- ret = boottime->close_event(event_notify);
- event_notify = NULL;
- if (ret != EFI_SUCCESS) {
- efi_st_error("could not close event\n");
- return EFI_ST_FAILURE;
- }
- }
- return EFI_ST_SUCCESS;
-}
-
-/*
* Execute unit test.
*
* Check that the notification function of the EVT_SIGNAL_EXIT_BOOT_SERVICES
@@ -107,5 +85,4 @@
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute,
- .teardown = teardown,
};
diff --git a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c
new file mode 100644
index 0000000..6ee7bbe
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_set_virtual_address_map.c
+ *
+ * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * This test checks the notification of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+ * and the following services: SetVirtualAddressMap, ConvertPointer.
+ */
+
+#include <efi_selftest.h>
+
+static const struct efi_boot_services *boottime;
+static const struct efi_runtime_services *runtime;
+static struct efi_event *event;
+static struct efi_mem_desc *memory_map;
+static efi_uintn_t map_size;
+static efi_uintn_t desc_size;
+static u32 desc_version;
+static u64 page1;
+static u64 page2;
+static u32 notify_call_count;
+
+/**
+ * notify () - notification function
+ *
+ * This function is called when the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event
+ * occurs. The correct output of ConvertPointer() is checked.
+ *
+ * @event notified event
+ * @context pointer to the notification count
+ */
+static void EFIAPI notify(struct efi_event *event, void *context)
+{
+ void *addr;
+ efi_status_t ret;
+
+ ++notify_call_count;
+
+ addr = (void *)(uintptr_t)page1;
+ ret = runtime->convert_pointer(0, &addr);
+ if (ret != EFI_SUCCESS)
+ efi_st_todo("ConvertPointer failed\n");
+ if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE)
+ efi_st_todo("ConvertPointer wrong address\n");
+
+ addr = (void *)(uintptr_t)page2;
+ ret = runtime->convert_pointer(0, &addr);
+ if (ret != EFI_SUCCESS)
+ efi_st_todo("ConvertPointer failed\n");
+ if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE)
+ efi_st_todo("ConvertPointer wrong address\n");
+}
+
+/**
+ * setup() - setup unit test
+ *
+ * The memory map is read. Boottime only entries are deleted. Two entries for
+ * newly allocated pages are added. For these virtual addresses deviating from
+ * the physical addresses are set.
+ *
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+ const struct efi_system_table *systable)
+{
+ efi_uintn_t map_key;
+ efi_status_t ret;
+ struct efi_mem_desc *end, *pos1, *pos2;
+
+ boottime = systable->boottime;
+ runtime = systable->runtime;
+
+ ret = boottime->create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
+ TPL_CALLBACK, notify, NULL,
+ &event);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("could not create event\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
+ &desc_version);
+ if (ret != EFI_BUFFER_TOO_SMALL) {
+ efi_st_error(
+ "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
+ return EFI_ST_FAILURE;
+ }
+ /* Allocate extra space for newly allocated memory */
+ map_size += 3 * sizeof(struct efi_mem_desc);
+ ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
+ (void **)&memory_map);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("AllocatePool failed\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
+ &desc_size, &desc_version);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("GetMemoryMap failed\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_BOOT_SERVICES_DATA, 2, &page1);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("AllocatePages failed\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_BOOT_SERVICES_DATA, 3, &page2);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("AllocatePages failed\n");
+ return EFI_ST_FAILURE;
+ }
+ /* Remove entries not relevant for runtime from map */
+ end = (struct efi_mem_desc *)((u8 *)memory_map + map_size);
+ for (pos1 = memory_map, pos2 = memory_map;
+ pos2 < end; ++pos2) {
+ switch (pos2->type) {
+ case EFI_LOADER_CODE:
+ case EFI_LOADER_DATA:
+ case EFI_BOOT_SERVICES_CODE:
+ case EFI_BOOT_SERVICES_DATA:
+ continue;
+ }
+ memcpy(pos1, pos2, desc_size);
+ ++pos1;
+ }
+
+ /*
+ * Add entries with virtual addresses deviating from the physical
+ * addresses. By choosing virtual address ranges within the allocated
+ * physical pages address space collisions are avoided.
+ */
+ pos1->type = EFI_RUNTIME_SERVICES_DATA;
+ pos1->reserved = 0;
+ pos1->physical_start = page1;
+ pos1->virtual_start = page1 + EFI_PAGE_SIZE;
+ pos1->num_pages = 1;
+ pos1->attribute = EFI_MEMORY_RUNTIME;
+ ++pos1;
+
+ pos1->type = EFI_RUNTIME_SERVICES_DATA;
+ pos1->reserved = 0;
+ pos1->physical_start = page2;
+ pos1->virtual_start = page2 + 2 * EFI_PAGE_SIZE;
+ pos1->num_pages = 1;
+ pos1->attribute = EFI_MEMORY_RUNTIME;
+ ++pos1;
+
+ map_size = (u8 *)pos1 - (u8 *)memory_map;
+
+ return EFI_ST_SUCCESS;
+}
+
+/**
+ * execute() - execute unit test
+ *
+ * SetVirtualAddressMap() is called with the memory map prepared in setup().
+ *
+ * The triggering of the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event is checked via
+ * the call count of the notification function.
+ *
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ efi_status_t ret;
+
+ ret = runtime->set_virtual_address_map(map_size, desc_size,
+ desc_version, memory_map);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVirtualAddressMap failed\n");
+ return EFI_ST_FAILURE;
+ }
+ if (notify_call_count != 1) {
+ efi_st_error("EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE triggered %d times\n",
+ notify_call_count);
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(virtaddrmap) = {
+ .name = "virtual address map",
+ .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
+ .setup = setup,
+ .execute = execute,
+};
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
index fb5e07b..5b5905a 100644
--- a/lib/rsa/rsa-sign.c
+++ b/lib/rsa/rsa-sign.c
@@ -141,6 +141,15 @@
snprintf(key_id, sizeof(key_id),
"pkcs11:object=%s;type=public",
name);
+ } else if (engine_id) {
+ if (keydir)
+ snprintf(key_id, sizeof(key_id),
+ "%s%s",
+ keydir, name);
+ else
+ snprintf(key_id, sizeof(key_id),
+ "%s",
+ name);
} else {
fprintf(stderr, "Engine not supported\n");
return -ENOTSUP;
@@ -252,6 +261,15 @@
snprintf(key_id, sizeof(key_id),
"pkcs11:object=%s;type=private",
name);
+ } else if (engine_id) {
+ if (keydir)
+ snprintf(key_id, sizeof(key_id),
+ "%s%s",
+ keydir, name);
+ else
+ snprintf(key_id, sizeof(key_id),
+ "%s",
+ name);
} else {
fprintf(stderr, "Engine not supported\n");
return -ENOTSUP;
diff --git a/net/Makefile b/net/Makefile
index 6251ff3..826544f 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -16,6 +16,7 @@
obj-$(CONFIG_NET) += eth_legacy.o
endif
obj-$(CONFIG_DM_MDIO) += mdio-uclass.o
+obj-$(CONFIG_DM_MDIO_MUX) += mdio-mux-uclass.o
obj-$(CONFIG_NET) += eth_common.o
obj-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
obj-$(CONFIG_NET) += net.o
diff --git a/net/mdio-mux-uclass.c b/net/mdio-mux-uclass.c
new file mode 100644
index 0000000..e425207
--- /dev/null
+++ b/net/mdio-mux-uclass.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019
+ * Alex Marginean, NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <miiphy.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <dm/lists.h>
+
+#define MDIO_MUX_CHILD_DRV_NAME "mdio-mux-bus-drv"
+
+/**
+ * struct mdio_mux_perdev_priv - Per-device class data for MDIO MUX DM
+ *
+ * @parent_mdio: Parent DM MDIO device, this is called for actual MDIO I/O after
+ * setting up the mux. Typically this is a real MDIO device,
+ * unless there are cascaded muxes.
+ * @selected: Current child bus selection. Defaults to -1
+ */
+struct mdio_mux_perdev_priv {
+ struct udevice *mdio_parent;
+ int selected;
+};
+
+/*
+ * This source file uses three types of devices, as follows:
+ * - mux is the hardware MDIO MUX which selects between the existing child MDIO
+ * buses, this is the device relevant for MDIO MUX class of drivers.
+ * - ch is a child MDIO bus, this is just a representation of a mux selection,
+ * not a real piece of hardware.
+ * - mdio_parent is the actual MDIO bus called to perform reads/writes after
+ * the MUX is configured. Typically this is a real MDIO device, unless there
+ * are cascaded muxes.
+ */
+
+/**
+ * struct mdio_mux_ch_data - Per-device data for child MDIOs
+ *
+ * @sel: Selection value used by the MDIO MUX to access this child MDIO bus
+ */
+struct mdio_mux_ch_data {
+ int sel;
+};
+
+static struct udevice *mmux_get_parent_mdio(struct udevice *mux)
+{
+ struct mdio_mux_perdev_priv *pdata = dev_get_uclass_priv(mux);
+
+ return pdata->mdio_parent;
+}
+
+static struct mdio_ops *mmux_get_mdio_parent_ops(struct udevice *mux)
+{
+ return mdio_get_ops(mmux_get_parent_mdio(mux));
+}
+
+/* call driver select function before performing MDIO r/w */
+static int mmux_change_sel(struct udevice *ch, bool sel)
+{
+ struct udevice *mux = ch->parent;
+ struct mdio_mux_perdev_priv *priv = dev_get_uclass_priv(mux);
+ struct mdio_mux_ops *ops = mdio_mux_get_ops(mux);
+ struct mdio_mux_ch_data *ch_data = dev_get_parent_platdata(ch);
+ int err = 0;
+
+ if (sel) {
+ err = ops->select(mux, priv->selected, ch_data->sel);
+ if (err)
+ return err;
+
+ priv->selected = ch_data->sel;
+ } else {
+ if (ops->deselect) {
+ ops->deselect(mux, ch_data->sel);
+ priv->selected = MDIO_MUX_SELECT_NONE;
+ }
+ }
+
+ return 0;
+}
+
+/* Read wrapper, sets up the mux before issuing a read on parent MDIO bus */
+static int mmux_read(struct udevice *ch, int addr, int devad,
+ int reg)
+{
+ struct udevice *mux = ch->parent;
+ struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
+ struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
+ int err;
+
+ err = mmux_change_sel(ch, true);
+ if (err)
+ return err;
+
+ err = parent_ops->read(parent_mdio, addr, devad, reg);
+ mmux_change_sel(ch, false);
+
+ return err;
+}
+
+/* Write wrapper, sets up the mux before issuing a write on parent MDIO bus */
+static int mmux_write(struct udevice *ch, int addr, int devad,
+ int reg, u16 val)
+{
+ struct udevice *mux = ch->parent;
+ struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
+ struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
+ int err;
+
+ err = mmux_change_sel(ch, true);
+ if (err)
+ return err;
+
+ err = parent_ops->write(parent_mdio, addr, devad, reg, val);
+ mmux_change_sel(ch, false);
+
+ return err;
+}
+
+/* Reset wrapper, sets up the mux before issuing a reset on parent MDIO bus */
+static int mmux_reset(struct udevice *ch)
+{
+ struct udevice *mux = ch->parent;
+ struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
+ struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
+ int err;
+
+ /* reset is optional, if it's not implemented just exit */
+ if (!parent_ops->reset)
+ return 0;
+
+ err = mmux_change_sel(ch, true);
+ if (err)
+ return err;
+
+ err = parent_ops->reset(parent_mdio);
+ mmux_change_sel(ch, false);
+
+ return err;
+}
+
+/* Picks up the mux selection value for each child */
+static int dm_mdio_mux_child_post_bind(struct udevice *ch)
+{
+ struct mdio_mux_ch_data *ch_data = dev_get_parent_platdata(ch);
+
+ ch_data->sel = dev_read_u32_default(ch, "reg", MDIO_MUX_SELECT_NONE);
+
+ if (ch_data->sel == MDIO_MUX_SELECT_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* Explicitly bind child MDIOs after binding the mux */
+static int dm_mdio_mux_post_bind(struct udevice *mux)
+{
+ ofnode ch_node;
+ int err, first_err = 0;
+
+ if (!ofnode_valid(mux->node)) {
+ debug("%s: no mux node found, no child MDIO busses set up\n",
+ __func__);
+ return 0;
+ }
+
+ /*
+ * we're going by Linux bindings so the child nodes do not have
+ * compatible strings. We're going through them here and binding to
+ * them.
+ */
+ dev_for_each_subnode(ch_node, mux) {
+ struct udevice *ch_dev;
+ const char *ch_name;
+
+ ch_name = ofnode_get_name(ch_node);
+
+ err = device_bind_driver_to_node(mux, MDIO_MUX_CHILD_DRV_NAME,
+ ch_name, ch_node, &ch_dev);
+ /* try to bind all, but keep 1st error */
+ if (err && !first_err)
+ first_err = err;
+ }
+
+ return first_err;
+}
+
+/* Get a reference to the parent MDIO bus, it should be bound by now */
+static int dm_mdio_mux_post_probe(struct udevice *mux)
+{
+ struct mdio_mux_perdev_priv *priv = dev_get_uclass_priv(mux);
+ int err;
+
+ priv->selected = MDIO_MUX_SELECT_NONE;
+
+ /* pick up mdio parent from device tree */
+ err = uclass_get_device_by_phandle(UCLASS_MDIO, mux, "mdio-parent-bus",
+ &priv->mdio_parent);
+ if (err) {
+ debug("%s: didn't find mdio-parent-bus\n", __func__);
+ return err;
+ }
+
+ return 0;
+}
+
+const struct mdio_ops mmux_child_mdio_ops = {
+ .read = mmux_read,
+ .write = mmux_write,
+ .reset = mmux_reset,
+};
+
+/* MDIO class driver used for MUX child MDIO buses */
+U_BOOT_DRIVER(mdio_mux_child) = {
+ .name = MDIO_MUX_CHILD_DRV_NAME,
+ .id = UCLASS_MDIO,
+ .ops = &mmux_child_mdio_ops,
+};
+
+UCLASS_DRIVER(mdio_mux) = {
+ .id = UCLASS_MDIO_MUX,
+ .name = "mdio-mux",
+ .child_post_bind = dm_mdio_mux_child_post_bind,
+ .post_bind = dm_mdio_mux_post_bind,
+ .post_probe = dm_mdio_mux_post_probe,
+ .per_device_auto_alloc_size = sizeof(struct mdio_mux_perdev_priv),
+ .per_child_platdata_auto_alloc_size = sizeof(struct mdio_mux_ch_data),
+};
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index 79872ba..e616f72 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -61,7 +61,6 @@
CONFIG_ARM_GIC_BASE_ADDRESS
CONFIG_ARM_PL180_MMCI_BASE
CONFIG_ARM_PL180_MMCI_CLOCK_FREQ
-CONFIG_ARM_THUMB
CONFIG_ARP_TIMEOUT
CONFIG_ASTRO_COFDMDUOS2
CONFIG_ASTRO_TWIN7S2
@@ -1533,6 +1532,7 @@
CONFIG_ROCKCHIP_CHIP_TAG
CONFIG_ROCKCHIP_MAX_INIT_SIZE
CONFIG_ROCKCHIP_SDHCI_MAX_FREQ
+CONFIG_ROCKCHIP_STIMER_BASE
CONFIG_ROM_STUBS
CONFIG_ROOTFS_OFFSET
CONFIG_ROOTPATH
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 3cb6259..516cf1d 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -212,7 +212,7 @@
my $type_constant = '\b``([^\`]+)``\b';
my $type_constant2 = '\%([-_\w]+)';
my $type_func = '(\w+)\(\)';
-my $type_param = '\@(\w*(\.\w+)*(\.\.\.)?)';
+my $type_param = '\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)';
my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params
my $type_env = '(\$\w+)';
my $type_enum = '\&(enum\s*([_\w]+))';
@@ -1062,7 +1062,7 @@
my $x = shift;
my $file = shift;
- if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
+ if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
my $decl_type = $1;
$declaration_name = $2;
my $members = $3;
@@ -1073,8 +1073,9 @@
# strip comments:
$members =~ s/\/\*.*?\*\///gos;
# strip attributes
- $members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
- $members =~ s/__aligned\s*\([^;]*\)//gos;
+ $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)//gi;
+ $members =~ s/\s*__aligned\s*\([^;]*\)//gos;
+ $members =~ s/\s*__packed\s*//gos;
$members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos;
# replace DECLARE_BITMAP
$members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
@@ -1148,20 +1149,20 @@
}
}
}
- $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)}([^\{\}\;]*)\;/$newmember/;
+ $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/;
}
# Ignore other nested elements, like enums
- $members =~ s/({[^\{\}]*})//g;
+ $members =~ s/(\{[^\{\}]*\})//g;
create_parameterlist($members, ';', $file, $declaration_name);
check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual);
# Adjust declaration for better display
- $declaration =~ s/([{;])/$1\n/g;
- $declaration =~ s/}\s+;/};/g;
+ $declaration =~ s/([\{;])/$1\n/g;
+ $declaration =~ s/\}\s+;/};/g;
# Better handle inlined enums
- do {} while ($declaration =~ s/(enum\s+{[^}]+),([^\n])/$1,\n$2/);
+ do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/);
my @def_args = split /\n/, $declaration;
my $level = 1;
@@ -1171,12 +1172,12 @@
$clause =~ s/\s+$//;
$clause =~ s/\s+/ /;
next if (!$clause);
- $level-- if ($clause =~ m/(})/ && $level > 1);
+ $level-- if ($clause =~ m/(\})/ && $level > 1);
if (!($clause =~ m/^\s*#/)) {
$declaration .= "\t" x $level;
}
$declaration .= "\t" . $clause . "\n";
- $level++ if ($clause =~ m/({)/ && !($clause =~m/}/));
+ $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/));
}
output_declaration($declaration_name,
'struct',
@@ -1244,7 +1245,7 @@
# strip #define macros inside enums
$x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos;
- if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
+ if ($x =~ /enum\s+(\w+)\s*\{(.*)\}/) {
$declaration_name = $1;
my $members = $2;
my %_members;
@@ -1381,7 +1382,7 @@
} elsif ($arg =~ m/\(.+\)\s*\(/) {
# pointer-to-function
$arg =~ tr/#/,/;
- $arg =~ m/[^\(]+\(\*?\s*([\w\.]*)\s*\)/;
+ $arg =~ m/[^\(]+\([\w\s]*\*?\s*([\w\.]*)\s*\)/;
$param = $1;
$type = $arg;
$type =~ s/([^\(]+\(\*?)\s*$param/$1/;
@@ -1473,7 +1474,7 @@
if (!defined $parameterdescs{$param} && $param !~ /^#/) {
$parameterdescs{$param} = $undescribed;
- if (show_warnings($type, $declaration_name)) {
+ if (show_warnings($type, $declaration_name) && $param !~ /\./) {
print STDERR
"${file}:$.: warning: Function parameter or member '$param' not described in '$declaration_name'\n";
++$warnings;
@@ -1785,7 +1786,7 @@
}
while (1) {
- if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
+ if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) {
if( length $prototype ) {
$prototype .= " "
}
@@ -1904,13 +1905,13 @@
++$warnings;
}
- if ($identifier =~ m/^struct/) {
+ if ($identifier =~ m/^struct\b/) {
$decl_type = 'struct';
- } elsif ($identifier =~ m/^union/) {
+ } elsif ($identifier =~ m/^union\b/) {
$decl_type = 'union';
- } elsif ($identifier =~ m/^enum/) {
+ } elsif ($identifier =~ m/^enum\b/) {
$decl_type = 'enum';
- } elsif ($identifier =~ m/^typedef/) {
+ } elsif ($identifier =~ m/^typedef\b/) {
$decl_type = 'typedef';
} else {
$decl_type = 'function';
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 6a36cc0..7b4dd6e 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -63,4 +63,5 @@
obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o
obj-$(CONFIG_DMA) += dma.o
obj-$(CONFIG_DM_MDIO) += mdio.o
+obj-$(CONFIG_DM_MDIO_MUX) += mdio_mux.o
endif
diff --git a/test/dm/mdio.c b/test/dm/mdio.c
index 5b66255..dc229ae 100644
--- a/test/dm/mdio.c
+++ b/test/dm/mdio.c
@@ -13,6 +13,9 @@
/* macros copied over from mdio_sandbox.c */
#define SANDBOX_PHY_ADDR 5
+#define SANDBOX_PHY_REG_CNT 2
+
+/* test using 1st register, 0 */
#define SANDBOX_PHY_REG 0
#define TEST_REG_VALUE 0xabcd
diff --git a/test/dm/mdio_mux.c b/test/dm/mdio_mux.c
new file mode 100644
index 0000000..f962e09
--- /dev/null
+++ b/test/dm/mdio_mux.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019
+ * Alex Marginean, NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/test.h>
+#include <misc.h>
+#include <test/ut.h>
+#include <miiphy.h>
+
+/* macros copied over from mdio_sandbox.c */
+#define SANDBOX_PHY_ADDR 5
+#define SANDBOX_PHY_REG_CNT 2
+
+#define TEST_REG_VALUE 0xabcd
+
+static int dm_test_mdio_mux(struct unit_test_state *uts)
+{
+ struct uclass *uc;
+ struct udevice *mux;
+ struct udevice *mdio_ch0, *mdio_ch1, *mdio;
+ struct mdio_ops *ops, *ops_parent;
+ struct mdio_mux_ops *mmops;
+ u16 reg;
+
+ ut_assertok(uclass_get(UCLASS_MDIO_MUX, &uc));
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_MDIO_MUX, "mdio-mux-test",
+ &mux));
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_MDIO, "mdio-ch-test@0",
+ &mdio_ch0));
+ ut_assertok(uclass_get_device_by_name(UCLASS_MDIO, "mdio-ch-test@1",
+ &mdio_ch1));
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_MDIO, "mdio-test", &mdio));
+
+ ops = mdio_get_ops(mdio_ch0);
+ ut_assertnonnull(ops);
+ ut_assertnonnull(ops->read);
+ ut_assertnonnull(ops->write);
+
+ mmops = mdio_mux_get_ops(mux);
+ ut_assertnonnull(mmops);
+ ut_assertnonnull(mmops->select);
+
+ ops_parent = mdio_get_ops(mdio);
+ ut_assertnonnull(ops);
+ ut_assertnonnull(ops->read);
+
+ /*
+ * mux driver sets last register on the emulated PHY whenever a group
+ * is selected to the selection #. Just reading that register from
+ * either of the child buses should return the id of the child bus
+ */
+ reg = ops->read(mdio_ch0, SANDBOX_PHY_ADDR, MDIO_DEVAD_NONE,
+ SANDBOX_PHY_REG_CNT - 1);
+ ut_asserteq(reg, 0);
+
+ reg = ops->read(mdio_ch1, SANDBOX_PHY_ADDR, MDIO_DEVAD_NONE,
+ SANDBOX_PHY_REG_CNT - 1);
+ ut_asserteq(reg, 1);
+
+ mmops->select(mux, MDIO_MUX_SELECT_NONE, 5);
+ reg = ops_parent->read(mdio, SANDBOX_PHY_ADDR, MDIO_DEVAD_NONE,
+ SANDBOX_PHY_REG_CNT - 1);
+ ut_asserteq(reg, 5);
+
+ mmops->deselect(mux, 5);
+ reg = ops_parent->read(mdio, SANDBOX_PHY_ADDR, MDIO_DEVAD_NONE,
+ SANDBOX_PHY_REG_CNT - 1);
+ ut_asserteq(reg, (u16)MDIO_MUX_SELECT_NONE);
+
+ return 0;
+}
+
+DM_TEST(dm_test_mdio_mux, DM_TESTF_SCAN_FDT);
diff --git a/test/dm/remoteproc.c b/test/dm/remoteproc.c
index 3975c67..a2c4be7 100644
--- a/test/dm/remoteproc.c
+++ b/test/dm/remoteproc.c
@@ -5,8 +5,10 @@
*/
#include <common.h>
#include <dm.h>
+#include <elf.h>
#include <errno.h>
#include <remoteproc.h>
+#include <asm/io.h>
#include <dm/test.h>
#include <test/ut.h>
/**
@@ -65,3 +67,123 @@
return 0;
}
DM_TEST(dm_test_remoteproc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+#define DEVICE_TO_PHYSICAL_OFFSET 0x1000
+/**
+ * dm_test_remoteproc_elf() - test the ELF operations
+ * @uts: unit test state
+ *
+ * Return: 0 if test passed, else error
+ */
+static int dm_test_remoteproc_elf(struct unit_test_state *uts)
+{
+ u8 valid_elf32[] = {
+ /* @0x00 - ELF HEADER - */
+ /* ELF magic */
+ 0x7f, 0x45, 0x4c, 0x46,
+ /* 32 Bits */
+ 0x01,
+ /* Endianness */
+#ifdef __LITTLE_ENDIAN
+ 0x01,
+#else
+ 0x02,
+#endif
+ /* Version */
+ 0x01,
+ /* Padding */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* Type : executable */
+ 0x02, 0x00,
+ /* Machine: ARM */
+ 0x28, 0x00,
+ /* Version */
+ 0x01, 0x00, 0x00, 0x00,
+ /* Entry */
+ 0x00, 0x00, 0x00, 0x08,
+ /* phoff (program header offset @ 0x40)*/
+ 0x40, 0x00, 0x00, 0x00,
+ /* shoff (section header offset : none) */
+ 0x00, 0x00, 0x00, 0x00,
+ /* flags */
+ 0x00, 0x00, 0x00, 0x00,
+ /* ehsize (elf header size = 0x34) */
+ 0x34, 0x00,
+ /* phentsize (program header size = 0x20) */
+ 0x20, 0x00,
+ /* phnum (program header number : 1) */
+ 0x01, 0x00,
+ /* shentsize (section heade size : none) */
+ 0x00, 0x00,
+ /* shnum (section header number: none) */
+ 0x00, 0x00,
+ /* shstrndx (section header name section index: none) */
+ 0x00, 0x00,
+ /* padding */
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* @0x40 - PROGRAM HEADER TABLE - */
+ /* type : PT_LOAD */
+ 0x01, 0x00, 0x00, 0x00,
+ /* offset */
+ 0x00, 0x00, 0x00, 0x00,
+ /* vaddr */
+ 0x00, 0x00, 0x00, 0x00,
+ /* paddr : physical address */
+ 0x00, 0x00, 0x00, 0x00,
+ /* filesz : 0x20 bytes (program header size) */
+ 0x20, 0x00, 0x00, 0x00,
+ /* memsz = filesz */
+ 0x20, 0x00, 0x00, 0x00,
+ /* flags : readable and exectuable */
+ 0x05, 0x00, 0x00, 0x00,
+ /* padding */
+ 0x00, 0x00, 0x00, 0x00,
+ };
+ unsigned int size = ARRAY_SIZE(valid_elf32);
+ struct udevice *dev;
+ phys_addr_t loaded_firmware_paddr;
+ void *loaded_firmware;
+ u32 loaded_firmware_size;
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)valid_elf32;
+ Elf32_Phdr *phdr = (Elf32_Phdr *)(valid_elf32 + ehdr->e_phoff);
+
+ ut_assertok(uclass_get_device(UCLASS_REMOTEPROC, 0, &dev));
+
+ /*
+ * In its Program Header Table, let the firmware specifies to be loaded
+ * at SDRAM_BASE *device* address (p_paddr field).
+ * Its size is defined by the p_filesz field.
+ */
+ phdr->p_paddr = CONFIG_SYS_SDRAM_BASE;
+ loaded_firmware_size = phdr->p_filesz;
+
+ /*
+ * This *device* address is converted to a *physical* address by the
+ * device_to_virt() operation of sandbox_test_rproc which returns
+ * DeviceAddress + DEVICE_TO_PHYSICAL_OFFSET.
+ * This is where we expect to get the firmware loaded.
+ */
+ loaded_firmware_paddr = phdr->p_paddr + DEVICE_TO_PHYSICAL_OFFSET;
+ loaded_firmware = map_physmem(loaded_firmware_paddr,
+ loaded_firmware_size, MAP_NOCACHE);
+ ut_assertnonnull(loaded_firmware);
+ memset(loaded_firmware, 0, loaded_firmware_size);
+
+ /* Verify valid ELF format */
+ ut_assertok(rproc_elf32_sanity_check((ulong)valid_elf32, size));
+
+ /* Load firmware in loaded_firmware, and verify it */
+ ut_assertok(rproc_elf32_load_image(dev, (unsigned long)valid_elf32));
+ ut_assertok(memcmp(loaded_firmware, valid_elf32, loaded_firmware_size));
+ unmap_physmem(loaded_firmware, MAP_NOCACHE);
+
+ /* Invalid ELF Magic */
+ valid_elf32[0] = 0;
+ ut_asserteq(-EPROTONOSUPPORT,
+ rproc_elf32_sanity_check((ulong)valid_elf32, size));
+
+ return 0;
+}
+DM_TEST(dm_test_remoteproc_elf, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index be16c99..ad85916 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -490,6 +490,7 @@
static int dm_test_fdt_translation(struct unit_test_state *uts)
{
struct udevice *dev;
+ fdt32_t dma_addr[2];
/* Some simple translations */
ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, true, &dev));
@@ -509,6 +510,17 @@
ut_asserteq_str("dev@42", dev->name);
ut_asserteq(0x42, dev_read_addr(dev));
+ /* dma address translation */
+ ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, true, &dev));
+ dma_addr[0] = cpu_to_be32(0);
+ dma_addr[1] = cpu_to_be32(0);
+ ut_asserteq(0x10000000, dev_translate_dma_address(dev, dma_addr));
+
+ ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 1, true, &dev));
+ dma_addr[0] = cpu_to_be32(1);
+ dma_addr[1] = cpu_to_be32(0x100);
+ ut_asserteq(0x20000000, dev_translate_dma_address(dev, dma_addr));
+
return 0;
}
DM_TEST(dm_test_fdt_translation, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/py/tests/test_android/test_ab.py b/test/py/tests/test_android/test_ab.py
new file mode 100644
index 0000000..c79cb07
--- /dev/null
+++ b/test/py/tests/test_android/test_ab.py
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2018 Texas Instruments, <www.ti.com>
+
+# Test A/B update commands.
+
+import os
+import pytest
+import u_boot_utils
+
+class ABTestDiskImage(object):
+ """Disk Image used by the A/B tests."""
+
+ def __init__(self, u_boot_console):
+ """Initialize a new ABTestDiskImage object.
+
+ Args:
+ u_boot_console: A U-Boot console.
+
+ Returns:
+ Nothing.
+ """
+
+ filename = 'test_ab_disk_image.bin'
+
+ persistent = u_boot_console.config.persistent_data_dir + '/' + filename
+ self.path = u_boot_console.config.result_dir + '/' + filename
+
+ with u_boot_utils.persistent_file_helper(u_boot_console.log, persistent):
+ if os.path.exists(persistent):
+ u_boot_console.log.action('Disk image file ' + persistent +
+ ' already exists')
+ else:
+ u_boot_console.log.action('Generating ' + persistent)
+ fd = os.open(persistent, os.O_RDWR | os.O_CREAT)
+ os.ftruncate(fd, 524288)
+ os.close(fd)
+ cmd = ('sgdisk', persistent)
+ u_boot_utils.run_and_log(u_boot_console, cmd)
+
+ cmd = ('sgdisk', '--new=1:64:512', '--change-name=1:misc',
+ persistent)
+ u_boot_utils.run_and_log(u_boot_console, cmd)
+ cmd = ('sgdisk', '--load-backup=' + persistent)
+ u_boot_utils.run_and_log(u_boot_console, cmd)
+
+ cmd = ('cp', persistent, self.path)
+ u_boot_utils.run_and_log(u_boot_console, cmd)
+
+di = None
+@pytest.fixture(scope='function')
+def ab_disk_image(u_boot_console):
+ global di
+ if not di:
+ di = ABTestDiskImage(u_boot_console)
+ return di
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('android_ab')
+@pytest.mark.buildconfigspec('cmd_ab_select')
+@pytest.mark.requiredtool('sgdisk')
+def test_ab(ab_disk_image, u_boot_console):
+ """Test the 'ab_select' command."""
+
+ u_boot_console.run_command('host bind 0 ' + ab_disk_image.path)
+
+ output = u_boot_console.run_command('ab_select slot_name host 0#misc')
+ assert 're-initializing A/B metadata' in output
+ assert 'Attempting slot a, tries remaining 7' in output
+ output = u_boot_console.run_command('printenv slot_name')
+ assert 'slot_name=a' in output
+
+ output = u_boot_console.run_command('ab_select slot_name host 0:1')
+ assert 'Attempting slot b, tries remaining 7' in output
+ output = u_boot_console.run_command('printenv slot_name')
+ assert 'slot_name=b' in output
diff --git a/test/py/tests/test_avb.py b/test/py/tests/test_avb.py
index 2bb75ed..8132423 100644
--- a/test/py/tests/test_avb.py
+++ b/test/py/tests/test_avb.py
@@ -8,7 +8,7 @@
This tests Android Verified Boot 2.0 support in U-boot:
For additional details about how to build proper vbmeta partition
-check doc/README.avb2
+check doc/android/avb2.txt
For configuration verification:
- Corrupt boot partition and check for failure
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py
index c8edb33..229d7eb 100644
--- a/test/py/tests/test_gpt.py
+++ b/test/py/tests/test_gpt.py
@@ -40,16 +40,19 @@
fd = os.open(persistent, os.O_RDWR | os.O_CREAT)
os.ftruncate(fd, 4194304)
os.close(fd)
- cmd = ('sgdisk', '-U', '375a56f7-d6c9-4e81-b5f0-09d41ca89efe',
+ cmd = ('sgdisk',
+ '--disk-guid=375a56f7-d6c9-4e81-b5f0-09d41ca89efe',
persistent)
u_boot_utils.run_and_log(u_boot_console, cmd)
# part1 offset 1MB size 1MB
- cmd = ('sgdisk', '--new=1:2048:4095', '-c 1:part1', persistent)
+ cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1',
+ persistent)
# part2 offset 2MB size 1.5MB
u_boot_utils.run_and_log(u_boot_console, cmd)
- cmd = ('sgdisk', '--new=2:4096:7167', '-c 2:part2', persistent)
+ cmd = ('sgdisk', '--new=2:4096:7167', '--change-name=2:part2',
+ persistent)
u_boot_utils.run_and_log(u_boot_console, cmd)
- cmd = ('sgdisk', '-l', persistent)
+ cmd = ('sgdisk', '--load-backup=' + persistent)
u_boot_utils.run_and_log(u_boot_console, cmd)
cmd = ('cp', persistent, self.path)
diff --git a/test/run b/test/run
index 55a6649..d635622 100755
--- a/test/run
+++ b/test/run
@@ -33,12 +33,14 @@
-k test_ut
# Set up a path to dtc (device-tree compiler) and libfdt.py, a library it
-# provides and which is built by the sandbox_spl config.
+# provides and which is built by the sandbox_spl config. Also set up the path
+# to tools build by the build.
DTC_DIR=build-sandbox_spl/scripts/dtc
export PYTHONPATH=${DTC_DIR}/pylibfdt
export DTC=${DTC_DIR}/dtc
+TOOLS_DIR=build-sandbox_spl/tools
-run_test "binman" ./tools/binman/binman -t
+run_test "binman" ./tools/binman/binman --toolpath ${TOOLS_DIR} test
run_test "patman" ./tools/patman/patman --test
[ "$1" == "quick" ] && skip=--skip-net-tests
@@ -49,7 +51,8 @@
# This needs you to set up Python test coverage tools.
# To enable Python test coverage on Debian-type distributions (e.g. Ubuntu):
# $ sudo apt-get install python-pytest python-coverage
-run_test "binman code coverage" ./tools/binman/binman -T
+export PATH=$PATH:${TOOLS_DIR}
+run_test "binman code coverage" ./tools/binman/binman test -T
run_test "dtoc code coverage" ./tools/dtoc/dtoc -T
run_test "fdt code coverage" ./tools/dtoc/test_fdt -T
diff --git a/test/unicode_ut.c b/test/unicode_ut.c
index 8e1efe6..1ccd36e 100644
--- a/test/unicode_ut.c
+++ b/test/unicode_ut.c
@@ -50,6 +50,16 @@
static const char j2[] = {0x6a, 0x32, 0xc3, 0xc3, 0x6c, 0x00};
static const char j3[] = {0x6a, 0x33, 0xf0, 0x90, 0xf0, 0x00};
+static int unicode_test_u16_strlen(struct unit_test_state *uts)
+{
+ ut_asserteq(6, u16_strlen(c1));
+ ut_asserteq(8, u16_strlen(c2));
+ ut_asserteq(3, u16_strlen(c3));
+ ut_asserteq(6, u16_strlen(c4));
+ return 0;
+}
+UNICODE_TEST(unicode_test_u16_strlen);
+
static int unicode_test_u16_strdup(struct unit_test_state *uts)
{
u16 *copy = u16_strdup(c4);
diff --git a/tools/Makefile b/tools/Makefile
index 33e90a8..87d81a3 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -175,6 +175,9 @@
ifdtool-objs := $(LIBFDT_OBJS) ifdtool.o
hostprogs-$(CONFIG_X86) += ifdtool
+ifwitool-objs := ifwitool.o
+hostprogs-$(CONFIG_X86)$(CONFIG_SANDBOX) += ifwitool
+
hostprogs-$(CONFIG_MX23) += mxsboot
hostprogs-$(CONFIG_MX28) += mxsboot
HOSTCFLAGS_mxsboot.o := -pedantic
diff --git a/tools/binman/README b/tools/binman/README
index ac193f1..756c6a0 100644
--- a/tools/binman/README
+++ b/tools/binman/README
@@ -36,10 +36,9 @@
they are included, by adding a Python plug-in. The device tree is available
to U-Boot at run-time so that the images can be interpreted.
-Binman does not yet update the device tree with the final location of
-everything when it is done. A simple C structure could be generated for
-constrained environments like SPL (using dtoc) but this is also not
-implemented.
+Binman can update the device tree with the final location of everything when it
+is done. Entry positions can be provided to U-Boot SPL as run-time symbols,
+avoiding device-tree code overhead.
Binman can also support incorporating filesystems in the image if required.
For example x86 platforms may use CBFS in some cases.
@@ -181,9 +180,14 @@
Running binman
--------------
+First install prerequisites, e.g.
+
+ sudo apt-get install python-pyelftools python3-pyelftools lzma-alone \
+ liblz4-tool
+
Type:
- binman -b <board_name>
+ binman build -b <board_name>
to build an image for a board. The board name is the same name used when
configuring U-Boot (e.g. for sandbox_defconfig the board name is 'sandbox').
@@ -191,7 +195,7 @@
Or you can specify this explicitly:
- binman -I <build_path>
+ binman build -I <build_path>
where <build_path> is the build directory containing the output of the U-Boot
build.
@@ -335,6 +339,10 @@
limited by the size of the image/section and the position of the next
entry.
+compress:
+ Sets the compression algortihm to use (for blobs only). See the entry
+ documentation for details.
+
The attributes supported for images and sections are described below. Several
are similar to those for entries.
@@ -479,8 +487,93 @@
For details on the various entry types supported by binman and how to use them,
see README.entries. This is generated from the source code using:
+ binman entry-docs >tools/binman/README.entries
+
+
+Listing images
+--------------
+
+It is possible to list the entries in an existing firmware image created by
+binman, provided that there is an 'fdtmap' entry in the image. For example:
+
+ $ binman ls -i image.bin
+ Name Image-pos Size Entry-type Offset Uncomp-size
+ ----------------------------------------------------------------------
+ main-section c00 section 0
+ u-boot 0 4 u-boot 0
+ section 5fc section 4
+ cbfs 100 400 cbfs 0
+ u-boot 138 4 u-boot 38
+ u-boot-dtb 180 108 u-boot-dtb 80 3b5
+ u-boot-dtb 500 1ff u-boot-dtb 400 3b5
+ fdtmap 6fc 381 fdtmap 6fc
+ image-header bf8 8 image-header bf8
+
+This shows the hierarchy of the image, the position, size and type of each
+entry, the offset of each entry within its parent and the uncompressed size if
+the entry is compressed.
+
- binman -E >tools/binman/README.entries
+It is also possible to list just some files in an image, e.g.
+ $ binman ls -i image.bin section/cbfs
+ Name Image-pos Size Entry-type Offset Uncomp-size
+ --------------------------------------------------------------------
+ cbfs 100 400 cbfs 0
+ u-boot 138 4 u-boot 38
+ u-boot-dtb 180 108 u-boot-dtb 80 3b5
+
+or with wildcards:
+
+ $ binman ls -i image.bin "*cb*" "*head*"
+ Name Image-pos Size Entry-type Offset Uncomp-size
+ ----------------------------------------------------------------------
+ cbfs 100 400 cbfs 0
+ u-boot 138 4 u-boot 38
+ u-boot-dtb 180 108 u-boot-dtb 80 3b5
+ image-header bf8 8 image-header bf8
+
+
+Extracting files from images
+----------------------------
+
+You can extract files from an existing firmware image created by binman,
+provided that there is an 'fdtmap' entry in the image. For example:
+
+ $ binman extract -i image.bin section/cbfs/u-boot
+
+which will write the uncompressed contents of that entry to the file 'u-boot' in
+the current directory. You can also extract to a particular file, in this case
+u-boot.bin:
+
+ $ binman extract -i image.bin section/cbfs/u-boot -f u-boot.bin
+
+It is possible to extract all files into a destination directory, which will
+put files in subdirectories matching the entry hierarchy:
+
+ $ binman extract -i image.bin -O outdir
+
+or just a selection:
+
+ $ binman extract -i image.bin "*u-boot*" -O outdir
+
+
+Logging
+-------
+
+Binman normally operates silently unless there is an error, in which case it
+just displays the error. The -D/--debug option can be used to create a full
+backtrace when errors occur.
+
+Internally binman logs some output while it is running. This can be displayed
+by increasing the -v/--verbosity from the default of 1:
+
+ 0: silent
+ 1: warnings only
+ 2: notices (important messages)
+ 3: info about major operations
+ 4: detailed information about each operation
+ 5: debug (all output)
+
Hashing Entries
---------------
@@ -558,7 +651,8 @@
The default implementatoin does nothing. This can be overriden to adjust the
contents of an entry in some way. For example, it would be possible to create
an entry containing a hash of the contents of some other entries. At this
-stage the offset and size of entries should not be adjusted.
+stage the offset and size of entries should not be adjusted unless absolutely
+necessary, since it requires a repack (going back to PackEntries()).
10. WriteSymbols() - write the value of symbols into the U-Boot SPL binary.
See 'Access to binman entry offsets at run time' below for a description of
@@ -634,20 +728,27 @@
the device tree. These can be used by U-Boot at run-time to find the location
of each entry.
+Alternatively, an FDT map entry can be used to add a special FDT containing
+just the information about the image. This is preceded by a magic string so can
+be located anywhere in the image. An image header (typically at the start or end
+of the image) can be used to point to the FDT map. See fdtmap and image-header
+entries for more information.
+
Compression
-----------
Binman support compression for 'blob' entries (those of type 'blob' and
-derivatives). To enable this for an entry, add a 'compression' property:
+derivatives). To enable this for an entry, add a 'compress' property:
blob {
filename = "datafile";
- compression = "lz4";
+ compress = "lz4";
};
The entry will then contain the compressed data, using the 'lz4' compression
-algorithm. Currently this is the only one that is supported.
+algorithm. Currently this is the only one that is supported. The uncompressed
+size is written to the node in an 'uncomp-size' property, if -u is used.
@@ -691,15 +792,25 @@
typically for filenames.
+External tools
+--------------
+
+Binman can make use of external command-line tools to handle processing of
+entry contents or to generate entry contents. These tools are executed using
+the 'tools' module's Run() method. The tools generally must exist on the PATH,
+but the --toolpath option can be used to specify additional search paths to
+use. This option can be specified multiple times to add more than one path.
+
+
Code coverage
-------------
Binman is a critical tool and is designed to be very testable. Entry
-implementations target 100% test coverage. Run 'binman -T' to check this.
+implementations target 100% test coverage. Run 'binman test -T' to check this.
To enable Python test coverage on Debian-type distributions (e.g. Ubuntu):
- $ sudo apt-get install python-coverage python-pytest
+ $ sudo apt-get install python-coverage python3-coverage python-pytest
Concurrent tests
@@ -716,6 +827,14 @@
being used (-T) since they are incompatible.
+Debugging tests
+---------------
+
+Sometimes when debugging tests it is useful to keep the input and output
+directories so they can be examined later. Use -X or --test-preserve-dirs for
+this.
+
+
Advanced Features / Technical docs
----------------------------------
@@ -788,13 +907,12 @@
- Use of-platdata to make the information available to code that is unable
to use device tree (such as a very small SPL image)
- Allow easy building of images by specifying just the board name
-- Produce a full Python binding for libfdt (for upstream). This is nearing
- completion but some work remains
-- Add an option to decode an image into the constituent binaries
- Support building an image for a board (-b) more completely, with a
configurable build directory
-- Consider making binman work with buildman, although if it is used in the
- Makefile, this will be automatic
+- Support updating binaries in an image (with no size change / repacking)
+- Support updating binaries in an image (with repacking)
+- Support adding FITs to an image
+- Support for ARM Trusted Firmware (ATF)
--
Simon Glass <sjg@chromium.org>
diff --git a/tools/binman/README.entries b/tools/binman/README.entries
index 357946d..7ce88ee 100644
--- a/tools/binman/README.entries
+++ b/tools/binman/README.entries
@@ -60,6 +60,158 @@
+Entry: cbfs: Entry containing a Coreboot Filesystem (CBFS)
+----------------------------------------------------------
+
+A CBFS provides a way to group files into a group. It has a simple directory
+structure and allows the position of individual files to be set, since it is
+designed to support execute-in-place in an x86 SPI-flash device. Where XIP
+is not used, it supports compression and storing ELF files.
+
+CBFS is used by coreboot as its way of orgnanising SPI-flash contents.
+
+The contents of the CBFS are defined by subnodes of the cbfs entry, e.g.:
+
+ cbfs {
+ size = <0x100000>;
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ };
+ };
+
+This creates a CBFS 1MB in size two files in it: u-boot.bin and u-boot.dtb.
+Note that the size is required since binman does not support calculating it.
+The contents of each entry is just what binman would normally provide if it
+were not a CBFS node. A blob type can be used to import arbitrary files as
+with the second subnode below:
+
+ cbfs {
+ size = <0x100000>;
+ u-boot {
+ cbfs-name = "BOOT";
+ cbfs-type = "raw";
+ };
+
+ dtb {
+ type = "blob";
+ filename = "u-boot.dtb";
+ cbfs-type = "raw";
+ cbfs-compress = "lz4";
+ cbfs-offset = <0x100000>;
+ };
+ };
+
+This creates a CBFS 1MB in size with u-boot.bin (named "BOOT") and
+u-boot.dtb (named "dtb") and compressed with the lz4 algorithm.
+
+
+Properties supported in the top-level CBFS node:
+
+cbfs-arch:
+ Defaults to "x86", but you can specify the architecture if needed.
+
+
+Properties supported in the CBFS entry subnodes:
+
+cbfs-name:
+ This is the name of the file created in CBFS. It defaults to the entry
+ name (which is the node name), but you can override it with this
+ property.
+
+cbfs-type:
+ This is the CBFS file type. The following are supported:
+
+ raw:
+ This is a 'raw' file, although compression is supported. It can be
+ used to store any file in CBFS.
+
+ stage:
+ This is an ELF file that has been loaded (i.e. mapped to memory), so
+ appears in the CBFS as a flat binary. The input file must be an ELF
+ image, for example this puts "u-boot" (the ELF image) into a 'stage'
+ entry:
+
+ cbfs {
+ size = <0x100000>;
+ u-boot-elf {
+ cbfs-name = "BOOT";
+ cbfs-type = "stage";
+ };
+ };
+
+ You can use your own ELF file with something like:
+
+ cbfs {
+ size = <0x100000>;
+ something {
+ type = "blob";
+ filename = "cbfs-stage.elf";
+ cbfs-type = "stage";
+ };
+ };
+
+ As mentioned, the file is converted to a flat binary, so it is
+ equivalent to adding "u-boot.bin", for example, but with the load and
+ start addresses specified by the ELF. At present there is no option
+ to add a flat binary with a load/start address, similar to the
+ 'add-flat-binary' option in cbfstool.
+
+cbfs-offset:
+ This is the offset of the file's data within the CBFS. It is used to
+ specify where the file should be placed in cases where a fixed position
+ is needed. Typical uses are for code which is not relocatable and must
+ execute in-place from a particular address. This works because SPI flash
+ is generally mapped into memory on x86 devices. The file header is
+ placed before this offset so that the data start lines up exactly with
+ the chosen offset. If this property is not provided, then the file is
+ placed in the next available spot.
+
+The current implementation supports only a subset of CBFS features. It does
+not support other file types (e.g. payload), adding multiple files (like the
+'files' entry with a pattern supported by binman), putting files at a
+particular offset in the CBFS and a few other things.
+
+Of course binman can create images containing multiple CBFSs, simply by
+defining these in the binman config:
+
+
+ binman {
+ size = <0x800000>;
+ cbfs {
+ offset = <0x100000>;
+ size = <0x100000>;
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ };
+ };
+
+ cbfs2 {
+ offset = <0x700000>;
+ size = <0x100000>;
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ };
+ image {
+ type = "blob";
+ filename = "image.jpg";
+ };
+ };
+ };
+
+This creates an 8MB image with two CBFSs, one at offset 1MB, one at 7MB,
+both of size 1MB.
+
+
+
Entry: cros-ec-rw: A blob entry which contains a Chromium OS read-write EC image
--------------------------------------------------------------------------------
@@ -69,7 +221,45 @@
This entry holds a Chromium OS EC (embedded controller) image, for use in
updating the EC on startup via software sync.
+
+
+Entry: fdtmap: An entry which contains an FDT map
+-------------------------------------------------
+
+Properties / Entry arguments:
+ None
+
+An FDT map is just a header followed by an FDT containing a list of all the
+entries in the image.
+
+The header is the string _FDTMAP_ followed by 8 unused bytes.
+When used, this entry will be populated with an FDT map which reflects the
+entries in the current image. Hierarchy is preserved, and all offsets and
+sizes are included.
+
+Note that the -u option must be provided to ensure that binman updates the
+FDT with the position of each entry.
+
+Example output for a simple image with U-Boot and an FDT map:
+
+/ {
+ size = <0x00000112>;
+ image-pos = <0x00000000>;
+ offset = <0x00000000>;
+ u-boot {
+ size = <0x00000004>;
+ image-pos = <0x00000000>;
+ offset = <0x00000000>;
+ };
+ fdtmap {
+ size = <0x0000010e>;
+ image-pos = <0x00000004>;
+ offset = <0x00000004>;
+ };
+};
+
+
Entry: files: Entry containing a set of files
---------------------------------------------
@@ -141,6 +331,25 @@
+Entry: image-header: An entry which contains a pointer to the FDT map
+---------------------------------------------------------------------
+
+Properties / Entry arguments:
+ location: Location of header ("start" or "end" of image). This is
+ optional. If omitted then the entry must have an offset property.
+
+This adds an 8-byte entry to the start or end of the image, pointing to the
+location of the FDT map. The format is a magic number followed by an offset
+from the start or end of the image, in twos-compliment format.
+
+This entry must be in the top-level part of the image.
+
+NOTE: If the location is at the start/end, you will probably need to specify
+sort-by-offset for the image, unless you actually put the image header
+first/last in the entry list.
+
+
+
Entry: intel-cmc: Entry containing an Intel Chipset Micro Code (CMC) file
-------------------------------------------------------------------------
@@ -192,6 +401,34 @@
+Entry: intel-ifwi: Entry containing an Intel Integrated Firmware Image (IFWI) file
+----------------------------------------------------------------------------------
+
+Properties / Entry arguments:
+ - filename: Filename of file to read into entry. This is either the
+ IFWI file itself, or a file that can be converted into one using a
+ tool
+ - convert-fit: If present this indicates that the ifwitool should be
+ used to convert the provided file into a IFWI.
+
+This file contains code and data used by the SoC that is required to make
+it work. It includes U-Boot TPL, microcode, things related to the CSE
+(Converged Security Engine, the microcontroller that loads all the firmware)
+and other items beyond the wit of man.
+
+A typical filename is 'ifwi.bin' for an IFWI file, or 'fitimage.bin' for a
+file that will be converted to an IFWI.
+
+The position of this entry is generally set by the intel-descriptor entry.
+
+The contents of the IFWI are specified by the subnodes of the IFWI node.
+Each subnode describes an entry which is placed into the IFWFI with a given
+sub-partition (and optional entry name).
+
+See README.x86 for information about x86 binary blobs.
+
+
+
Entry: intel-me: Entry containing an Intel Management Engine (ME) file
----------------------------------------------------------------------
@@ -206,6 +443,8 @@
A typical filename is 'me.bin'.
+The position of this entry is generally set by the intel-descriptor entry.
+
See README.x86 for information about x86 binary blobs.
@@ -282,16 +521,21 @@
-------------------------------------------------
Properties / Entry arguments: (see binman README for more information)
- - size: Size of section in bytes
- - align-size: Align size to a particular power of two
- - pad-before: Add padding before the entry
- - pad-after: Add padding after the entry
- - pad-byte: Pad byte to use when padding
- - sort-by-offset: Reorder the entries by offset
- - end-at-4gb: Used to build an x86 ROM which ends at 4GB (2^32)
- - name-prefix: Adds a prefix to the name of every entry in the section
+ pad-byte: Pad byte to use when padding
+ sort-by-offset: True if entries should be sorted by offset, False if
+ they must be in-order in the device tree description
+ end-at-4gb: Used to build an x86 ROM which ends at 4GB (2^32)
+ skip-at-start: Number of bytes before the first entry starts. These
+ effectively adjust the starting offset of entries. For example,
+ if this is 16, then the first entry would start at 16. An entry
+ with offset = 20 would in fact be written at offset 4 in the image
+ file, since the first 16 bytes are skipped when writing.
+ name-prefix: Adds a prefix to the name of every entry in the section
when writing out the map
+Since a section is also an entry, it inherits all the properies of entries
+too.
+
A section is an entry which can contain other entries, thus allowing
hierarchical images to be created. See 'Sections and hierarchical images'
in the binman README for more information.
@@ -310,6 +554,8 @@
that contains the string to place in the entry
<xxx> (actual name is the value of text-label): contains the string to
place in the entry.
+ <text>: The text to place in the entry (overrides the above mechanism).
+ This is useful when the text is constant.
Example node:
@@ -332,6 +578,13 @@
message = "a message directly in the node"
};
+or just:
+
+ text {
+ size = <8>;
+ text = "some text directly in the node"
+ };
+
The text is not itself nul-terminated. This can be achieved, if required,
by setting the size of the entry to something larger than the text.
@@ -485,7 +738,7 @@
-------------------------------------------
Properties / Entry arguments:
- - filename: Filename of SPL u-boot (default 'spl/u-boot')
+ - filename: Filename of SPL u-boot (default 'spl/u-boot-spl')
This is the U-Boot SPL ELF image. It does not include a device tree but can
be relocated to any address for execution.
@@ -563,6 +816,17 @@
+Entry: u-boot-tpl-elf: U-Boot TPL ELF image
+-------------------------------------------
+
+Properties / Entry arguments:
+ - filename: Filename of TPL u-boot (default 'tpl/u-boot-tpl')
+
+This is the U-Boot TPL ELF image. It does not include a device tree but can
+be relocated to any address for execution.
+
+
+
Entry: u-boot-tpl-with-ucode-ptr: U-Boot TPL with embedded microcode pointer
----------------------------------------------------------------------------
diff --git a/tools/binman/binman.py b/tools/binman/binman.py
index aad2e9c..8bd5868 100755
--- a/tools/binman/binman.py
+++ b/tools/binman/binman.py
@@ -11,23 +11,32 @@
from __future__ import print_function
+from distutils.sysconfig import get_python_lib
import glob
import multiprocessing
import os
+import site
import sys
import traceback
import unittest
-# Bring in the patman and dtoc libraries
+# Bring in the patman and dtoc libraries (but don't override the first path
+# in PYTHONPATH)
our_path = os.path.dirname(os.path.realpath(__file__))
for dirname in ['../patman', '../dtoc', '..', '../concurrencytest']:
- sys.path.insert(0, os.path.join(our_path, dirname))
+ sys.path.insert(2, os.path.join(our_path, dirname))
# Bring in the libfdt module
-sys.path.insert(0, 'scripts/dtc/pylibfdt')
-sys.path.insert(0, os.path.join(our_path,
+sys.path.insert(2, 'scripts/dtc/pylibfdt')
+sys.path.insert(2, os.path.join(our_path,
'../../build-sandbox_spl/scripts/dtc/pylibfdt'))
+# When running under python-coverage on Ubuntu 16.04, the dist-packages
+# directories are dropped from the python path. Add them in so that we can find
+# the elffile module. We could use site.getsitepackages() here but unfortunately
+# that is not available in a virtualenv.
+sys.path.append(get_python_lib())
+
import cmdline
import command
use_concurrent = True
@@ -38,15 +47,23 @@
import control
import test_util
-def RunTests(debug, processes, args):
+def RunTests(debug, verbosity, processes, test_preserve_dirs, args, toolpath):
"""Run the functional tests and any embedded doctests
Args:
debug: True to enable debugging, which shows a full stack trace on error
- args: List of positional args provided to binman. This can hold a test
- name to execute (as in 'binman -t testSections', for example)
+ verbosity: Verbosity level to use
+ test_preserve_dirs: True to preserve the input directory used by tests
+ so that it can be examined afterwards (only useful for debugging
+ tests). If a single test is selected (in args[0]) it also preserves
+ the output directory for this test. Both directories are displayed
+ on the command line.
processes: Number of processes to use to run tests (None=same as #CPUs)
+ args: List of positional args provided to binman. This can hold a test
+ name to execute (as in 'binman test testSections', for example)
+ toolpath: List of paths to use for tools
"""
+ import cbfs_util_test
import elf_test
import entry_test
import fdt_test
@@ -63,8 +80,11 @@
sys.argv = [sys.argv[0]]
if debug:
sys.argv.append('-D')
- if debug:
- sys.argv.append('-D')
+ if verbosity:
+ sys.argv.append('-v%d' % verbosity)
+ if toolpath:
+ for path in toolpath:
+ sys.argv += ['--toolpath', path]
# Run the entry tests first ,since these need to be the first to import the
# 'entry' module.
@@ -72,7 +92,14 @@
suite = unittest.TestSuite()
loader = unittest.TestLoader()
for module in (entry_test.TestEntry, ftest.TestFunctional, fdt_test.TestFdt,
- elf_test.TestElf, image_test.TestImage):
+ elf_test.TestElf, image_test.TestImage,
+ cbfs_util_test.TestCbfs):
+ # Test the test module about our arguments, if it is interested
+ if hasattr(module, 'setup_test_args'):
+ setup_test_args = getattr(module, 'setup_test_args')
+ setup_test_args(preserve_indir=test_preserve_dirs,
+ preserve_outdirs=test_preserve_dirs and test_name is not None,
+ toolpath=toolpath, verbosity=verbosity)
if test_name:
try:
suite.addTests(loader.loadTestsFromName(test_name, module))
@@ -104,9 +131,14 @@
print(test.id(), err)
for test, err in result.failures:
print(err, result.failures)
+ if result.skipped:
+ print('%d binman test%s SKIPPED:' %
+ (len(result.skipped), 's' if len(result.skipped) > 1 else ''))
+ for skip_info in result.skipped:
+ print('%s: %s' % (skip_info[0], skip_info[1]))
if result.errors or result.failures:
- print('binman tests FAILED')
- return 1
+ print('binman tests FAILED')
+ return 1
return 0
def GetEntryModules(include_testing=True):
@@ -127,38 +159,36 @@
for item in glob_list if '_testing' not in item])
test_util.RunTestCoverage('tools/binman/binman.py', None,
['*test*', '*binman.py', 'tools/patman/*', 'tools/dtoc/*'],
- options.build_dir, all_set)
+ args.build_dir, all_set)
-def RunBinman(options, args):
+def RunBinman(args):
"""Main entry point to binman once arguments are parsed
Args:
- options: Command-line options
- args: Non-option arguments
+ args: Command line arguments Namespace object
"""
ret_code = 0
- # For testing: This enables full exception traces.
- #options.debug = True
-
- if not options.debug:
+ if not args.debug:
sys.tracebacklimit = 0
- if options.test:
- ret_code = RunTests(options.debug, options.processes, args[1:])
-
- elif options.test_coverage:
- RunTestCoverage()
+ if args.cmd == 'test':
+ if args.test_coverage:
+ RunTestCoverage()
+ else:
+ ret_code = RunTests(args.debug, args.verbosity, args.processes,
+ args.test_preserve_dirs, args.tests,
+ args.toolpath)
- elif options.entry_docs:
+ elif args.cmd == 'entry-docs':
control.WriteEntryDocs(GetEntryModules())
else:
try:
- ret_code = control.Binman(options, args)
+ ret_code = control.Binman(args)
except Exception as e:
print('binman: %s' % e)
- if options.debug:
+ if args.debug:
print()
traceback.print_exc()
ret_code = 1
@@ -166,6 +196,7 @@
if __name__ == "__main__":
- (options, args) = cmdline.ParseArgs(sys.argv)
- ret_code = RunBinman(options, args)
+ args = cmdline.ParseArgs(sys.argv[1:])
+
+ ret_code = RunBinman(args)
sys.exit(ret_code)
diff --git a/tools/binman/bsection.py b/tools/binman/bsection.py
deleted file mode 100644
index 03dfa2f..0000000
--- a/tools/binman/bsection.py
+++ /dev/null
@@ -1,464 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+
-# Copyright (c) 2018 Google, Inc
-# Written by Simon Glass <sjg@chromium.org>
-#
-# Base class for sections (collections of entries)
-#
-
-from __future__ import print_function
-
-from collections import OrderedDict
-import sys
-
-import fdt_util
-import re
-import state
-import tools
-
-class Section(object):
- """A section which contains multiple entries
-
- A section represents a collection of entries. There must be one or more
- sections in an image. Sections are used to group entries together.
-
- Attributes:
- _node: Node object that contains the section definition in device tree
- _parent_section: Parent Section object which created this Section
- _size: Section size in bytes, or None if not known yet
- _align_size: Section size alignment, or None
- _pad_before: Number of bytes before the first entry starts. This
- effectively changes the place where entry offset 0 starts
- _pad_after: Number of bytes after the last entry ends. The last
- entry will finish on or before this boundary
- _pad_byte: Byte to use to pad the section where there is no entry
- _sort: True if entries should be sorted by offset, False if they
- must be in-order in the device tree description
- _skip_at_start: Number of bytes before the first entry starts. These
- effectively adjust the starting offset of entries. For example,
- if _pad_before is 16, then the first entry would start at 16.
- An entry with offset = 20 would in fact be written at offset 4
- in the image file.
- _end_4gb: Indicates that the section ends at the 4GB boundary. This is
- used for x86 images, which want to use offsets such that a memory
- address (like 0xff800000) is the first entry offset. This causes
- _skip_at_start to be set to the starting memory address.
- _name_prefix: Prefix to add to the name of all entries within this
- section
- _entries: OrderedDict() of entries
- """
- def __init__(self, name, parent_section, node, image, test=False):
- global entry
- global Entry
- import entry
- from entry import Entry
-
- self._parent_section = parent_section
- self._name = name
- self._node = node
- self._image = image
- self._offset = None
- self._size = None
- self._align_size = None
- self._pad_before = 0
- self._pad_after = 0
- self._pad_byte = 0
- self._sort = False
- self._skip_at_start = None
- self._end_4gb = False
- self._name_prefix = ''
- self._entries = OrderedDict()
- self._image_pos = None
- if not test:
- self._ReadNode()
- self._ReadEntries()
-
- def _ReadNode(self):
- """Read properties from the section node"""
- self._offset = fdt_util.GetInt(self._node, 'offset')
- self._size = fdt_util.GetInt(self._node, 'size')
- self._align_size = fdt_util.GetInt(self._node, 'align-size')
- if tools.NotPowerOfTwo(self._align_size):
- self._Raise("Alignment size %s must be a power of two" %
- self._align_size)
- self._pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
- self._pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
- self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 0)
- self._sort = fdt_util.GetBool(self._node, 'sort-by-offset')
- self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb')
- self._skip_at_start = fdt_util.GetInt(self._node, 'skip-at-start')
- if self._end_4gb:
- if not self._size:
- self._Raise("Section size must be provided when using end-at-4gb")
- if self._skip_at_start is not None:
- self._Raise("Provide either 'end-at-4gb' or 'skip-at-start'")
- else:
- self._skip_at_start = 0x100000000 - self._size
- else:
- if self._skip_at_start is None:
- self._skip_at_start = 0
- self._name_prefix = fdt_util.GetString(self._node, 'name-prefix')
-
- def _ReadEntries(self):
- for node in self._node.subnodes:
- if node.name == 'hash':
- continue
- entry = Entry.Create(self, node)
- entry.SetPrefix(self._name_prefix)
- self._entries[node.name] = entry
-
- def GetFdtSet(self):
- """Get the set of device tree files used by this image"""
- fdt_set = set()
- for entry in self._entries.values():
- fdt_set.update(entry.GetFdtSet())
- return fdt_set
-
- def SetOffset(self, offset):
- self._offset = offset
-
- def ExpandEntries(self):
- for entry in self._entries.values():
- entry.ExpandEntries()
-
- def AddMissingProperties(self):
- """Add new properties to the device tree as needed for this entry"""
- for prop in ['offset', 'size', 'image-pos']:
- if not prop in self._node.props:
- state.AddZeroProp(self._node, prop)
- state.CheckAddHashProp(self._node)
- for entry in self._entries.values():
- entry.AddMissingProperties()
-
- def SetCalculatedProperties(self):
- state.SetInt(self._node, 'offset', self._offset or 0)
- state.SetInt(self._node, 'size', self._size)
- image_pos = self._image_pos
- if self._parent_section:
- image_pos -= self._parent_section.GetRootSkipAtStart()
- state.SetInt(self._node, 'image-pos', image_pos)
- for entry in self._entries.values():
- entry.SetCalculatedProperties()
-
- def ProcessFdt(self, fdt):
- todo = self._entries.values()
- for passnum in range(3):
- next_todo = []
- for entry in todo:
- if not entry.ProcessFdt(fdt):
- next_todo.append(entry)
- todo = next_todo
- if not todo:
- break
- if todo:
- self._Raise('Internal error: Could not complete processing of Fdt: '
- 'remaining %s' % todo)
- return True
-
- def CheckSize(self):
- """Check that the section contents does not exceed its size, etc."""
- contents_size = 0
- for entry in self._entries.values():
- contents_size = max(contents_size, entry.offset + entry.size)
-
- contents_size -= self._skip_at_start
-
- size = self._size
- if not size:
- size = self._pad_before + contents_size + self._pad_after
- size = tools.Align(size, self._align_size)
-
- if self._size and contents_size > self._size:
- self._Raise("contents size %#x (%d) exceeds section size %#x (%d)" %
- (contents_size, contents_size, self._size, self._size))
- if not self._size:
- self._size = size
- if self._size != tools.Align(self._size, self._align_size):
- self._Raise("Size %#x (%d) does not match align-size %#x (%d)" %
- (self._size, self._size, self._align_size, self._align_size))
- return size
-
- def _Raise(self, msg):
- """Raises an error for this section
-
- Args:
- msg: Error message to use in the raise string
- Raises:
- ValueError()
- """
- raise ValueError("Section '%s': %s" % (self._node.path, msg))
-
- def GetPath(self):
- """Get the path of an image (in the FDT)
-
- Returns:
- Full path of the node for this image
- """
- return self._node.path
-
- def FindEntryType(self, etype):
- """Find an entry type in the section
-
- Args:
- etype: Entry type to find
- Returns:
- entry matching that type, or None if not found
- """
- for entry in self._entries.values():
- if entry.etype == etype:
- return entry
- return None
-
- def GetEntryContents(self):
- """Call ObtainContents() for each entry
-
- This calls each entry's ObtainContents() a few times until they all
- return True. We stop calling an entry's function once it returns
- True. This allows the contents of one entry to depend on another.
-
- After 3 rounds we give up since it's likely an error.
- """
- todo = self._entries.values()
- for passnum in range(3):
- next_todo = []
- for entry in todo:
- if not entry.ObtainContents():
- next_todo.append(entry)
- todo = next_todo
- if not todo:
- break
- if todo:
- self._Raise('Internal error: Could not complete processing of '
- 'contents: remaining %s' % todo)
- return True
-
- def _SetEntryOffsetSize(self, name, offset, size):
- """Set the offset and size of an entry
-
- Args:
- name: Entry name to update
- offset: New offset
- size: New size
- """
- entry = self._entries.get(name)
- if not entry:
- self._Raise("Unable to set offset/size for unknown entry '%s'" %
- name)
- entry.SetOffsetSize(self._skip_at_start + offset, size)
-
- def GetEntryOffsets(self):
- """Handle entries that want to set the offset/size of other entries
-
- This calls each entry's GetOffsets() method. If it returns a list
- of entries to update, it updates them.
- """
- for entry in self._entries.values():
- offset_dict = entry.GetOffsets()
- for name, info in offset_dict.items():
- self._SetEntryOffsetSize(name, *info)
-
- def PackEntries(self):
- """Pack all entries into the section"""
- offset = self._skip_at_start
- for entry in self._entries.values():
- offset = entry.Pack(offset)
- self._size = self.CheckSize()
-
- def _SortEntries(self):
- """Sort entries by offset"""
- entries = sorted(self._entries.values(), key=lambda entry: entry.offset)
- self._entries.clear()
- for entry in entries:
- self._entries[entry._node.name] = entry
-
- def _ExpandEntries(self):
- """Expand any entries that are permitted to"""
- exp_entry = None
- for entry in self._entries.values():
- if exp_entry:
- exp_entry.ExpandToLimit(entry.offset)
- exp_entry = None
- if entry.expand_size:
- exp_entry = entry
- if exp_entry:
- exp_entry.ExpandToLimit(self._size)
-
- def CheckEntries(self):
- """Check that entries do not overlap or extend outside the section
-
- This also sorts entries, if needed and expands
- """
- if self._sort:
- self._SortEntries()
- self._ExpandEntries()
- offset = 0
- prev_name = 'None'
- for entry in self._entries.values():
- entry.CheckOffset()
- if (entry.offset < self._skip_at_start or
- entry.offset + entry.size > self._skip_at_start + self._size):
- entry.Raise("Offset %#x (%d) is outside the section starting "
- "at %#x (%d)" %
- (entry.offset, entry.offset, self._skip_at_start,
- self._skip_at_start))
- if entry.offset < offset:
- entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
- "ending at %#x (%d)" %
- (entry.offset, entry.offset, prev_name, offset, offset))
- offset = entry.offset + entry.size
- prev_name = entry.GetPath()
-
- def SetImagePos(self, image_pos):
- self._image_pos = image_pos
- for entry in self._entries.values():
- entry.SetImagePos(image_pos)
-
- def ProcessEntryContents(self):
- """Call the ProcessContents() method for each entry
-
- This is intended to adjust the contents as needed by the entry type.
- """
- for entry in self._entries.values():
- entry.ProcessContents()
-
- def WriteSymbols(self):
- """Write symbol values into binary files for access at run time"""
- for entry in self._entries.values():
- entry.WriteSymbols(self)
-
- def BuildSection(self, fd, base_offset):
- """Write the section to a file"""
- fd.seek(base_offset)
- fd.write(self.GetData())
-
- def GetData(self):
- """Get the contents of the section"""
- section_data = tools.GetBytes(self._pad_byte, self._size)
-
- for entry in self._entries.values():
- data = entry.GetData()
- base = self._pad_before + entry.offset - self._skip_at_start
- section_data = (section_data[:base] + data +
- section_data[base + len(data):])
- return section_data
-
- def LookupSymbol(self, sym_name, optional, msg):
- """Look up a symbol in an ELF file
-
- Looks up a symbol in an ELF file. Only entry types which come from an
- ELF image can be used by this function.
-
- At present the only entry property supported is offset.
-
- Args:
- sym_name: Symbol name in the ELF file to look up in the format
- _binman_<entry>_prop_<property> where <entry> is the name of
- the entry and <property> is the property to find (e.g.
- _binman_u_boot_prop_offset). As a special case, you can append
- _any to <entry> to have it search for any matching entry. E.g.
- _binman_u_boot_any_prop_offset will match entries called u-boot,
- u-boot-img and u-boot-nodtb)
- optional: True if the symbol is optional. If False this function
- will raise if the symbol is not found
- msg: Message to display if an error occurs
-
- Returns:
- Value that should be assigned to that symbol, or None if it was
- optional and not found
-
- Raises:
- ValueError if the symbol is invalid or not found, or references a
- property which is not supported
- """
- m = re.match(r'^_binman_(\w+)_prop_(\w+)$', sym_name)
- if not m:
- raise ValueError("%s: Symbol '%s' has invalid format" %
- (msg, sym_name))
- entry_name, prop_name = m.groups()
- entry_name = entry_name.replace('_', '-')
- entry = self._entries.get(entry_name)
- if not entry:
- if entry_name.endswith('-any'):
- root = entry_name[:-4]
- for name in self._entries:
- if name.startswith(root):
- rest = name[len(root):]
- if rest in ['', '-img', '-nodtb']:
- entry = self._entries[name]
- if not entry:
- err = ("%s: Entry '%s' not found in list (%s)" %
- (msg, entry_name, ','.join(self._entries.keys())))
- if optional:
- print('Warning: %s' % err, file=sys.stderr)
- return None
- raise ValueError(err)
- if prop_name == 'offset':
- return entry.offset
- elif prop_name == 'image_pos':
- return entry.image_pos
- else:
- raise ValueError("%s: No such property '%s'" % (msg, prop_name))
-
- def GetEntries(self):
- """Get the number of entries in a section
-
- Returns:
- Number of entries in a section
- """
- return self._entries
-
- def GetSize(self):
- """Get the size of a section in bytes
-
- This is only meaningful if the section has a pre-defined size, or the
- entries within it have been packed, so that the size has been
- calculated.
-
- Returns:
- Entry size in bytes
- """
- return self._size
-
- def WriteMap(self, fd, indent):
- """Write a map of the section to a .map file
-
- Args:
- fd: File to write the map to
- """
- Entry.WriteMapLine(fd, indent, self._name, self._offset or 0,
- self._size, self._image_pos)
- for entry in self._entries.values():
- entry.WriteMap(fd, indent + 1)
-
- def GetContentsByPhandle(self, phandle, source_entry):
- """Get the data contents of an entry specified by a phandle
-
- This uses a phandle to look up a node and and find the entry
- associated with it. Then it returnst he contents of that entry.
-
- Args:
- phandle: Phandle to look up (integer)
- source_entry: Entry containing that phandle (used for error
- reporting)
-
- Returns:
- data from associated entry (as a string), or None if not found
- """
- node = self._node.GetFdt().LookupPhandle(phandle)
- if not node:
- source_entry.Raise("Cannot find node for phandle %d" % phandle)
- for entry in self._entries.values():
- if entry._node == node:
- return entry.GetData()
- source_entry.Raise("Cannot find entry for node '%s'" % node.name)
-
- def ExpandSize(self, size):
- if size != self._size:
- self._size = size
-
- def GetRootSkipAtStart(self):
- if self._parent_section:
- return self._parent_section.GetRootSkipAtStart()
- return self._skip_at_start
-
- def GetImageSize(self):
- return self._image._size
diff --git a/tools/binman/cbfs_util.py b/tools/binman/cbfs_util.py
new file mode 100644
index 0000000..45e16da
--- /dev/null
+++ b/tools/binman/cbfs_util.py
@@ -0,0 +1,887 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2019 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+
+"""Support for coreboot's CBFS format
+
+CBFS supports a header followed by a number of files, generally targeted at SPI
+flash.
+
+The format is somewhat defined by documentation in the coreboot tree although
+it is necessary to rely on the C structures and source code (mostly cbfstool)
+to fully understand it.
+
+Currently supported: raw and stage types with compression, padding empty areas
+ with empty files, fixed-offset files
+"""
+
+from __future__ import print_function
+
+from collections import OrderedDict
+import io
+import struct
+import sys
+
+import command
+import elf
+import tools
+
+# Set to True to enable printing output while working
+DEBUG = False
+
+# Set to True to enable output from running cbfstool for debugging
+VERBOSE = False
+
+# The master header, at the start of the CBFS
+HEADER_FORMAT = '>IIIIIIII'
+HEADER_LEN = 0x20
+HEADER_MAGIC = 0x4f524243
+HEADER_VERSION1 = 0x31313131
+HEADER_VERSION2 = 0x31313132
+
+# The file header, at the start of each file in the CBFS
+FILE_HEADER_FORMAT = b'>8sIIII'
+FILE_HEADER_LEN = 0x18
+FILE_MAGIC = b'LARCHIVE'
+FILENAME_ALIGN = 16 # Filename lengths are aligned to this
+
+# A stage header containing information about 'stage' files
+# Yes this is correct: this header is in litte-endian format
+STAGE_FORMAT = '<IQQII'
+STAGE_LEN = 0x1c
+
+# An attribute describring the compression used in a file
+ATTR_COMPRESSION_FORMAT = '>IIII'
+ATTR_COMPRESSION_LEN = 0x10
+
+# Attribute tags
+# Depending on how the header was initialised, it may be backed with 0x00 or
+# 0xff. Support both.
+FILE_ATTR_TAG_UNUSED = 0
+FILE_ATTR_TAG_UNUSED2 = 0xffffffff
+FILE_ATTR_TAG_COMPRESSION = 0x42435a4c
+FILE_ATTR_TAG_HASH = 0x68736148
+FILE_ATTR_TAG_POSITION = 0x42435350 # PSCB
+FILE_ATTR_TAG_ALIGNMENT = 0x42434c41 # ALCB
+FILE_ATTR_TAG_PADDING = 0x47444150 # PDNG
+
+# This is 'the size of bootblock reserved in firmware image (cbfs.txt)'
+# Not much more info is available, but we set it to 4, due to this comment in
+# cbfstool.c:
+# This causes 4 bytes to be left out at the end of the image, for two reasons:
+# 1. The cbfs master header pointer resides there
+# 2. Ssme cbfs implementations assume that an image that resides below 4GB has
+# a bootblock and get confused when the end of the image is at 4GB == 0.
+MIN_BOOTBLOCK_SIZE = 4
+
+# Files start aligned to this boundary in the CBFS
+ENTRY_ALIGN = 0x40
+
+# CBFSs must declare an architecture since much of the logic is designed with
+# x86 in mind. The effect of setting this value is not well documented, but in
+# general x86 is used and this makes use of a boot block and an image that ends
+# at the end of 32-bit address space.
+ARCHITECTURE_UNKNOWN = 0xffffffff
+ARCHITECTURE_X86 = 0x00000001
+ARCHITECTURE_ARM = 0x00000010
+ARCHITECTURE_AARCH64 = 0x0000aa64
+ARCHITECTURE_MIPS = 0x00000100
+ARCHITECTURE_RISCV = 0xc001d0de
+ARCHITECTURE_PPC64 = 0x407570ff
+
+ARCH_NAMES = {
+ ARCHITECTURE_UNKNOWN : 'unknown',
+ ARCHITECTURE_X86 : 'x86',
+ ARCHITECTURE_ARM : 'arm',
+ ARCHITECTURE_AARCH64 : 'arm64',
+ ARCHITECTURE_MIPS : 'mips',
+ ARCHITECTURE_RISCV : 'riscv',
+ ARCHITECTURE_PPC64 : 'ppc64',
+ }
+
+# File types. Only supported ones are included here
+TYPE_CBFSHEADER = 0x02 # Master header, HEADER_FORMAT
+TYPE_STAGE = 0x10 # Stage, holding an executable, see STAGE_FORMAT
+TYPE_RAW = 0x50 # Raw file, possibly compressed
+TYPE_EMPTY = 0xffffffff # Empty data
+
+# Compression types
+COMPRESS_NONE, COMPRESS_LZMA, COMPRESS_LZ4 = range(3)
+
+COMPRESS_NAMES = {
+ COMPRESS_NONE : 'none',
+ COMPRESS_LZMA : 'lzma',
+ COMPRESS_LZ4 : 'lz4',
+ }
+
+def find_arch(find_name):
+ """Look up an architecture name
+
+ Args:
+ find_name: Architecture name to find
+
+ Returns:
+ ARCHITECTURE_... value or None if not found
+ """
+ for arch, name in ARCH_NAMES.items():
+ if name == find_name:
+ return arch
+ return None
+
+def find_compress(find_name):
+ """Look up a compression algorithm name
+
+ Args:
+ find_name: Compression algorithm name to find
+
+ Returns:
+ COMPRESS_... value or None if not found
+ """
+ for compress, name in COMPRESS_NAMES.items():
+ if name == find_name:
+ return compress
+ return None
+
+def compress_name(compress):
+ """Look up the name of a compression algorithm
+
+ Args:
+ compress: Compression algorithm number to find (COMPRESS_...)
+
+ Returns:
+ Compression algorithm name (string)
+
+ Raises:
+ KeyError if the algorithm number is invalid
+ """
+ return COMPRESS_NAMES[compress]
+
+def align_int(val, align):
+ """Align a value up to the given alignment
+
+ Args:
+ val: Integer value to align
+ align: Integer alignment value (e.g. 4 to align to 4-byte boundary)
+
+ Returns:
+ integer value aligned to the required boundary, rounding up if necessary
+ """
+ return int((val + align - 1) / align) * align
+
+def align_int_down(val, align):
+ """Align a value down to the given alignment
+
+ Args:
+ val: Integer value to align
+ align: Integer alignment value (e.g. 4 to align to 4-byte boundary)
+
+ Returns:
+ integer value aligned to the required boundary, rounding down if
+ necessary
+ """
+ return int(val / align) * align
+
+def _pack_string(instr):
+ """Pack a string to the required aligned size by adding padding
+
+ Args:
+ instr: String to process
+
+ Returns:
+ String with required padding (at least one 0x00 byte) at the end
+ """
+ val = tools.ToBytes(instr)
+ pad_len = align_int(len(val) + 1, FILENAME_ALIGN)
+ return val + tools.GetBytes(0, pad_len - len(val))
+
+
+class CbfsFile(object):
+ """Class to represent a single CBFS file
+
+ This is used to hold the information about a file, including its contents.
+ Use the get_data_and_offset() method to obtain the raw output for writing to
+ CBFS.
+
+ Properties:
+ name: Name of file
+ offset: Offset of file data from start of file header
+ cbfs_offset: Offset of file data in bytes from start of CBFS, or None to
+ place this file anyway
+ data: Contents of file, uncompressed
+ data_len: Length of (possibly compressed) data in bytes
+ ftype: File type (TYPE_...)
+ compression: Compression type (COMPRESS_...)
+ memlen: Length of data in memory, i.e. the uncompressed length, None if
+ no compression algortihm is selected
+ load: Load address in memory if known, else None
+ entry: Entry address in memory if known, else None. This is where
+ execution starts after the file is loaded
+ base_address: Base address to use for 'stage' files
+ erase_byte: Erase byte to use for padding between the file header and
+ contents (used for empty files)
+ size: Size of the file in bytes (used for empty files)
+ """
+ def __init__(self, name, ftype, data, cbfs_offset, compress=COMPRESS_NONE):
+ self.name = name
+ self.offset = None
+ self.cbfs_offset = cbfs_offset
+ self.data = data
+ self.ftype = ftype
+ self.compress = compress
+ self.memlen = None
+ self.load = None
+ self.entry = None
+ self.base_address = None
+ self.data_len = len(data)
+ self.erase_byte = None
+ self.size = None
+
+ def decompress(self):
+ """Handle decompressing data if necessary"""
+ indata = self.data
+ if self.compress == COMPRESS_LZ4:
+ data = tools.Decompress(indata, 'lz4')
+ elif self.compress == COMPRESS_LZMA:
+ data = tools.Decompress(indata, 'lzma')
+ else:
+ data = indata
+ self.memlen = len(data)
+ self.data = data
+ self.data_len = len(indata)
+
+ @classmethod
+ def stage(cls, base_address, name, data, cbfs_offset):
+ """Create a new stage file
+
+ Args:
+ base_address: Int base address for memory-mapping of ELF file
+ name: String file name to put in CBFS (does not need to correspond
+ to the name that the file originally came from)
+ data: Contents of file
+ cbfs_offset: Offset of file data in bytes from start of CBFS, or
+ None to place this file anyway
+
+ Returns:
+ CbfsFile object containing the file information
+ """
+ cfile = CbfsFile(name, TYPE_STAGE, data, cbfs_offset)
+ cfile.base_address = base_address
+ return cfile
+
+ @classmethod
+ def raw(cls, name, data, cbfs_offset, compress):
+ """Create a new raw file
+
+ Args:
+ name: String file name to put in CBFS (does not need to correspond
+ to the name that the file originally came from)
+ data: Contents of file
+ cbfs_offset: Offset of file data in bytes from start of CBFS, or
+ None to place this file anyway
+ compress: Compression algorithm to use (COMPRESS_...)
+
+ Returns:
+ CbfsFile object containing the file information
+ """
+ return CbfsFile(name, TYPE_RAW, data, cbfs_offset, compress)
+
+ @classmethod
+ def empty(cls, space_to_use, erase_byte):
+ """Create a new empty file of a given size
+
+ Args:
+ space_to_use:: Size of available space, which must be at least as
+ large as the alignment size for this CBFS
+ erase_byte: Byte to use for contents of file (repeated through the
+ whole file)
+
+ Returns:
+ CbfsFile object containing the file information
+ """
+ cfile = CbfsFile('', TYPE_EMPTY, b'', None)
+ cfile.size = space_to_use - FILE_HEADER_LEN - FILENAME_ALIGN
+ cfile.erase_byte = erase_byte
+ return cfile
+
+ def calc_start_offset(self):
+ """Check if this file needs to start at a particular offset in CBFS
+
+ Returns:
+ None if the file can be placed anywhere, or
+ the largest offset where the file could start (integer)
+ """
+ if self.cbfs_offset is None:
+ return None
+ return self.cbfs_offset - self.get_header_len()
+
+ def get_header_len(self):
+ """Get the length of headers required for a file
+
+ This is the minimum length required before the actual data for this file
+ could start. It might start later if there is padding.
+
+ Returns:
+ Total length of all non-data fields, in bytes
+ """
+ name = _pack_string(self.name)
+ hdr_len = len(name) + FILE_HEADER_LEN
+ if self.ftype == TYPE_STAGE:
+ pass
+ elif self.ftype == TYPE_RAW:
+ hdr_len += ATTR_COMPRESSION_LEN
+ elif self.ftype == TYPE_EMPTY:
+ pass
+ else:
+ raise ValueError('Unknown file type %#x\n' % self.ftype)
+ return hdr_len
+
+ def get_data_and_offset(self, offset=None, pad_byte=None):
+ """Obtain the contents of the file, in CBFS format and the offset of
+ the data within the file
+
+ Returns:
+ tuple:
+ bytes representing the contents of this file, packed and aligned
+ for directly inserting into the final CBFS output
+ offset to the file data from the start of the returned data.
+ """
+ name = _pack_string(self.name)
+ hdr_len = len(name) + FILE_HEADER_LEN
+ attr_pos = 0
+ content = b''
+ attr = b''
+ pad = b''
+ data = self.data
+ if self.ftype == TYPE_STAGE:
+ elf_data = elf.DecodeElf(data, self.base_address)
+ content = struct.pack(STAGE_FORMAT, self.compress,
+ elf_data.entry, elf_data.load,
+ len(elf_data.data), elf_data.memsize)
+ data = elf_data.data
+ elif self.ftype == TYPE_RAW:
+ orig_data = data
+ if self.compress == COMPRESS_LZ4:
+ data = tools.Compress(orig_data, 'lz4')
+ elif self.compress == COMPRESS_LZMA:
+ data = tools.Compress(orig_data, 'lzma')
+ self.memlen = len(orig_data)
+ self.data_len = len(data)
+ attr = struct.pack(ATTR_COMPRESSION_FORMAT,
+ FILE_ATTR_TAG_COMPRESSION, ATTR_COMPRESSION_LEN,
+ self.compress, self.memlen)
+ elif self.ftype == TYPE_EMPTY:
+ data = tools.GetBytes(self.erase_byte, self.size)
+ else:
+ raise ValueError('Unknown type %#x when writing\n' % self.ftype)
+ if attr:
+ attr_pos = hdr_len
+ hdr_len += len(attr)
+ if self.cbfs_offset is not None:
+ pad_len = self.cbfs_offset - offset - hdr_len
+ if pad_len < 0: # pragma: no cover
+ # Test coverage of this is not available since this should never
+ # happen. It indicates that get_header_len() provided an
+ # incorrect value (too small) so that we decided that we could
+ # put this file at the requested place, but in fact a previous
+ # file extends far enough into the CBFS that this is not
+ # possible.
+ raise ValueError("Internal error: CBFS file '%s': Requested offset %#x but current output position is %#x" %
+ (self.name, self.cbfs_offset, offset))
+ pad = tools.GetBytes(pad_byte, pad_len)
+ hdr_len += pad_len
+
+ # This is the offset of the start of the file's data,
+ size = len(content) + len(data)
+ hdr = struct.pack(FILE_HEADER_FORMAT, FILE_MAGIC, size,
+ self.ftype, attr_pos, hdr_len)
+
+ # Do a sanity check of the get_header_len() function, to ensure that it
+ # stays in lockstep with this function
+ expected_len = self.get_header_len()
+ actual_len = len(hdr + name + attr)
+ if expected_len != actual_len: # pragma: no cover
+ # Test coverage of this is not available since this should never
+ # happen. It probably indicates that get_header_len() is broken.
+ raise ValueError("Internal error: CBFS file '%s': Expected headers of %#x bytes, got %#d" %
+ (self.name, expected_len, actual_len))
+ return hdr + name + attr + pad + content + data, hdr_len
+
+
+class CbfsWriter(object):
+ """Class to handle writing a Coreboot File System (CBFS)
+
+ Usage is something like:
+
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', tools.ReadFile('u-boot.bin'))
+ ...
+ data, cbfs_offset = cbw.get_data_and_offset()
+
+ Attributes:
+ _master_name: Name of the file containing the master header
+ _size: Size of the filesystem, in bytes
+ _files: Ordered list of files in the CBFS, each a CbfsFile
+ _arch: Architecture of the CBFS (ARCHITECTURE_...)
+ _bootblock_size: Size of the bootblock, typically at the end of the CBFS
+ _erase_byte: Byte to use for empty space in the CBFS
+ _align: Alignment to use for files, typically ENTRY_ALIGN
+ _base_address: Boot block offset in bytes from the start of CBFS.
+ Typically this is located at top of the CBFS. It is 0 when there is
+ no boot block
+ _header_offset: Offset of master header in bytes from start of CBFS
+ _contents_offset: Offset of first file header
+ _hdr_at_start: True if the master header is at the start of the CBFS,
+ instead of the end as normal for x86
+ _add_fileheader: True to add a fileheader around the master header
+ """
+ def __init__(self, size, arch=ARCHITECTURE_X86):
+ """Set up a new CBFS
+
+ This sets up all properties to default values. Files can be added using
+ add_file_raw(), etc.
+
+ Args:
+ size: Size of CBFS in bytes
+ arch: Architecture to declare for CBFS
+ """
+ self._master_name = 'cbfs master header'
+ self._size = size
+ self._files = OrderedDict()
+ self._arch = arch
+ self._bootblock_size = 0
+ self._erase_byte = 0xff
+ self._align = ENTRY_ALIGN
+ self._add_fileheader = False
+ if self._arch == ARCHITECTURE_X86:
+ # Allow 4 bytes for the header pointer. That holds the
+ # twos-compliment negative offset of the master header in bytes
+ # measured from one byte past the end of the CBFS
+ self._base_address = self._size - max(self._bootblock_size,
+ MIN_BOOTBLOCK_SIZE)
+ self._header_offset = self._base_address - HEADER_LEN
+ self._contents_offset = 0
+ self._hdr_at_start = False
+ else:
+ # For non-x86, different rules apply
+ self._base_address = 0
+ self._header_offset = align_int(self._base_address +
+ self._bootblock_size, 4)
+ self._contents_offset = align_int(self._header_offset +
+ FILE_HEADER_LEN +
+ self._bootblock_size, self._align)
+ self._hdr_at_start = True
+
+ def _skip_to(self, fd, offset):
+ """Write out pad bytes until a given offset
+
+ Args:
+ fd: File objext to write to
+ offset: Offset to write to
+ """
+ if fd.tell() > offset:
+ raise ValueError('No space for data before offset %#x (current offset %#x)' %
+ (offset, fd.tell()))
+ fd.write(tools.GetBytes(self._erase_byte, offset - fd.tell()))
+
+ def _pad_to(self, fd, offset):
+ """Write out pad bytes and/or an empty file until a given offset
+
+ Args:
+ fd: File objext to write to
+ offset: Offset to write to
+ """
+ self._align_to(fd, self._align)
+ upto = fd.tell()
+ if upto > offset:
+ raise ValueError('No space for data before pad offset %#x (current offset %#x)' %
+ (offset, upto))
+ todo = align_int_down(offset - upto, self._align)
+ if todo:
+ cbf = CbfsFile.empty(todo, self._erase_byte)
+ fd.write(cbf.get_data_and_offset()[0])
+ self._skip_to(fd, offset)
+
+ def _align_to(self, fd, align):
+ """Write out pad bytes until a given alignment is reached
+
+ This only aligns if the resulting output would not reach the end of the
+ CBFS, since we want to leave the last 4 bytes for the master-header
+ pointer.
+
+ Args:
+ fd: File objext to write to
+ align: Alignment to require (e.g. 4 means pad to next 4-byte
+ boundary)
+ """
+ offset = align_int(fd.tell(), align)
+ if offset < self._size:
+ self._skip_to(fd, offset)
+
+ def add_file_stage(self, name, data, cbfs_offset=None):
+ """Add a new stage file to the CBFS
+
+ Args:
+ name: String file name to put in CBFS (does not need to correspond
+ to the name that the file originally came from)
+ data: Contents of file
+ cbfs_offset: Offset of this file's data within the CBFS, in bytes,
+ or None to place this file anywhere
+
+ Returns:
+ CbfsFile object created
+ """
+ cfile = CbfsFile.stage(self._base_address, name, data, cbfs_offset)
+ self._files[name] = cfile
+ return cfile
+
+ def add_file_raw(self, name, data, cbfs_offset=None,
+ compress=COMPRESS_NONE):
+ """Create a new raw file
+
+ Args:
+ name: String file name to put in CBFS (does not need to correspond
+ to the name that the file originally came from)
+ data: Contents of file
+ cbfs_offset: Offset of this file's data within the CBFS, in bytes,
+ or None to place this file anywhere
+ compress: Compression algorithm to use (COMPRESS_...)
+
+ Returns:
+ CbfsFile object created
+ """
+ cfile = CbfsFile.raw(name, data, cbfs_offset, compress)
+ self._files[name] = cfile
+ return cfile
+
+ def _write_header(self, fd, add_fileheader):
+ """Write out the master header to a CBFS
+
+ Args:
+ fd: File object
+ add_fileheader: True to place the master header in a file header
+ record
+ """
+ if fd.tell() > self._header_offset:
+ raise ValueError('No space for header at offset %#x (current offset %#x)' %
+ (self._header_offset, fd.tell()))
+ if not add_fileheader:
+ self._pad_to(fd, self._header_offset)
+ hdr = struct.pack(HEADER_FORMAT, HEADER_MAGIC, HEADER_VERSION2,
+ self._size, self._bootblock_size, self._align,
+ self._contents_offset, self._arch, 0xffffffff)
+ if add_fileheader:
+ name = _pack_string(self._master_name)
+ fd.write(struct.pack(FILE_HEADER_FORMAT, FILE_MAGIC, len(hdr),
+ TYPE_CBFSHEADER, 0,
+ FILE_HEADER_LEN + len(name)))
+ fd.write(name)
+ self._header_offset = fd.tell()
+ fd.write(hdr)
+ self._align_to(fd, self._align)
+ else:
+ fd.write(hdr)
+
+ def get_data(self):
+ """Obtain the full contents of the CBFS
+
+ Thhis builds the CBFS with headers and all required files.
+
+ Returns:
+ 'bytes' type containing the data
+ """
+ fd = io.BytesIO()
+
+ # THe header can go at the start in some cases
+ if self._hdr_at_start:
+ self._write_header(fd, add_fileheader=self._add_fileheader)
+ self._skip_to(fd, self._contents_offset)
+
+ # Write out each file
+ for cbf in self._files.values():
+ # Place the file at its requested place, if any
+ offset = cbf.calc_start_offset()
+ if offset is not None:
+ self._pad_to(fd, align_int_down(offset, self._align))
+ pos = fd.tell()
+ data, data_offset = cbf.get_data_and_offset(pos, self._erase_byte)
+ fd.write(data)
+ self._align_to(fd, self._align)
+ cbf.calced_cbfs_offset = pos + data_offset
+ if not self._hdr_at_start:
+ self._write_header(fd, add_fileheader=self._add_fileheader)
+
+ # Pad to the end and write a pointer to the CBFS master header
+ self._pad_to(fd, self._base_address or self._size - 4)
+ rel_offset = self._header_offset - self._size
+ fd.write(struct.pack('<I', rel_offset & 0xffffffff))
+
+ return fd.getvalue()
+
+
+class CbfsReader(object):
+ """Class to handle reading a Coreboot File System (CBFS)
+
+ Usage is something like:
+ cbfs = cbfs_util.CbfsReader(data)
+ cfile = cbfs.files['u-boot']
+ self.WriteFile('u-boot.bin', cfile.data)
+
+ Attributes:
+ files: Ordered list of CbfsFile objects
+ align: Alignment to use for files, typically ENTRT_ALIGN
+ stage_base_address: Base address to use when mapping ELF files into the
+ CBFS for TYPE_STAGE files. If this is larger than the code address
+ of the ELF file, then data at the start of the ELF file will not
+ appear in the CBFS. Currently there are no tests for behaviour as
+ documentation is sparse
+ magic: Integer magic number from master header (HEADER_MAGIC)
+ version: Version number of CBFS (HEADER_VERSION2)
+ rom_size: Size of CBFS
+ boot_block_size: Size of boot block
+ cbfs_offset: Offset of the first file in bytes from start of CBFS
+ arch: Architecture of CBFS file (ARCHITECTURE_...)
+ """
+ def __init__(self, data, read=True):
+ self.align = ENTRY_ALIGN
+ self.arch = None
+ self.boot_block_size = None
+ self.cbfs_offset = None
+ self.files = OrderedDict()
+ self.magic = None
+ self.rom_size = None
+ self.stage_base_address = 0
+ self.version = None
+ self.data = data
+ if read:
+ self.read()
+
+ def read(self):
+ """Read all the files in the CBFS and add them to self.files"""
+ with io.BytesIO(self.data) as fd:
+ # First, get the master header
+ if not self._find_and_read_header(fd, len(self.data)):
+ raise ValueError('Cannot find master header')
+ fd.seek(self.cbfs_offset)
+
+ # Now read in the files one at a time
+ while True:
+ cfile = self._read_next_file(fd)
+ if cfile:
+ self.files[cfile.name] = cfile
+ elif cfile is False:
+ break
+
+ def _find_and_read_header(self, fd, size):
+ """Find and read the master header in the CBFS
+
+ This looks at the pointer word at the very end of the CBFS. This is an
+ offset to the header relative to the size of the CBFS, which is assumed
+ to be known. Note that the offset is in *little endian* format.
+
+ Args:
+ fd: File to read from
+ size: Size of file
+
+ Returns:
+ True if header was found, False if not
+ """
+ orig_pos = fd.tell()
+ fd.seek(size - 4)
+ rel_offset, = struct.unpack('<I', fd.read(4))
+ pos = (size + rel_offset) & 0xffffffff
+ fd.seek(pos)
+ found = self._read_header(fd)
+ if not found:
+ print('Relative offset seems wrong, scanning whole image')
+ for pos in range(0, size - HEADER_LEN, 4):
+ fd.seek(pos)
+ found = self._read_header(fd)
+ if found:
+ break
+ fd.seek(orig_pos)
+ return found
+
+ def _read_next_file(self, fd):
+ """Read the next file from a CBFS
+
+ Args:
+ fd: File to read from
+
+ Returns:
+ CbfsFile object, if found
+ None if no object found, but data was parsed (e.g. TYPE_CBFSHEADER)
+ False if at end of CBFS and reading should stop
+ """
+ file_pos = fd.tell()
+ data = fd.read(FILE_HEADER_LEN)
+ if len(data) < FILE_HEADER_LEN:
+ print('File header at %x ran out of data' % file_pos)
+ return False
+ magic, size, ftype, attr, offset = struct.unpack(FILE_HEADER_FORMAT,
+ data)
+ if magic != FILE_MAGIC:
+ return False
+ pos = fd.tell()
+ name = self._read_string(fd)
+ if name is None:
+ print('String at %x ran out of data' % pos)
+ return False
+
+ if DEBUG:
+ print('name', name)
+
+ # If there are attribute headers present, read those
+ compress = self._read_attr(fd, file_pos, attr, offset)
+ if compress is None:
+ return False
+
+ # Create the correct CbfsFile object depending on the type
+ cfile = None
+ cbfs_offset = file_pos + offset
+ fd.seek(cbfs_offset, io.SEEK_SET)
+ if ftype == TYPE_CBFSHEADER:
+ self._read_header(fd)
+ elif ftype == TYPE_STAGE:
+ data = fd.read(STAGE_LEN)
+ cfile = CbfsFile.stage(self.stage_base_address, name, b'',
+ cbfs_offset)
+ (cfile.compress, cfile.entry, cfile.load, cfile.data_len,
+ cfile.memlen) = struct.unpack(STAGE_FORMAT, data)
+ cfile.data = fd.read(cfile.data_len)
+ elif ftype == TYPE_RAW:
+ data = fd.read(size)
+ cfile = CbfsFile.raw(name, data, cbfs_offset, compress)
+ cfile.decompress()
+ if DEBUG:
+ print('data', data)
+ elif ftype == TYPE_EMPTY:
+ # Just read the data and discard it, since it is only padding
+ fd.read(size)
+ cfile = CbfsFile('', TYPE_EMPTY, b'', cbfs_offset)
+ else:
+ raise ValueError('Unknown type %#x when reading\n' % ftype)
+ if cfile:
+ cfile.offset = offset
+
+ # Move past the padding to the start of a possible next file. If we are
+ # already at an alignment boundary, then there is no padding.
+ pad = (self.align - fd.tell() % self.align) % self.align
+ fd.seek(pad, io.SEEK_CUR)
+ return cfile
+
+ @classmethod
+ def _read_attr(cls, fd, file_pos, attr, offset):
+ """Read attributes from the file
+
+ CBFS files can have attributes which are things that cannot fit into the
+ header. The only attributes currently supported are compression and the
+ unused tag.
+
+ Args:
+ fd: File to read from
+ file_pos: Position of file in fd
+ attr: Offset of attributes, 0 if none
+ offset: Offset of file data (used to indicate the end of the
+ attributes)
+
+ Returns:
+ Compression to use for the file (COMPRESS_...)
+ """
+ compress = COMPRESS_NONE
+ if not attr:
+ return compress
+ attr_size = offset - attr
+ fd.seek(file_pos + attr, io.SEEK_SET)
+ while attr_size:
+ pos = fd.tell()
+ hdr = fd.read(8)
+ if len(hdr) < 8:
+ print('Attribute tag at %x ran out of data' % pos)
+ return None
+ atag, alen = struct.unpack(">II", hdr)
+ data = hdr + fd.read(alen - 8)
+ if atag == FILE_ATTR_TAG_COMPRESSION:
+ # We don't currently use this information
+ atag, alen, compress, _decomp_size = struct.unpack(
+ ATTR_COMPRESSION_FORMAT, data)
+ elif atag == FILE_ATTR_TAG_UNUSED2:
+ break
+ else:
+ print('Unknown attribute tag %x' % atag)
+ attr_size -= len(data)
+ return compress
+
+ def _read_header(self, fd):
+ """Read the master header
+
+ Reads the header and stores the information obtained into the member
+ variables.
+
+ Args:
+ fd: File to read from
+
+ Returns:
+ True if header was read OK, False if it is truncated or has the
+ wrong magic or version
+ """
+ pos = fd.tell()
+ data = fd.read(HEADER_LEN)
+ if len(data) < HEADER_LEN:
+ print('Header at %x ran out of data' % pos)
+ return False
+ (self.magic, self.version, self.rom_size, self.boot_block_size,
+ self.align, self.cbfs_offset, self.arch, _) = struct.unpack(
+ HEADER_FORMAT, data)
+ return self.magic == HEADER_MAGIC and (
+ self.version == HEADER_VERSION1 or
+ self.version == HEADER_VERSION2)
+
+ @classmethod
+ def _read_string(cls, fd):
+ """Read a string from a file
+
+ This reads a string and aligns the data to the next alignment boundary
+
+ Args:
+ fd: File to read from
+
+ Returns:
+ string read ('str' type) encoded to UTF-8, or None if we ran out of
+ data
+ """
+ val = b''
+ while True:
+ data = fd.read(FILENAME_ALIGN)
+ if len(data) < FILENAME_ALIGN:
+ return None
+ pos = data.find(b'\0')
+ if pos == -1:
+ val += data
+ else:
+ val += data[:pos]
+ break
+ return val.decode('utf-8')
+
+
+def cbfstool(fname, *cbfs_args, **kwargs):
+ """Run cbfstool with provided arguments
+
+ If the tool fails then this function raises an exception and prints out the
+ output and stderr.
+
+ Args:
+ fname: Filename of CBFS
+ *cbfs_args: List of arguments to pass to cbfstool
+
+ Returns:
+ CommandResult object containing the results
+ """
+ args = ['cbfstool', fname] + list(cbfs_args)
+ if kwargs.get('base') is not None:
+ args += ['-b', '%#x' % kwargs['base']]
+ result = command.RunPipe([args], capture=not VERBOSE,
+ capture_stderr=not VERBOSE, raise_on_error=False)
+ if result.return_code:
+ print(result.stderr, file=sys.stderr)
+ raise Exception("Failed to run (error %d): '%s'" %
+ (result.return_code, ' '.join(args)))
diff --git a/tools/binman/cbfs_util_test.py b/tools/binman/cbfs_util_test.py
new file mode 100755
index 0000000..0fe4aa4
--- /dev/null
+++ b/tools/binman/cbfs_util_test.py
@@ -0,0 +1,625 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2019 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+
+"""Tests for cbfs_util
+
+These create and read various CBFSs and compare the results with expected
+values and with cbfstool
+"""
+
+from __future__ import print_function
+
+import io
+import os
+import shutil
+import struct
+import tempfile
+import unittest
+
+import cbfs_util
+from cbfs_util import CbfsWriter
+import elf
+import test_util
+import tools
+
+U_BOOT_DATA = b'1234'
+U_BOOT_DTB_DATA = b'udtb'
+COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
+
+
+class TestCbfs(unittest.TestCase):
+ """Test of cbfs_util classes"""
+ #pylint: disable=W0212
+ @classmethod
+ def setUpClass(cls):
+ # Create a temporary directory for test files
+ cls._indir = tempfile.mkdtemp(prefix='cbfs_util.')
+ tools.SetInputDirs([cls._indir])
+
+ # Set up some useful data files
+ TestCbfs._make_input_file('u-boot.bin', U_BOOT_DATA)
+ TestCbfs._make_input_file('u-boot.dtb', U_BOOT_DTB_DATA)
+ TestCbfs._make_input_file('compress', COMPRESS_DATA)
+
+ # Set up a temporary output directory, used by the tools library when
+ # compressing files
+ tools.PrepareOutputDir(None)
+
+ cls.have_cbfstool = True
+ try:
+ tools.Run('which', 'cbfstool')
+ except:
+ cls.have_cbfstool = False
+
+ cls.have_lz4 = True
+ try:
+ tools.Run('lz4', '--no-frame-crc', '-c',
+ tools.GetInputFilename('u-boot.bin'))
+ except:
+ cls.have_lz4 = False
+
+ @classmethod
+ def tearDownClass(cls):
+ """Remove the temporary input directory and its contents"""
+ if cls._indir:
+ shutil.rmtree(cls._indir)
+ cls._indir = None
+ tools.FinaliseOutputDir()
+
+ @classmethod
+ def _make_input_file(cls, fname, contents):
+ """Create a new test input file, creating directories as needed
+
+ Args:
+ fname: Filename to create
+ contents: File contents to write in to the file
+ Returns:
+ Full pathname of file created
+ """
+ pathname = os.path.join(cls._indir, fname)
+ tools.WriteFile(pathname, contents)
+ return pathname
+
+ def _check_hdr(self, data, size, offset=0, arch=cbfs_util.ARCHITECTURE_X86):
+ """Check that the CBFS has the expected header
+
+ Args:
+ data: Data to check
+ size: Expected ROM size
+ offset: Expected offset to first CBFS file
+ arch: Expected architecture
+
+ Returns:
+ CbfsReader object containing the CBFS
+ """
+ cbfs = cbfs_util.CbfsReader(data)
+ self.assertEqual(cbfs_util.HEADER_MAGIC, cbfs.magic)
+ self.assertEqual(cbfs_util.HEADER_VERSION2, cbfs.version)
+ self.assertEqual(size, cbfs.rom_size)
+ self.assertEqual(0, cbfs.boot_block_size)
+ self.assertEqual(cbfs_util.ENTRY_ALIGN, cbfs.align)
+ self.assertEqual(offset, cbfs.cbfs_offset)
+ self.assertEqual(arch, cbfs.arch)
+ return cbfs
+
+ def _check_uboot(self, cbfs, ftype=cbfs_util.TYPE_RAW, offset=0x38,
+ data=U_BOOT_DATA, cbfs_offset=None):
+ """Check that the U-Boot file is as expected
+
+ Args:
+ cbfs: CbfsReader object to check
+ ftype: Expected file type
+ offset: Expected offset of file
+ data: Expected data in file
+ cbfs_offset: Expected CBFS offset for file's data
+
+ Returns:
+ CbfsFile object containing the file
+ """
+ self.assertIn('u-boot', cbfs.files)
+ cfile = cbfs.files['u-boot']
+ self.assertEqual('u-boot', cfile.name)
+ self.assertEqual(offset, cfile.offset)
+ if cbfs_offset is not None:
+ self.assertEqual(cbfs_offset, cfile.cbfs_offset)
+ self.assertEqual(data, cfile.data)
+ self.assertEqual(ftype, cfile.ftype)
+ self.assertEqual(cbfs_util.COMPRESS_NONE, cfile.compress)
+ self.assertEqual(len(data), cfile.memlen)
+ return cfile
+
+ def _check_dtb(self, cbfs, offset=0x38, data=U_BOOT_DTB_DATA,
+ cbfs_offset=None):
+ """Check that the U-Boot dtb file is as expected
+
+ Args:
+ cbfs: CbfsReader object to check
+ offset: Expected offset of file
+ data: Expected data in file
+ cbfs_offset: Expected CBFS offset for file's data
+ """
+ self.assertIn('u-boot-dtb', cbfs.files)
+ cfile = cbfs.files['u-boot-dtb']
+ self.assertEqual('u-boot-dtb', cfile.name)
+ self.assertEqual(offset, cfile.offset)
+ if cbfs_offset is not None:
+ self.assertEqual(cbfs_offset, cfile.cbfs_offset)
+ self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
+ self.assertEqual(cbfs_util.TYPE_RAW, cfile.ftype)
+ self.assertEqual(cbfs_util.COMPRESS_NONE, cfile.compress)
+ self.assertEqual(len(U_BOOT_DTB_DATA), cfile.memlen)
+
+ def _check_raw(self, data, size, offset=0, arch=cbfs_util.ARCHITECTURE_X86):
+ """Check that two raw files are added as expected
+
+ Args:
+ data: Data to check
+ size: Expected ROM size
+ offset: Expected offset to first CBFS file
+ arch: Expected architecture
+ """
+ cbfs = self._check_hdr(data, size, offset=offset, arch=arch)
+ self._check_uboot(cbfs)
+ self._check_dtb(cbfs)
+
+ def _get_expected_cbfs(self, size, arch='x86', compress=None, base=None):
+ """Get the file created by cbfstool for a particular scenario
+
+ Args:
+ size: Size of the CBFS in bytes
+ arch: Architecture of the CBFS, as a string
+ compress: Compression to use, e.g. cbfs_util.COMPRESS_LZMA
+ base: Base address of file, or None to put it anywhere
+
+ Returns:
+ Resulting CBFS file, or None if cbfstool is not available
+ """
+ if not self.have_cbfstool or not self.have_lz4:
+ return None
+ cbfs_fname = os.path.join(self._indir, 'test.cbfs')
+ cbfs_util.cbfstool(cbfs_fname, 'create', '-m', arch, '-s', '%#x' % size)
+ if base:
+ base = [(1 << 32) - size + b for b in base]
+ cbfs_util.cbfstool(cbfs_fname, 'add', '-n', 'u-boot', '-t', 'raw',
+ '-c', compress and compress[0] or 'none',
+ '-f', tools.GetInputFilename(
+ compress and 'compress' or 'u-boot.bin'),
+ base=base[0] if base else None)
+ cbfs_util.cbfstool(cbfs_fname, 'add', '-n', 'u-boot-dtb', '-t', 'raw',
+ '-c', compress and compress[1] or 'none',
+ '-f', tools.GetInputFilename(
+ compress and 'compress' or 'u-boot.dtb'),
+ base=base[1] if base else None)
+ return cbfs_fname
+
+ def _compare_expected_cbfs(self, data, cbfstool_fname):
+ """Compare against what cbfstool creates
+
+ This compares what binman creates with what cbfstool creates for what
+ is proportedly the same thing.
+
+ Args:
+ data: CBFS created by binman
+ cbfstool_fname: CBFS created by cbfstool
+ """
+ if not self.have_cbfstool or not self.have_lz4:
+ return
+ expect = tools.ReadFile(cbfstool_fname)
+ if expect != data:
+ tools.WriteFile('/tmp/expect', expect)
+ tools.WriteFile('/tmp/actual', data)
+ print('diff -y <(xxd -g1 /tmp/expect) <(xxd -g1 /tmp/actual) | colordiff')
+ self.fail('cbfstool produced a different result')
+
+ def test_cbfs_functions(self):
+ """Test global functions of cbfs_util"""
+ self.assertEqual(cbfs_util.ARCHITECTURE_X86, cbfs_util.find_arch('x86'))
+ self.assertIsNone(cbfs_util.find_arch('bad-arch'))
+
+ self.assertEqual(cbfs_util.COMPRESS_LZMA, cbfs_util.find_compress('lzma'))
+ self.assertIsNone(cbfs_util.find_compress('bad-comp'))
+
+ def test_cbfstool_failure(self):
+ """Test failure to run cbfstool"""
+ if not self.have_cbfstool:
+ self.skipTest('No cbfstool available')
+ try:
+ # In verbose mode this test fails since stderr is not captured. Fix
+ # this by turning off verbosity.
+ old_verbose = cbfs_util.VERBOSE
+ cbfs_util.VERBOSE = False
+ with test_util.capture_sys_output() as (_stdout, stderr):
+ with self.assertRaises(Exception) as e:
+ cbfs_util.cbfstool('missing-file', 'bad-command')
+ finally:
+ cbfs_util.VERBOSE = old_verbose
+ self.assertIn('Unknown command', stderr.getvalue())
+ self.assertIn('Failed to run', str(e.exception))
+
+ def test_cbfs_raw(self):
+ """Test base handling of a Coreboot Filesystem (CBFS)"""
+ size = 0xb0
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA)
+ data = cbw.get_data()
+ self._check_raw(data, size)
+ cbfs_fname = self._get_expected_cbfs(size=size)
+ self._compare_expected_cbfs(data, cbfs_fname)
+
+ def test_cbfs_invalid_file_type(self):
+ """Check handling of an invalid file type when outputiing a CBFS"""
+ size = 0xb0
+ cbw = CbfsWriter(size)
+ cfile = cbw.add_file_raw('u-boot', U_BOOT_DATA)
+
+ # Change the type manually before generating the CBFS, and make sure
+ # that the generator complains
+ cfile.ftype = 0xff
+ with self.assertRaises(ValueError) as e:
+ cbw.get_data()
+ self.assertIn('Unknown type 0xff when writing', str(e.exception))
+
+ def test_cbfs_invalid_file_type_on_read(self):
+ """Check handling of an invalid file type when reading the CBFS"""
+ size = 0xb0
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+
+ data = cbw.get_data()
+
+ # Read in the first file header
+ cbr = cbfs_util.CbfsReader(data, read=False)
+ with io.BytesIO(data) as fd:
+ self.assertTrue(cbr._find_and_read_header(fd, len(data)))
+ pos = fd.tell()
+ hdr_data = fd.read(cbfs_util.FILE_HEADER_LEN)
+ magic, size, ftype, attr, offset = struct.unpack(
+ cbfs_util.FILE_HEADER_FORMAT, hdr_data)
+
+ # Create a new CBFS with a change to the file type
+ ftype = 0xff
+ newdata = data[:pos]
+ newdata += struct.pack(cbfs_util.FILE_HEADER_FORMAT, magic, size, ftype,
+ attr, offset)
+ newdata += data[pos + cbfs_util.FILE_HEADER_LEN:]
+
+ # Read in this CBFS and make sure that the reader complains
+ with self.assertRaises(ValueError) as e:
+ cbfs_util.CbfsReader(newdata)
+ self.assertIn('Unknown type 0xff when reading', str(e.exception))
+
+ def test_cbfs_no_space(self):
+ """Check handling of running out of space in the CBFS"""
+ size = 0x60
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ with self.assertRaises(ValueError) as e:
+ cbw.get_data()
+ self.assertIn('No space for header', str(e.exception))
+
+ def test_cbfs_no_space_skip(self):
+ """Check handling of running out of space in CBFS with file header"""
+ size = 0x5c
+ cbw = CbfsWriter(size, arch=cbfs_util.ARCHITECTURE_PPC64)
+ cbw._add_fileheader = True
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ with self.assertRaises(ValueError) as e:
+ cbw.get_data()
+ self.assertIn('No space for data before offset', str(e.exception))
+
+ def test_cbfs_no_space_pad(self):
+ """Check handling of running out of space in CBFS with file header"""
+ size = 0x70
+ cbw = CbfsWriter(size)
+ cbw._add_fileheader = True
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ with self.assertRaises(ValueError) as e:
+ cbw.get_data()
+ self.assertIn('No space for data before pad offset', str(e.exception))
+
+ def test_cbfs_bad_header_ptr(self):
+ """Check handling of a bad master-header pointer"""
+ size = 0x70
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ data = cbw.get_data()
+
+ # Add one to the pointer to make it invalid
+ newdata = data[:-4] + struct.pack('<I', cbw._header_offset + 1)
+
+ # We should still be able to find the master header by searching
+ with test_util.capture_sys_output() as (stdout, _stderr):
+ cbfs = cbfs_util.CbfsReader(newdata)
+ self.assertIn('Relative offset seems wrong', stdout.getvalue())
+ self.assertIn('u-boot', cbfs.files)
+ self.assertEqual(size, cbfs.rom_size)
+
+ def test_cbfs_bad_header(self):
+ """Check handling of a bad master header"""
+ size = 0x70
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ data = cbw.get_data()
+
+ # Drop most of the header and try reading the modified CBFS
+ newdata = data[:cbw._header_offset + 4]
+
+ with test_util.capture_sys_output() as (stdout, _stderr):
+ with self.assertRaises(ValueError) as e:
+ cbfs_util.CbfsReader(newdata)
+ self.assertIn('Relative offset seems wrong', stdout.getvalue())
+ self.assertIn('Cannot find master header', str(e.exception))
+
+ def test_cbfs_bad_file_header(self):
+ """Check handling of a bad file header"""
+ size = 0x70
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ data = cbw.get_data()
+
+ # Read in the CBFS master header (only), then stop
+ cbr = cbfs_util.CbfsReader(data, read=False)
+ with io.BytesIO(data) as fd:
+ self.assertTrue(cbr._find_and_read_header(fd, len(data)))
+ pos = fd.tell()
+
+ # Remove all but 4 bytes of the file headerm and try to read the file
+ newdata = data[:pos + 4]
+ with test_util.capture_sys_output() as (stdout, _stderr):
+ with io.BytesIO(newdata) as fd:
+ fd.seek(pos)
+ self.assertEqual(False, cbr._read_next_file(fd))
+ self.assertIn('File header at 0 ran out of data', stdout.getvalue())
+
+ def test_cbfs_bad_file_string(self):
+ """Check handling of an incomplete filename string"""
+ size = 0x70
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('16-characters xx', U_BOOT_DATA)
+ data = cbw.get_data()
+
+ # Read in the CBFS master header (only), then stop
+ cbr = cbfs_util.CbfsReader(data, read=False)
+ with io.BytesIO(data) as fd:
+ self.assertTrue(cbr._find_and_read_header(fd, len(data)))
+ pos = fd.tell()
+
+ # Create a new CBFS with only the first 16 bytes of the file name, then
+ # try to read the file
+ newdata = data[:pos + cbfs_util.FILE_HEADER_LEN + 16]
+ with test_util.capture_sys_output() as (stdout, _stderr):
+ with io.BytesIO(newdata) as fd:
+ fd.seek(pos)
+ self.assertEqual(False, cbr._read_next_file(fd))
+ self.assertIn('String at %x ran out of data' %
+ cbfs_util.FILE_HEADER_LEN, stdout.getvalue())
+
+ def test_cbfs_debug(self):
+ """Check debug output"""
+ size = 0x70
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ data = cbw.get_data()
+
+ try:
+ cbfs_util.DEBUG = True
+ with test_util.capture_sys_output() as (stdout, _stderr):
+ cbfs_util.CbfsReader(data)
+ self.assertEqual('name u-boot\ndata %s\n' % U_BOOT_DATA,
+ stdout.getvalue())
+ finally:
+ cbfs_util.DEBUG = False
+
+ def test_cbfs_bad_attribute(self):
+ """Check handling of bad attribute tag"""
+ if not self.have_lz4:
+ self.skipTest('lz4 --no-frame-crc not available')
+ size = 0x140
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', COMPRESS_DATA, None,
+ compress=cbfs_util.COMPRESS_LZ4)
+ data = cbw.get_data()
+
+ # Search the CBFS for the expected compression tag
+ with io.BytesIO(data) as fd:
+ while True:
+ pos = fd.tell()
+ tag, = struct.unpack('>I', fd.read(4))
+ if tag == cbfs_util.FILE_ATTR_TAG_COMPRESSION:
+ break
+
+ # Create a new CBFS with the tag changed to something invalid
+ newdata = data[:pos] + struct.pack('>I', 0x123) + data[pos + 4:]
+ with test_util.capture_sys_output() as (stdout, _stderr):
+ cbfs_util.CbfsReader(newdata)
+ self.assertEqual('Unknown attribute tag 123\n', stdout.getvalue())
+
+ def test_cbfs_missing_attribute(self):
+ """Check handling of an incomplete attribute tag"""
+ if not self.have_lz4:
+ self.skipTest('lz4 --no-frame-crc not available')
+ size = 0x140
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', COMPRESS_DATA, None,
+ compress=cbfs_util.COMPRESS_LZ4)
+ data = cbw.get_data()
+
+ # Read in the CBFS master header (only), then stop
+ cbr = cbfs_util.CbfsReader(data, read=False)
+ with io.BytesIO(data) as fd:
+ self.assertTrue(cbr._find_and_read_header(fd, len(data)))
+ pos = fd.tell()
+
+ # Create a new CBFS with only the first 4 bytes of the compression tag,
+ # then try to read the file
+ tag_pos = pos + cbfs_util.FILE_HEADER_LEN + cbfs_util.FILENAME_ALIGN
+ newdata = data[:tag_pos + 4]
+ with test_util.capture_sys_output() as (stdout, _stderr):
+ with io.BytesIO(newdata) as fd:
+ fd.seek(pos)
+ self.assertEqual(False, cbr._read_next_file(fd))
+ self.assertIn('Attribute tag at %x ran out of data' % tag_pos,
+ stdout.getvalue())
+
+ def test_cbfs_file_master_header(self):
+ """Check handling of a file containing a master header"""
+ size = 0x100
+ cbw = CbfsWriter(size)
+ cbw._add_fileheader = True
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ data = cbw.get_data()
+
+ cbr = cbfs_util.CbfsReader(data)
+ self.assertIn('u-boot', cbr.files)
+ self.assertEqual(size, cbr.rom_size)
+
+ def test_cbfs_arch(self):
+ """Test on non-x86 architecture"""
+ size = 0x100
+ cbw = CbfsWriter(size, arch=cbfs_util.ARCHITECTURE_PPC64)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA)
+ data = cbw.get_data()
+ self._check_raw(data, size, offset=0x40,
+ arch=cbfs_util.ARCHITECTURE_PPC64)
+
+ # Compare against what cbfstool creates
+ cbfs_fname = self._get_expected_cbfs(size=size, arch='ppc64')
+ self._compare_expected_cbfs(data, cbfs_fname)
+
+ def test_cbfs_stage(self):
+ """Tests handling of a Coreboot Filesystem (CBFS)"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
+ elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
+ elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
+
+ size = 0xb0
+ cbw = CbfsWriter(size)
+ cbw.add_file_stage('u-boot', tools.ReadFile(elf_fname))
+
+ data = cbw.get_data()
+ cbfs = self._check_hdr(data, size)
+ load = 0xfef20000
+ entry = load + 2
+
+ cfile = self._check_uboot(cbfs, cbfs_util.TYPE_STAGE, offset=0x28,
+ data=U_BOOT_DATA + U_BOOT_DTB_DATA)
+
+ self.assertEqual(entry, cfile.entry)
+ self.assertEqual(load, cfile.load)
+ self.assertEqual(len(U_BOOT_DATA) + len(U_BOOT_DTB_DATA),
+ cfile.data_len)
+
+ # Compare against what cbfstool creates
+ if self.have_cbfstool:
+ cbfs_fname = os.path.join(self._indir, 'test.cbfs')
+ cbfs_util.cbfstool(cbfs_fname, 'create', '-m', 'x86', '-s',
+ '%#x' % size)
+ cbfs_util.cbfstool(cbfs_fname, 'add-stage', '-n', 'u-boot',
+ '-f', elf_fname)
+ self._compare_expected_cbfs(data, cbfs_fname)
+
+ def test_cbfs_raw_compress(self):
+ """Test base handling of compressing raw files"""
+ if not self.have_lz4:
+ self.skipTest('lz4 --no-frame-crc not available')
+ size = 0x140
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', COMPRESS_DATA, None,
+ compress=cbfs_util.COMPRESS_LZ4)
+ cbw.add_file_raw('u-boot-dtb', COMPRESS_DATA, None,
+ compress=cbfs_util.COMPRESS_LZMA)
+ data = cbw.get_data()
+
+ cbfs = self._check_hdr(data, size)
+ self.assertIn('u-boot', cbfs.files)
+ cfile = cbfs.files['u-boot']
+ self.assertEqual(cfile.name, 'u-boot')
+ self.assertEqual(cfile.offset, 56)
+ self.assertEqual(cfile.data, COMPRESS_DATA)
+ self.assertEqual(cfile.ftype, cbfs_util.TYPE_RAW)
+ self.assertEqual(cfile.compress, cbfs_util.COMPRESS_LZ4)
+ self.assertEqual(cfile.memlen, len(COMPRESS_DATA))
+
+ self.assertIn('u-boot-dtb', cbfs.files)
+ cfile = cbfs.files['u-boot-dtb']
+ self.assertEqual(cfile.name, 'u-boot-dtb')
+ self.assertEqual(cfile.offset, 56)
+ self.assertEqual(cfile.data, COMPRESS_DATA)
+ self.assertEqual(cfile.ftype, cbfs_util.TYPE_RAW)
+ self.assertEqual(cfile.compress, cbfs_util.COMPRESS_LZMA)
+ self.assertEqual(cfile.memlen, len(COMPRESS_DATA))
+
+ cbfs_fname = self._get_expected_cbfs(size=size, compress=['lz4', 'lzma'])
+ self._compare_expected_cbfs(data, cbfs_fname)
+
+ def test_cbfs_raw_space(self):
+ """Test files with unused space in the CBFS"""
+ size = 0xf0
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA)
+ data = cbw.get_data()
+ self._check_raw(data, size)
+ cbfs_fname = self._get_expected_cbfs(size=size)
+ self._compare_expected_cbfs(data, cbfs_fname)
+
+ def test_cbfs_offset(self):
+ """Test a CBFS with files at particular offsets"""
+ size = 0x200
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA, 0x40)
+ cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA, 0x140)
+
+ data = cbw.get_data()
+ cbfs = self._check_hdr(data, size)
+ self._check_uboot(cbfs, ftype=cbfs_util.TYPE_RAW, offset=0x40,
+ cbfs_offset=0x40)
+ self._check_dtb(cbfs, offset=0x40, cbfs_offset=0x140)
+
+ cbfs_fname = self._get_expected_cbfs(size=size, base=(0x40, 0x140))
+ self._compare_expected_cbfs(data, cbfs_fname)
+
+ def test_cbfs_invalid_file_type_header(self):
+ """Check handling of an invalid file type when outputting a header"""
+ size = 0xb0
+ cbw = CbfsWriter(size)
+ cfile = cbw.add_file_raw('u-boot', U_BOOT_DATA, 0)
+
+ # Change the type manually before generating the CBFS, and make sure
+ # that the generator complains
+ cfile.ftype = 0xff
+ with self.assertRaises(ValueError) as e:
+ cbw.get_data()
+ self.assertIn('Unknown file type 0xff', str(e.exception))
+
+ def test_cbfs_offset_conflict(self):
+ """Test a CBFS with files that want to overlap"""
+ size = 0x200
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA, 0x40)
+ cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA, 0x80)
+
+ with self.assertRaises(ValueError) as e:
+ cbw.get_data()
+ self.assertIn('No space for data before pad offset', str(e.exception))
+
+ def test_cbfs_check_offset(self):
+ """Test that we can discover the offset of a file after writing it"""
+ size = 0xb0
+ cbw = CbfsWriter(size)
+ cbw.add_file_raw('u-boot', U_BOOT_DATA)
+ cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA)
+ data = cbw.get_data()
+
+ cbfs = cbfs_util.CbfsReader(data)
+ self.assertEqual(0x38, cbfs.files['u-boot'].cbfs_offset)
+ self.assertEqual(0x78, cbfs.files['u-boot-dtb'].cbfs_offset)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/binman/cmdline.py b/tools/binman/cmdline.py
index 3886d52..a43aec6 100644
--- a/tools/binman/cmdline.py
+++ b/tools/binman/cmdline.py
@@ -5,7 +5,7 @@
# Command-line parser for binman
#
-from optparse import OptionParser
+from argparse import ArgumentParser
def ParseArgs(argv):
"""Parse the binman command-line arguments
@@ -17,50 +17,83 @@
options provides access to the options (e.g. option.debug)
args is a list of string arguments
"""
- parser = OptionParser()
- parser.add_option('-a', '--entry-arg', type='string', action='append',
+ if '-H' in argv:
+ argv.append('build')
+
+ epilog = '''Binman creates and manipulate images for a board from a set of binaries. Binman is
+controlled by a description in the board device tree.'''
+
+ parser = ArgumentParser(epilog=epilog)
+ parser.add_argument('-B', '--build-dir', type=str, default='b',
+ help='Directory containing the build output')
+ parser.add_argument('-D', '--debug', action='store_true',
+ help='Enabling debugging (provides a full traceback on error)')
+ parser.add_argument('-H', '--full-help', action='store_true',
+ default=False, help='Display the README file')
+ parser.add_argument('--toolpath', type=str, action='append',
+ help='Add a path to the directories containing tools')
+ parser.add_argument('-v', '--verbosity', default=1,
+ type=int, help='Control verbosity: 0=silent, 1=warnings, 2=notices, '
+ '3=info, 4=detail, 5=debug')
+
+ subparsers = parser.add_subparsers(dest='cmd')
+
+ build_parser = subparsers.add_parser('build', help='Build firmware image')
+ build_parser.add_argument('-a', '--entry-arg', type=str, action='append',
help='Set argument value arg=value')
- parser.add_option('-b', '--board', type='string',
+ build_parser.add_argument('-b', '--board', type=str,
help='Board name to build')
- parser.add_option('-B', '--build-dir', type='string', default='b',
- help='Directory containing the build output')
- parser.add_option('-d', '--dt', type='string',
+ build_parser.add_argument('-d', '--dt', type=str,
help='Configuration file (.dtb) to use')
- parser.add_option('-D', '--debug', action='store_true',
- help='Enabling debugging (provides a full traceback on error)')
- parser.add_option('-E', '--entry-docs', action='store_true',
- help='Write out entry documentation (see README.entries)')
- parser.add_option('--fake-dtb', action='store_true',
+ build_parser.add_argument('--fake-dtb', action='store_true',
help='Use fake device tree contents (for testing only)')
- parser.add_option('-i', '--image', type='string', action='append',
+ build_parser.add_argument('-i', '--image', type=str, action='append',
help='Image filename to build (if not specified, build all)')
- parser.add_option('-I', '--indir', action='append',
- help='Add a path to a directory to use for input files')
- parser.add_option('-H', '--full-help', action='store_true',
- default=False, help='Display the README file')
- parser.add_option('-m', '--map', action='store_true',
+ build_parser.add_argument('-I', '--indir', action='append',
+ help='Add a path to the list of directories to use for input files')
+ build_parser.add_argument('-m', '--map', action='store_true',
default=False, help='Output a map file for each image')
- parser.add_option('-O', '--outdir', type='string',
+ build_parser.add_argument('-O', '--outdir', type=str,
action='store', help='Path to directory to use for intermediate and '
'output files')
- parser.add_option('-p', '--preserve', action='store_true',\
+ build_parser.add_argument('-p', '--preserve', action='store_true',\
help='Preserve temporary output directory even if option -O is not '
'given')
- parser.add_option('-P', '--processes', type=int,
- help='set number of processes to use for running tests')
- parser.add_option('-t', '--test', action='store_true',
- default=False, help='run tests')
- parser.add_option('-T', '--test-coverage', action='store_true',
- default=False, help='run tests and check for 100% coverage')
- parser.add_option('-u', '--update-fdt', action='store_true',
+ build_parser.add_argument('-u', '--update-fdt', action='store_true',
default=False, help='Update the binman node with offset/size info')
- parser.add_option('-v', '--verbosity', default=1,
- type='int', help='Control verbosity: 0=silent, 1=progress, 3=full, '
- '4=debug')
- parser.usage += """
+ entry_parser = subparsers.add_parser('entry-docs',
+ help='Write out entry documentation (see README.entries)')
+
+ list_parser = subparsers.add_parser('ls', help='List files in an image')
+ list_parser.add_argument('-i', '--image', type=str, required=True,
+ help='Image filename to list')
+ list_parser.add_argument('paths', type=str, nargs='*',
+ help='Paths within file to list (wildcard)')
+
+ extract_parser = subparsers.add_parser('extract',
+ help='Extract files from an image')
+ extract_parser.add_argument('-i', '--image', type=str, required=True,
+ help='Image filename to extract')
+ extract_parser.add_argument('-f', '--filename', type=str,
+ help='Output filename to write to')
+ extract_parser.add_argument('-O', '--outdir', type=str, default='',
+ help='Path to directory to use for output files')
+ extract_parser.add_argument('paths', type=str, nargs='*',
+ help='Paths within file to extract (wildcard)')
+ extract_parser.add_argument('-U', '--uncompressed', action='store_true',
+ help='Output raw uncompressed data for compressed entries')
-Create images for a board from a set of binaries. It is controlled by a
-description in the board device tree."""
+ test_parser = subparsers.add_parser('test', help='Run tests')
+ test_parser.add_argument('-P', '--processes', type=int,
+ help='set number of processes to use for running tests')
+ test_parser.add_argument('-T', '--test-coverage', action='store_true',
+ default=False, help='run tests and check for 100%% coverage')
+ test_parser.add_argument('-X', '--test-preserve-dirs', action='store_true',
+ help='Preserve and display test-created input directories; also '
+ 'preserve the output directory if a single test is run (pass test '
+ 'name at the end of the command line')
+ test_parser.add_argument('tests', nargs='*',
+ help='Test names to run (omit for all)')
return parser.parse_args(argv)
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 20186ee..dc898be 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -12,6 +12,7 @@
import sys
import tools
+import cbfs_util
import command
import elf
from image import Image
@@ -66,19 +67,120 @@
from entry import Entry
Entry.WriteDocs(modules, test_missing)
-def Binman(options, args):
+
+def ListEntries(image_fname, entry_paths):
+ """List the entries in an image
+
+ This decodes the supplied image and displays a table of entries from that
+ image, preceded by a header.
+
+ Args:
+ image_fname: Image filename to process
+ entry_paths: List of wildcarded paths (e.g. ['*dtb*', 'u-boot*',
+ 'section/u-boot'])
+ """
+ image = Image.FromFile(image_fname)
+
+ entries, lines, widths = image.GetListEntries(entry_paths)
+
+ num_columns = len(widths)
+ for linenum, line in enumerate(lines):
+ if linenum == 1:
+ # Print header line
+ print('-' * (sum(widths) + num_columns * 2))
+ out = ''
+ for i, item in enumerate(line):
+ width = -widths[i]
+ if item.startswith('>'):
+ width = -width
+ item = item[1:]
+ txt = '%*s ' % (width, item)
+ out += txt
+ print(out.rstrip())
+
+
+def ReadEntry(image_fname, entry_path, decomp=True):
+ """Extract an entry from an image
+
+ This extracts the data from a particular entry in an image
+
+ Args:
+ image_fname: Image filename to process
+ entry_path: Path to entry to extract
+ decomp: True to return uncompressed data, if the data is compress
+ False to return the raw data
+
+ Returns:
+ data extracted from the entry
+ """
+ image = Image.FromFile(image_fname)
+ entry = image.FindEntryPath(entry_path)
+ return entry.ReadData(decomp)
+
+
+def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
+ decomp=True):
+ """Extract the data from one or more entries and write it to files
+
+ Args:
+ image_fname: Image filename to process
+ output_fname: Single output filename to use if extracting one file, None
+ otherwise
+ outdir: Output directory to use (for any number of files), else None
+ entry_paths: List of entry paths to extract
+ decomp: True to compress the entry data
+
+ Returns:
+ List of EntryInfo records that were written
+ """
+ image = Image.FromFile(image_fname)
+
+ # Output an entry to a single file, as a special case
+ if output_fname:
+ if not entry_paths:
+ raise ValueError('Must specify an entry path to write with -o')
+ if len(entry_paths) != 1:
+ raise ValueError('Must specify exactly one entry path to write with -o')
+ entry = image.FindEntryPath(entry_paths[0])
+ data = entry.ReadData(decomp)
+ tools.WriteFile(output_fname, data)
+ tout.Notice("Wrote %#x bytes to file '%s'" % (len(data), output_fname))
+ return
+
+ # Otherwise we will output to a path given by the entry path of each entry.
+ # This means that entries will appear in subdirectories if they are part of
+ # a sub-section.
+ einfos = image.GetListEntries(entry_paths)[0]
+ tout.Notice('%d entries match and will be written' % len(einfos))
+ for einfo in einfos:
+ entry = einfo.entry
+ data = entry.ReadData(decomp)
+ path = entry.GetPath()[1:]
+ fname = os.path.join(outdir, path)
+
+ # If this entry has children, create a directory for it and put its
+ # data in a file called 'root' in that directory
+ if entry.GetEntries():
+ if not os.path.exists(fname):
+ os.makedirs(fname)
+ fname = os.path.join(fname, 'root')
+ tout.Notice("Write entry '%s' to '%s'" % (entry.GetPath(), fname))
+ tools.WriteFile(fname, data)
+ return einfos
+
+
+def Binman(args):
"""The main control code for binman
This assumes that help and test options have already been dealt with. It
deals with the core task of building images.
Args:
- options: Command line options object
- args: Command line arguments (list of strings)
+ args: Command line arguments Namespace object
"""
global images
- if options.full_help:
+ if args.full_help:
pager = os.getenv('PAGER')
if not pager:
pager = 'more'
@@ -87,18 +189,31 @@
command.Run(pager, fname)
return 0
+ if args.cmd == 'ls':
+ ListEntries(args.image, args.paths)
+ return 0
+
+ if args.cmd == 'extract':
+ try:
+ tools.PrepareOutputDir(None)
+ ExtractEntries(args.image, args.filename, args.outdir, args.paths,
+ not args.uncompressed)
+ finally:
+ tools.FinaliseOutputDir()
+ return 0
+
# Try to figure out which device tree contains our image description
- if options.dt:
- dtb_fname = options.dt
+ if args.dt:
+ dtb_fname = args.dt
else:
- board = options.board
+ board = args.board
if not board:
raise ValueError('Must provide a board to process (use -b <board>)')
- board_pathname = os.path.join(options.build_dir, board)
+ board_pathname = os.path.join(args.build_dir, board)
dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
- if not options.indir:
- options.indir = ['.']
- options.indir.append(board_pathname)
+ if not args.indir:
+ args.indir = ['.']
+ args.indir.append(board_pathname)
try:
# Import these here in case libfdt.py is not available, in which case
@@ -106,13 +221,15 @@
import fdt
import fdt_util
- tout.Init(options.verbosity)
- elf.debug = options.debug
- state.use_fake_dtb = options.fake_dtb
+ tout.Init(args.verbosity)
+ elf.debug = args.debug
+ cbfs_util.VERBOSE = args.verbosity > 2
+ state.use_fake_dtb = args.fake_dtb
try:
- tools.SetInputDirs(options.indir)
- tools.PrepareOutputDir(options.outdir, options.preserve)
- state.SetEntryArgs(options.entry_arg)
+ tools.SetInputDirs(args.indir)
+ tools.PrepareOutputDir(args.outdir, args.preserve)
+ tools.SetToolPaths(args.toolpath)
+ state.SetEntryArgs(args.entry_arg)
# Get the device tree ready by compiling it and copying the compiled
# output into a file in our output directly. Then scan it for use
@@ -129,16 +246,16 @@
images = _ReadImageDesc(node)
- if options.image:
+ if args.image:
skip = []
new_images = OrderedDict()
for name, image in images.items():
- if name in options.image:
+ if name in args.image:
new_images[name] = image
else:
skip.append(name)
images = new_images
- if skip and options.verbosity >= 2:
+ if skip and args.verbosity >= 2:
print('Skipping images: %s' % ', '.join(skip))
state.Prepare(images, dtb)
@@ -152,7 +269,7 @@
# entry offsets remain the same.
for image in images.values():
image.ExpandEntries()
- if options.update_fdt:
+ if args.update_fdt:
image.AddMissingProperties()
image.ProcessFdt(dtb)
@@ -168,24 +285,45 @@
# completed and written, but that does not seem important.
image.GetEntryContents()
image.GetEntryOffsets()
- try:
- image.PackEntries()
- image.CheckSize()
- image.CheckEntries()
- except Exception as e:
- if options.map:
- fname = image.WriteMap()
- print("Wrote map file '%s' to show errors" % fname)
- raise
- image.SetImagePos()
- if options.update_fdt:
- image.SetCalculatedProperties()
- for dtb_item in state.GetFdts():
- dtb_item.Sync()
- image.ProcessEntryContents()
+
+ # We need to pack the entries to figure out where everything
+ # should be placed. This sets the offset/size of each entry.
+ # However, after packing we call ProcessEntryContents() which
+ # may result in an entry changing size. In that case we need to
+ # do another pass. Since the device tree often contains the
+ # final offset/size information we try to make space for this in
+ # AddMissingProperties() above. However, if the device is
+ # compressed we cannot know this compressed size in advance,
+ # since changing an offset from 0x100 to 0x104 (for example) can
+ # alter the compressed size of the device tree. So we need a
+ # third pass for this.
+ passes = 3
+ for pack_pass in range(passes):
+ try:
+ image.PackEntries()
+ image.CheckSize()
+ image.CheckEntries()
+ except Exception as e:
+ if args.map:
+ fname = image.WriteMap()
+ print("Wrote map file '%s' to show errors" % fname)
+ raise
+ image.SetImagePos()
+ if args.update_fdt:
+ image.SetCalculatedProperties()
+ for dtb_item in state.GetFdts():
+ dtb_item.Sync()
+ sizes_ok = image.ProcessEntryContents()
+ if sizes_ok:
+ break
+ image.ResetForPack()
+ if not sizes_ok:
+ image.Raise('Entries expanded after packing (tried %s passes)' %
+ passes)
+
image.WriteSymbols()
image.BuildImage()
- if options.map:
+ if args.map:
image.WriteMap()
# Write the updated FDTs to our output files
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
index 828681d..8147b34 100644
--- a/tools/binman/elf.py
+++ b/tools/binman/elf.py
@@ -5,19 +5,39 @@
# Handle various things related to ELF images
#
+from __future__ import print_function
+
from collections import namedtuple, OrderedDict
import command
+import io
import os
import re
+import shutil
import struct
+import tempfile
import tools
+ELF_TOOLS = True
+try:
+ from elftools.elf.elffile import ELFFile
+ from elftools.elf.sections import SymbolTableSection
+except: # pragma: no cover
+ ELF_TOOLS = False
+
# This is enabled from control.py
debug = False
Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak'])
+# Information about an ELF file:
+# data: Extracted program contents of ELF file (this would be loaded by an
+# ELF loader when reading this file
+# load: Load address of code
+# entry: Entry address of code
+# memsize: Number of bytes in memory occupied by loading this ELF file
+ElfInfo = namedtuple('ElfInfo', ['data', 'load', 'entry', 'memsize'])
+
def GetSymbols(fname, patterns):
"""Get the symbols from an ELF file
@@ -128,3 +148,157 @@
(msg, name, offset, value, len(value_bytes)))
entry.data = (entry.data[:offset] + value_bytes +
entry.data[offset + sym.size:])
+
+def MakeElf(elf_fname, text, data):
+ """Make an elf file with the given data in a single section
+
+ The output file has a several section including '.text' and '.data',
+ containing the info provided in arguments.
+
+ Args:
+ elf_fname: Output filename
+ text: Text (code) to put in the file's .text section
+ data: Data to put in the file's .data section
+ """
+ outdir = tempfile.mkdtemp(prefix='binman.elf.')
+ s_file = os.path.join(outdir, 'elf.S')
+
+ # Spilt the text into two parts so that we can make the entry point two
+ # bytes after the start of the text section
+ text_bytes1 = ['\t.byte\t%#x' % tools.ToByte(byte) for byte in text[:2]]
+ text_bytes2 = ['\t.byte\t%#x' % tools.ToByte(byte) for byte in text[2:]]
+ data_bytes = ['\t.byte\t%#x' % tools.ToByte(byte) for byte in data]
+ with open(s_file, 'w') as fd:
+ print('''/* Auto-generated C program to produce an ELF file for testing */
+
+.section .text
+.code32
+.globl _start
+.type _start, @function
+%s
+_start:
+%s
+.ident "comment"
+
+.comm fred,8,4
+
+.section .empty
+.globl _empty
+_empty:
+.byte 1
+
+.globl ernie
+.data
+.type ernie, @object
+.size ernie, 4
+ernie:
+%s
+''' % ('\n'.join(text_bytes1), '\n'.join(text_bytes2), '\n'.join(data_bytes)),
+ file=fd)
+ lds_file = os.path.join(outdir, 'elf.lds')
+
+ # Use a linker script to set the alignment and text address.
+ with open(lds_file, 'w') as fd:
+ print('''/* Auto-generated linker script to produce an ELF file for testing */
+
+PHDRS
+{
+ text PT_LOAD ;
+ data PT_LOAD ;
+ empty PT_LOAD FLAGS ( 6 ) ;
+ note PT_NOTE ;
+}
+
+SECTIONS
+{
+ . = 0xfef20000;
+ ENTRY(_start)
+ .text . : SUBALIGN(0)
+ {
+ *(.text)
+ } :text
+ .data : {
+ *(.data)
+ } :data
+ _bss_start = .;
+ .empty : {
+ *(.empty)
+ } :empty
+ .note : {
+ *(.comment)
+ } :note
+ .bss _bss_start (OVERLAY) : {
+ *(.bss)
+ }
+}
+''', file=fd)
+ # -static: Avoid requiring any shared libraries
+ # -nostdlib: Don't link with C library
+ # -Wl,--build-id=none: Don't generate a build ID, so that we just get the
+ # text section at the start
+ # -m32: Build for 32-bit x86
+ # -T...: Specifies the link script, which sets the start address
+ stdout = command.Output('cc', '-static', '-nostdlib', '-Wl,--build-id=none',
+ '-m32','-T', lds_file, '-o', elf_fname, s_file)
+ shutil.rmtree(outdir)
+
+def DecodeElf(data, location):
+ """Decode an ELF file and return information about it
+
+ Args:
+ data: Data from ELF file
+ location: Start address of data to return
+
+ Returns:
+ ElfInfo object containing information about the decoded ELF file
+ """
+ file_size = len(data)
+ with io.BytesIO(data) as fd:
+ elf = ELFFile(fd)
+ data_start = 0xffffffff;
+ data_end = 0;
+ mem_end = 0;
+ virt_to_phys = 0;
+
+ for i in range(elf.num_segments()):
+ segment = elf.get_segment(i)
+ if segment['p_type'] != 'PT_LOAD' or not segment['p_memsz']:
+ skipped = 1 # To make code-coverage see this line
+ continue
+ start = segment['p_paddr']
+ mend = start + segment['p_memsz']
+ rend = start + segment['p_filesz']
+ data_start = min(data_start, start)
+ data_end = max(data_end, rend)
+ mem_end = max(mem_end, mend)
+ if not virt_to_phys:
+ virt_to_phys = segment['p_paddr'] - segment['p_vaddr']
+
+ output = bytearray(data_end - data_start)
+ for i in range(elf.num_segments()):
+ segment = elf.get_segment(i)
+ if segment['p_type'] != 'PT_LOAD' or not segment['p_memsz']:
+ skipped = 1 # To make code-coverage see this line
+ continue
+ start = segment['p_paddr']
+ offset = 0
+ if start < location:
+ offset = location - start
+ start = location
+ # A legal ELF file can have a program header with non-zero length
+ # but zero-length file size and a non-zero offset which, added
+ # together, are greater than input->size (i.e. the total file size).
+ # So we need to not even test in the case that p_filesz is zero.
+ # Note: All of this code is commented out since we don't have a test
+ # case for it.
+ size = segment['p_filesz']
+ #if not size:
+ #continue
+ #end = segment['p_offset'] + segment['p_filesz']
+ #if end > file_size:
+ #raise ValueError('Underflow copying out the segment. File has %#x bytes left, segment end is %#x\n',
+ #file_size, end)
+ output[start - data_start:start - data_start + size] = (
+ segment.data()[offset:])
+ return ElfInfo(output, data_start, elf.header['e_entry'] + virt_to_phys,
+ mem_end - data_start)
diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py
index 42d94cb..e250637 100644
--- a/tools/binman/elf_test.py
+++ b/tools/binman/elf_test.py
@@ -5,9 +5,12 @@
# Test for the elf module
import os
+import shutil
import sys
+import tempfile
import unittest
+import command
import elf
import test_util
import tools
@@ -136,6 +139,44 @@
elf.debug = False
self.assertTrue(len(stdout.getvalue()) > 0)
+ def testMakeElf(self):
+ """Test for the MakeElf function"""
+ outdir = tempfile.mkdtemp(prefix='elf.')
+ expected_text = b'1234'
+ expected_data = b'wxyz'
+ elf_fname = os.path.join(outdir, 'elf')
+ bin_fname = os.path.join(outdir, 'elf')
+
+ # Make an Elf file and then convert it to a fkat binary file. This
+ # should produce the original data.
+ elf.MakeElf(elf_fname, expected_text, expected_data)
+ stdout = command.Output('objcopy', '-O', 'binary', elf_fname, bin_fname)
+ with open(bin_fname, 'rb') as fd:
+ data = fd.read()
+ self.assertEqual(expected_text + expected_data, data)
+ shutil.rmtree(outdir)
+
+ def testDecodeElf(self):
+ """Test for the MakeElf function"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
+ outdir = tempfile.mkdtemp(prefix='elf.')
+ expected_text = b'1234'
+ expected_data = b'wxyz'
+ elf_fname = os.path.join(outdir, 'elf')
+ elf.MakeElf(elf_fname, expected_text, expected_data)
+ data = tools.ReadFile(elf_fname)
+
+ load = 0xfef20000
+ entry = load + 2
+ expected = expected_text + expected_data
+ self.assertEqual(elf.ElfInfo(expected, load, entry, len(expected)),
+ elf.DecodeElf(data, 0))
+ self.assertEqual(elf.ElfInfo(b'\0\0' + expected[2:],
+ load, entry, len(expected)),
+ elf.DecodeElf(data, load + 2))
+ #shutil.rmtree(outdir)
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index d842d89..1c382f3 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -23,6 +23,7 @@
import fdt_util
import state
import tools
+import tout
modules = {}
@@ -33,6 +34,10 @@
# device-tree properties.
EntryArg = namedtuple('EntryArg', ['name', 'datatype'])
+# Information about an entry for use when displaying summaries
+EntryInfo = namedtuple('EntryInfo', ['indent', 'name', 'etype', 'size',
+ 'image_pos', 'uncomp_size', 'offset',
+ 'entry'])
class Entry(object):
"""An Entry in the section
@@ -51,6 +56,8 @@
offset: Offset of entry within the section, None if not known yet (in
which case it will be calculated by Pack())
size: Entry size in bytes, None if not known
+ uncomp_size: Size of uncompressed data in bytes, if the entry is
+ compressed, else None
contents_size: Size of contents in bytes, 0 by default
align: Entry start offset alignment, or None
align_size: Entry size alignment, or None
@@ -58,6 +65,9 @@
pad_before: Number of pad bytes before the contents, 0 if none
pad_after: Number of pad bytes after the contents, 0 if none
data: Contents of entry (string of bytes)
+ compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
+ orig_offset: Original offset value read from node
+ orig_size: Original size value read from node
"""
def __init__(self, section, etype, node, read_node=True, name_prefix=''):
self.section = section
@@ -66,6 +76,7 @@
self.name = node and (name_prefix + node.name) or 'none'
self.offset = None
self.size = None
+ self.uncomp_size = None
self.data = None
self.contents_size = 0
self.align = None
@@ -76,15 +87,15 @@
self.offset_unset = False
self.image_pos = None
self._expand_size = False
+ self.compress = 'none'
if read_node:
self.ReadNode()
@staticmethod
- def Lookup(section, node_path, etype):
+ def Lookup(node_path, etype):
"""Look up the entry class for a node.
Args:
- section: Section object containing this node
node_node: Path name of Node object containing information about
the entry to create (used for errors)
etype: Entry type to use
@@ -135,7 +146,7 @@
"""
if not etype:
etype = fdt_util.GetString(node, 'type', node.name)
- obj = Entry.Lookup(section, node.path, etype)
+ obj = Entry.Lookup(node.path, etype)
# Call its constructor to get the object we want.
return obj(section, etype, node)
@@ -149,6 +160,14 @@
self.Raise("Please use 'offset' instead of 'pos'")
self.offset = fdt_util.GetInt(self._node, 'offset')
self.size = fdt_util.GetInt(self._node, 'size')
+ self.orig_offset = self.offset
+ self.orig_size = self.size
+
+ # These should not be set in input files, but are set in an FDT map,
+ # which is also read by this code.
+ self.image_pos = fdt_util.GetInt(self._node, 'image-pos')
+ self.uncomp_size = fdt_util.GetInt(self._node, 'uncomp-size')
+
self.align = fdt_util.GetInt(self._node, 'align')
if tools.NotPowerOfTwo(self.align):
raise ValueError("Node '%s': Alignment %s must be a power of two" %
@@ -157,8 +176,8 @@
self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
self.align_size = fdt_util.GetInt(self._node, 'align-size')
if tools.NotPowerOfTwo(self.align_size):
- raise ValueError("Node '%s': Alignment size %s must be a power "
- "of two" % (self._node.path, self.align_size))
+ self.Raise("Alignment size %s must be a power of two" %
+ self.align_size)
self.align_end = fdt_util.GetInt(self._node, 'align-end')
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
@@ -188,6 +207,8 @@
for prop in ['offset', 'size', 'image-pos']:
if not prop in self._node.props:
state.AddZeroProp(self._node, prop)
+ if self.compress != 'none':
+ state.AddZeroProp(self._node, 'uncomp-size')
err = state.CheckAddHashProp(self._node)
if err:
self.Raise(err)
@@ -196,8 +217,10 @@
"""Set the value of device-tree properties calculated by binman"""
state.SetInt(self._node, 'offset', self.offset)
state.SetInt(self._node, 'size', self.size)
- state.SetInt(self._node, 'image-pos',
- self.image_pos - self.section.GetRootSkipAtStart())
+ base = self.section.GetRootSkipAtStart() if self.section else 0
+ state.SetInt(self._node, 'image-pos', self.image_pos - base)
+ if self.uncomp_size is not None:
+ state.SetInt(self._node, 'uncomp-size', self.uncomp_size)
state.CheckSetHashValue(self._node, self.GetData)
def ProcessFdt(self, fdt):
@@ -229,26 +252,36 @@
This sets both the data and content_size properties
Args:
- data: Data to set to the contents (string)
+ data: Data to set to the contents (bytes)
"""
self.data = data
self.contents_size = len(self.data)
def ProcessContentsUpdate(self, data):
- """Update the contens of an entry, after the size is fixed
+ """Update the contents of an entry, after the size is fixed
- This checks that the new data is the same size as the old.
+ This checks that the new data is the same size as the old. If the size
+ has changed, this triggers a re-run of the packing algorithm.
Args:
- data: Data to set to the contents (string)
+ data: Data to set to the contents (bytes)
Raises:
ValueError if the new data size is not the same as the old
"""
- if len(data) != self.contents_size:
+ size_ok = True
+ new_size = len(data)
+ if state.AllowEntryExpansion():
+ if new_size > self.contents_size:
+ tout.Debug("Entry '%s' size change from %#x to %#x" % (
+ self._node.path, self.contents_size, new_size))
+ # self.data will indicate the new size needed
+ size_ok = False
+ elif new_size != self.contents_size:
self.Raise('Cannot update entry size from %d to %d' %
- (len(data), self.contents_size))
+ (self.contents_size, new_size))
self.SetContents(data)
+ return size_ok
def ObtainContents(self):
"""Figure out the contents of an entry.
@@ -260,6 +293,11 @@
# No contents by default: subclasses can implement this
return True
+ def ResetForPack(self):
+ """Reset offset/size fields so that packing can be done again"""
+ self.offset = self.orig_offset
+ self.size = self.orig_size
+
def Pack(self, offset):
"""Figure out how to pack the entry into the section
@@ -355,11 +393,34 @@
return self.data
def GetOffsets(self):
+ """Get the offsets for siblings
+
+ Some entry types can contain information about the position or size of
+ other entries. An example of this is the Intel Flash Descriptor, which
+ knows where the Intel Management Engine section should go.
+
+ If this entry knows about the position of other entries, it can specify
+ this by returning values here
+
+ Returns:
+ Dict:
+ key: Entry type
+ value: List containing position and size of the given entry
+ type. Either can be None if not known
+ """
return {}
+ def SetOffsetSize(self, offset, size):
+ """Set the offset and/or size of an entry
+
- def SetOffsetSize(self, pos, size):
- self.offset = pos
- self.size = size
+ Args:
+ offset: New offset, or None to leave alone
+ size: New size, or None to leave alone
+ """
+ if offset is not None:
+ self.offset = offset
+ if size is not None:
+ self.size = size
def SetImagePos(self, image_pos):
"""Set the position in the image
@@ -370,7 +431,22 @@
self.image_pos = image_pos + self.offset
def ProcessContents(self):
- pass
+ """Do any post-packing updates of entry contents
+
+ This function should call ProcessContentsUpdate() to update the entry
+ contents, if necessary, returning its return value here.
+
+ Args:
+ data: Data to set to the contents (bytes)
+
+ Returns:
+ True if the new data size is OK, False if expansion is needed
+
+ Raises:
+ ValueError if the new data size is not the same as the old and
+ state.AllowEntryExpansion() is False
+ """
+ return True
def WriteSymbols(self, section):
"""Write symbol values into binary files for access at run time
@@ -482,7 +558,9 @@
modules.remove('_testing')
missing = []
for name in modules:
- module = Entry.Lookup(name, name, name)
+ if name.startswith('__'):
+ continue
+ module = Entry.Lookup(name, name)
docs = getattr(module, '__doc__')
if test_missing == name:
docs = None
@@ -529,3 +607,76 @@
# the data grows. This should not fail, but check it to be sure.
if not self.ObtainContents():
self.Raise('Cannot obtain contents when expanding entry')
+
+ def HasSibling(self, name):
+ """Check if there is a sibling of a given name
+
+ Returns:
+ True if there is an entry with this name in the the same section,
+ else False
+ """
+ return name in self.section.GetEntries()
+
+ def GetSiblingImagePos(self, name):
+ """Return the image position of the given sibling
+
+ Returns:
+ Image position of sibling, or None if the sibling has no position,
+ or False if there is no such sibling
+ """
+ if not self.HasSibling(name):
+ return False
+ return self.section.GetEntries()[name].image_pos
+
+ @staticmethod
+ def AddEntryInfo(entries, indent, name, etype, size, image_pos,
+ uncomp_size, offset, entry):
+ """Add a new entry to the entries list
+
+ Args:
+ entries: List (of EntryInfo objects) to add to
+ indent: Current indent level to add to list
+ name: Entry name (string)
+ etype: Entry type (string)
+ size: Entry size in bytes (int)
+ image_pos: Position within image in bytes (int)
+ uncomp_size: Uncompressed size if the entry uses compression, else
+ None
+ offset: Entry offset within parent in bytes (int)
+ entry: Entry object
+ """
+ entries.append(EntryInfo(indent, name, etype, size, image_pos,
+ uncomp_size, offset, entry))
+
+ def ListEntries(self, entries, indent):
+ """Add files in this entry to the list of entries
+
+ This can be overridden by subclasses which need different behaviour.
+
+ Args:
+ entries: List (of EntryInfo objects) to add to
+ indent: Current indent level to add to list
+ """
+ self.AddEntryInfo(entries, indent, self.name, self.etype, self.size,
+ self.image_pos, self.uncomp_size, self.offset, self)
+
+ def ReadData(self, decomp=True):
+ """Read the data for an entry from the image
+
+ This is used when the image has been read in and we want to extract the
+ data for a particular entry from that image.
+
+ Args:
+ decomp: True to decompress any compressed data before returning it;
+ False to return the raw, uncompressed data
+
+ Returns:
+ Entry data (bytes)
+ """
+ # Use True here so that we get an uncompressed section to work from,
+ # although compressed sections are currently not supported
+ data = self.section.ReadData(True)
+ tout.Info('%s: Reading data from offset %#x-%#x, size %#x (avail %#x)' %
+ (self.GetPath(), self.offset, self.offset + self.size,
+ self.size, len(data)))
+ return data[self.offset:self.offset + self.size]
diff --git a/tools/binman/entry_test.py b/tools/binman/entry_test.py
index b30a7be..b6ad3ed 100644
--- a/tools/binman/entry_test.py
+++ b/tools/binman/entry_test.py
@@ -9,12 +9,11 @@
import sys
import unittest
+import entry
import fdt
import fdt_util
import tools
-entry = None
-
class TestEntry(unittest.TestCase):
def setUp(self):
tools.PrepareOutputDir(None)
@@ -29,16 +28,7 @@
dtb = fdt.FdtScan(fname)
return dtb.GetNode('/binman/u-boot')
- def test1EntryNoImportLib(self):
- """Test that we can import Entry subclassess successfully"""
-
- sys.modules['importlib'] = None
- global entry
- import entry
- entry.Entry.Create(None, self.GetNode(), 'u-boot')
-
- def test2EntryImportLib(self):
- del sys.modules['importlib']
+ def _ReloadEntry(self):
global entry
if entry:
if sys.version_info[0] >= 3:
@@ -48,8 +38,21 @@
reload(entry)
else:
import entry
+
+ def test1EntryNoImportLib(self):
+ """Test that we can import Entry subclassess successfully"""
+ sys.modules['importlib'] = None
+ global entry
+ self._ReloadEntry()
+ entry.Entry.Create(None, self.GetNode(), 'u-boot')
+ self.assertFalse(entry.have_importlib)
+
+ def test2EntryImportLib(self):
+ del sys.modules['importlib']
+ global entry
+ self._ReloadEntry()
entry.Entry.Create(None, self.GetNode(), 'u-boot-spl')
- del entry
+ self.assertTrue(entry.have_importlib)
def testEntryContents(self):
"""Test the Entry bass class"""
@@ -59,7 +62,6 @@
def testUnknownEntry(self):
"""Test that unknown entry types are detected"""
- import entry
Node = collections.namedtuple('Node', ['name', 'path'])
node = Node('invalid-name', 'invalid-path')
with self.assertRaises(ValueError) as e:
@@ -69,7 +71,6 @@
def testUniqueName(self):
"""Test Entry.GetUniqueName"""
- import entry
Node = collections.namedtuple('Node', ['name', 'parent'])
base_node = Node('root', None)
base_entry = entry.Entry(None, None, base_node, read_node=False)
@@ -80,7 +81,6 @@
def testGetDefaultFilename(self):
"""Trivial test for this base class function"""
- import entry
base_entry = entry.Entry(None, None, None, read_node=False)
self.assertIsNone(base_entry.GetDefaultFilename())
diff --git a/tools/binman/etype/__init__.py b/tools/binman/etype/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/binman/etype/__init__.py
diff --git a/tools/binman/etype/_testing.py b/tools/binman/etype/_testing.py
index ac62d2e..ae24fe8 100644
--- a/tools/binman/etype/_testing.py
+++ b/tools/binman/etype/_testing.py
@@ -50,6 +50,8 @@
'bad-update-contents')
self.return_contents_once = fdt_util.GetBool(self._node,
'return-contents-once')
+ self.bad_update_contents_twice = fdt_util.GetBool(self._node,
+ 'bad-update-contents-twice')
# Set to True when the entry is ready to process the FDT.
self.process_fdt_ready = False
@@ -71,11 +73,12 @@
if self.force_bad_datatype:
self.GetEntryArgsOrProps([EntryArg('test-bad-datatype-arg', bool)])
self.return_contents = True
+ self.contents = b'a'
def ObtainContents(self):
if self.return_unknown_contents or not self.return_contents:
return False
- self.data = b'a'
+ self.data = self.contents
self.contents_size = len(self.data)
if self.return_contents_once:
self.return_contents = False
@@ -88,9 +91,14 @@
def ProcessContents(self):
if self.bad_update_contents:
- # Request to update the conents with something larger, to cause a
+ # Request to update the contents with something larger, to cause a
# failure.
- self.ProcessContentsUpdate('aa')
+ if self.bad_update_contents_twice:
+ self.contents += b'a'
+ else:
+ self.contents = b'aa'
+ return self.ProcessContentsUpdate(self.contents)
+ return True
def ProcessFdt(self, fdt):
"""Force reprocessing the first time"""
diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py
index f56a1f8..00cad33 100644
--- a/tools/binman/etype/blob.py
+++ b/tools/binman/etype/blob.py
@@ -9,6 +9,7 @@
import fdt_util
import state
import tools
+import tout
class Entry_blob(Entry):
"""Entry containing an arbitrary binary blob
@@ -33,8 +34,7 @@
def __init__(self, section, etype, node):
Entry.__init__(self, section, etype, node)
self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
- self._compress = fdt_util.GetString(self._node, 'compress', 'none')
- self._uncompressed_size = None
+ self.compress = fdt_util.GetString(self._node, 'compress', 'none')
def ObtainContents(self):
self._filename = self.GetDefaultFilename()
@@ -42,37 +42,40 @@
self.ReadBlobContents()
return True
+ def CompressData(self, indata):
+ if self.compress != 'none':
+ self.uncomp_size = len(indata)
+ data = tools.Compress(indata, self.compress)
+ return data
+
def ReadBlobContents(self):
- # We assume the data is small enough to fit into memory. If this
- # is used for large filesystem image that might not be true.
- # In that case, Image.BuildImage() could be adjusted to use a
- # new Entry method which can read in chunks. Then we could copy
- # the data in chunks and avoid reading it all at once. For now
- # this seems like an unnecessary complication.
- data = tools.ReadFile(self._pathname)
- if self._compress == 'lz4':
- self._uncompressed_size = len(data)
- '''
- import lz4 # Import this only if needed (python-lz4 dependency)
+ """Read blob contents into memory
- try:
- data = lz4.frame.compress(data)
- except AttributeError:
- data = lz4.compress(data)
- '''
- data = tools.Run('lz4', '-c', self._pathname, binary=True)
+ This function compresses the data before storing if needed.
+
+ We assume the data is small enough to fit into memory. If this
+ is used for large filesystem image that might not be true.
+ In that case, Image.BuildImage() could be adjusted to use a
+ new Entry method which can read in chunks. Then we could copy
+ the data in chunks and avoid reading it all at once. For now
+ this seems like an unnecessary complication.
+ """
+ indata = tools.ReadFile(self._pathname)
+ data = self.CompressData(indata)
self.SetContents(data)
return True
def GetDefaultFilename(self):
return self._filename
- def AddMissingProperties(self):
- Entry.AddMissingProperties(self)
- if self._compress != 'none':
- state.AddZeroProp(self._node, 'uncomp-size')
-
- def SetCalculatedProperties(self):
- Entry.SetCalculatedProperties(self)
- if self._uncompressed_size is not None:
- state.SetInt(self._node, 'uncomp-size', self._uncompressed_size)
+ def ReadData(self, decomp=True):
+ indata = Entry.ReadData(self, decomp)
+ if decomp:
+ data = tools.Decompress(indata, self.compress)
+ if self.uncomp_size:
+ tout.Info("%s: Decompressing data size %#x with algo '%s' to data size %#x" %
+ (self.GetPath(), len(indata), self.compress,
+ len(data)))
+ else:
+ data = indata
+ return data
diff --git a/tools/binman/etype/blob_dtb.py b/tools/binman/etype/blob_dtb.py
index cc5b4a3..88ed55d 100644
--- a/tools/binman/etype/blob_dtb.py
+++ b/tools/binman/etype/blob_dtb.py
@@ -23,11 +23,11 @@
def ObtainContents(self):
"""Get the device-tree from the list held by the 'state' module"""
self._filename = self.GetDefaultFilename()
- self._pathname, data = state.GetFdtContents(self._filename)
- self.SetContents(data)
- return True
+ self._pathname, _ = state.GetFdtContents(self._filename)
+ return Entry_blob.ReadBlobContents(self)
def ProcessContents(self):
"""Re-read the DTB contents so that we get any calculated properties"""
- _, data = state.GetFdtContents(self._filename)
- self.SetContents(data)
+ _, indata = state.GetFdtContents(self._filename)
+ data = self.CompressData(indata)
+ return self.ProcessContentsUpdate(data)
diff --git a/tools/binman/etype/cbfs.py b/tools/binman/etype/cbfs.py
new file mode 100644
index 0000000..edf2189
--- /dev/null
+++ b/tools/binman/etype/cbfs.py
@@ -0,0 +1,263 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2019 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type module for a Coreboot Filesystem (CBFS)
+#
+
+from collections import OrderedDict
+
+import cbfs_util
+from cbfs_util import CbfsWriter
+from entry import Entry
+import fdt_util
+import state
+
+class Entry_cbfs(Entry):
+ """Entry containing a Coreboot Filesystem (CBFS)
+
+ A CBFS provides a way to group files into a group. It has a simple directory
+ structure and allows the position of individual files to be set, since it is
+ designed to support execute-in-place in an x86 SPI-flash device. Where XIP
+ is not used, it supports compression and storing ELF files.
+
+ CBFS is used by coreboot as its way of orgnanising SPI-flash contents.
+
+ The contents of the CBFS are defined by subnodes of the cbfs entry, e.g.:
+
+ cbfs {
+ size = <0x100000>;
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ };
+ };
+
+ This creates a CBFS 1MB in size two files in it: u-boot.bin and u-boot.dtb.
+ Note that the size is required since binman does not support calculating it.
+ The contents of each entry is just what binman would normally provide if it
+ were not a CBFS node. A blob type can be used to import arbitrary files as
+ with the second subnode below:
+
+ cbfs {
+ size = <0x100000>;
+ u-boot {
+ cbfs-name = "BOOT";
+ cbfs-type = "raw";
+ };
+
+ dtb {
+ type = "blob";
+ filename = "u-boot.dtb";
+ cbfs-type = "raw";
+ cbfs-compress = "lz4";
+ cbfs-offset = <0x100000>;
+ };
+ };
+
+ This creates a CBFS 1MB in size with u-boot.bin (named "BOOT") and
+ u-boot.dtb (named "dtb") and compressed with the lz4 algorithm.
+
+
+ Properties supported in the top-level CBFS node:
+
+ cbfs-arch:
+ Defaults to "x86", but you can specify the architecture if needed.
+
+
+ Properties supported in the CBFS entry subnodes:
+
+ cbfs-name:
+ This is the name of the file created in CBFS. It defaults to the entry
+ name (which is the node name), but you can override it with this
+ property.
+
+ cbfs-type:
+ This is the CBFS file type. The following are supported:
+
+ raw:
+ This is a 'raw' file, although compression is supported. It can be
+ used to store any file in CBFS.
+
+ stage:
+ This is an ELF file that has been loaded (i.e. mapped to memory), so
+ appears in the CBFS as a flat binary. The input file must be an ELF
+ image, for example this puts "u-boot" (the ELF image) into a 'stage'
+ entry:
+
+ cbfs {
+ size = <0x100000>;
+ u-boot-elf {
+ cbfs-name = "BOOT";
+ cbfs-type = "stage";
+ };
+ };
+
+ You can use your own ELF file with something like:
+
+ cbfs {
+ size = <0x100000>;
+ something {
+ type = "blob";
+ filename = "cbfs-stage.elf";
+ cbfs-type = "stage";
+ };
+ };
+
+ As mentioned, the file is converted to a flat binary, so it is
+ equivalent to adding "u-boot.bin", for example, but with the load and
+ start addresses specified by the ELF. At present there is no option
+ to add a flat binary with a load/start address, similar to the
+ 'add-flat-binary' option in cbfstool.
+
+ cbfs-offset:
+ This is the offset of the file's data within the CBFS. It is used to
+ specify where the file should be placed in cases where a fixed position
+ is needed. Typical uses are for code which is not relocatable and must
+ execute in-place from a particular address. This works because SPI flash
+ is generally mapped into memory on x86 devices. The file header is
+ placed before this offset so that the data start lines up exactly with
+ the chosen offset. If this property is not provided, then the file is
+ placed in the next available spot.
+
+ The current implementation supports only a subset of CBFS features. It does
+ not support other file types (e.g. payload), adding multiple files (like the
+ 'files' entry with a pattern supported by binman), putting files at a
+ particular offset in the CBFS and a few other things.
+
+ Of course binman can create images containing multiple CBFSs, simply by
+ defining these in the binman config:
+
+
+ binman {
+ size = <0x800000>;
+ cbfs {
+ offset = <0x100000>;
+ size = <0x100000>;
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ };
+ };
+
+ cbfs2 {
+ offset = <0x700000>;
+ size = <0x100000>;
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ };
+ image {
+ type = "blob";
+ filename = "image.jpg";
+ };
+ };
+ };
+
+ This creates an 8MB image with two CBFSs, one at offset 1MB, one at 7MB,
+ both of size 1MB.
+ """
+ def __init__(self, section, etype, node):
+ Entry.__init__(self, section, etype, node)
+ self._cbfs_arg = fdt_util.GetString(node, 'cbfs-arch', 'x86')
+ self._cbfs_entries = OrderedDict()
+ self._ReadSubnodes()
+
+ def ObtainContents(self):
+ arch = cbfs_util.find_arch(self._cbfs_arg)
+ if arch is None:
+ self.Raise("Invalid architecture '%s'" % self._cbfs_arg)
+ if self.size is None:
+ self.Raise("'cbfs' entry must have a size property")
+ cbfs = CbfsWriter(self.size, arch)
+ for entry in self._cbfs_entries.values():
+ # First get the input data and put it in a file. If not available,
+ # try later.
+ if not entry.ObtainContents():
+ return False
+ data = entry.GetData()
+ cfile = None
+ if entry._type == 'raw':
+ cfile = cbfs.add_file_raw(entry._cbfs_name, data,
+ entry._cbfs_offset,
+ entry._cbfs_compress)
+ elif entry._type == 'stage':
+ cfile = cbfs.add_file_stage(entry._cbfs_name, data,
+ entry._cbfs_offset)
+ else:
+ entry.Raise("Unknown cbfs-type '%s' (use 'raw', 'stage')" %
+ entry._type)
+ if cfile:
+ entry._cbfs_file = cfile
+ data = cbfs.get_data()
+ self.SetContents(data)
+ return True
+
+ def _ReadSubnodes(self):
+ """Read the subnodes to find out what should go in this IFWI"""
+ for node in self._node.subnodes:
+ entry = Entry.Create(self.section, node)
+ entry._cbfs_name = fdt_util.GetString(node, 'cbfs-name', entry.name)
+ entry._type = fdt_util.GetString(node, 'cbfs-type')
+ compress = fdt_util.GetString(node, 'cbfs-compress', 'none')
+ entry._cbfs_offset = fdt_util.GetInt(node, 'cbfs-offset')
+ entry._cbfs_compress = cbfs_util.find_compress(compress)
+ if entry._cbfs_compress is None:
+ self.Raise("Invalid compression in '%s': '%s'" %
+ (node.name, compress))
+ self._cbfs_entries[entry._cbfs_name] = entry
+
+ def SetImagePos(self, image_pos):
+ """Override this function to set all the entry properties from CBFS
+
+ We can only do this once image_pos is known
+
+ Args:
+ image_pos: Position of this entry in the image
+ """
+ Entry.SetImagePos(self, image_pos)
+
+ # Now update the entries with info from the CBFS entries
+ for entry in self._cbfs_entries.values():
+ cfile = entry._cbfs_file
+ entry.size = cfile.data_len
+ entry.offset = cfile.calced_cbfs_offset
+ entry.image_pos = self.image_pos + entry.offset
+ if entry._cbfs_compress:
+ entry.uncomp_size = cfile.memlen
+
+ def AddMissingProperties(self):
+ Entry.AddMissingProperties(self)
+ for entry in self._cbfs_entries.values():
+ entry.AddMissingProperties()
+ if entry._cbfs_compress:
+ state.AddZeroProp(entry._node, 'uncomp-size')
+ # Store the 'compress' property, since we don't look at
+ # 'cbfs-compress' in Entry.ReadData()
+ state.AddString(entry._node, 'compress',
+ cbfs_util.compress_name(entry._cbfs_compress))
+
+ def SetCalculatedProperties(self):
+ """Set the value of device-tree properties calculated by binman"""
+ Entry.SetCalculatedProperties(self)
+ for entry in self._cbfs_entries.values():
+ state.SetInt(entry._node, 'offset', entry.offset)
+ state.SetInt(entry._node, 'size', entry.size)
+ state.SetInt(entry._node, 'image-pos', entry.image_pos)
+ if entry.uncomp_size is not None:
+ state.SetInt(entry._node, 'uncomp-size', entry.uncomp_size)
+
+ def ListEntries(self, entries, indent):
+ """Override this method to list all files in the section"""
+ Entry.ListEntries(self, entries, indent)
+ for entry in self._cbfs_entries.values():
+ entry.ListEntries(entries, indent + 1)
+
+ def GetEntries(self):
+ return self._cbfs_entries
diff --git a/tools/binman/etype/fdtmap.py b/tools/binman/etype/fdtmap.py
new file mode 100644
index 0000000..ddb9738
--- /dev/null
+++ b/tools/binman/etype/fdtmap.py
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+
+"""# Entry-type module for a full map of the firmware image
+
+This handles putting an FDT into the image with just the information about the
+image.
+"""
+
+import libfdt
+
+from entry import Entry
+from fdt import Fdt
+import state
+import tools
+
+FDTMAP_MAGIC = b'_FDTMAP_'
+FDTMAP_HDR_LEN = 16
+
+def LocateFdtmap(data):
+ """Search an image for an fdt map
+
+ Args:
+ data: Data to search
+
+ Returns:
+ Position of fdt map in data, or None if not found. Note that the
+ position returned is of the FDT header, i.e. before the FDT data
+ """
+ hdr_pos = data.find(FDTMAP_MAGIC)
+ size = len(data)
+ if hdr_pos != -1:
+ hdr = data[hdr_pos:hdr_pos + FDTMAP_HDR_LEN]
+ if len(hdr) == FDTMAP_HDR_LEN:
+ return hdr_pos
+ return None
+
+class Entry_fdtmap(Entry):
+ """An entry which contains an FDT map
+
+ Properties / Entry arguments:
+ None
+
+ An FDT map is just a header followed by an FDT containing a list of all the
+ entries in the image. The root node corresponds to the image node in the
+ original FDT, and an image-name property indicates the image name in that
+ original tree.
+
+ The header is the string _FDTMAP_ followed by 8 unused bytes.
+
+ When used, this entry will be populated with an FDT map which reflects the
+ entries in the current image. Hierarchy is preserved, and all offsets and
+ sizes are included.
+
+ Note that the -u option must be provided to ensure that binman updates the
+ FDT with the position of each entry.
+
+ Example output for a simple image with U-Boot and an FDT map:
+
+ / {
+ size = <0x00000112>;
+ image-pos = <0x00000000>;
+ offset = <0x00000000>;
+ u-boot {
+ size = <0x00000004>;
+ image-pos = <0x00000000>;
+ offset = <0x00000000>;
+ };
+ fdtmap {
+ size = <0x0000010e>;
+ image-pos = <0x00000004>;
+ offset = <0x00000004>;
+ };
+ };
+ """
+ def __init__(self, section, etype, node):
+ Entry.__init__(self, section, etype, node)
+
+ def _GetFdtmap(self):
+ """Build an FDT map from the entries in the current image
+
+ Returns:
+ FDT map binary data
+ """
+ def _AddNode(node):
+ """Add a node to the FDT map"""
+ for pname, prop in node.props.items():
+ fsw.property(pname, prop.bytes)
+ for subnode in node.subnodes:
+ with fsw.add_node(subnode.name):
+ _AddNode(subnode)
+
+ # Get the FDT data into an Fdt object
+ data = state.GetFdtContents()[1]
+ infdt = Fdt.FromData(data)
+ infdt.Scan()
+
+ # Find the node for the image containing the Fdt-map entry
+ path = self.section.GetPath()
+ node = infdt.GetNode(path)
+ if not node:
+ self.Raise("Internal error: Cannot locate node for path '%s'" %
+ path)
+
+ # Build a new tree with all nodes and properties starting from that node
+ fsw = libfdt.FdtSw()
+ fsw.finish_reservemap()
+ with fsw.add_node(''):
+ _AddNode(node)
+ fdt = fsw.as_fdt()
+
+ # Pack this new FDT and return its contents
+ fdt.pack()
+ outfdt = Fdt.FromData(fdt.as_bytearray())
+ data = FDTMAP_MAGIC + tools.GetBytes(0, 8) + outfdt.GetContents()
+ return data
+
+ def ObtainContents(self):
+ """Obtain a placeholder for the fdt-map contents"""
+ self.SetContents(self._GetFdtmap())
+ return True
+
+ def ProcessContents(self):
+ """Write an updated version of the FDT map to this entry
+
+ This is necessary since new data may have been written back to it during
+ processing, e.g. the image-pos properties.
+ """
+ return self.ProcessContentsUpdate(self._GetFdtmap())
diff --git a/tools/binman/etype/files.py b/tools/binman/etype/files.py
index 99f2f2f..0068b30 100644
--- a/tools/binman/etype/files.py
+++ b/tools/binman/etype/files.py
@@ -14,7 +14,6 @@
import state
import tools
-import bsection
class Entry_files(Entry_section):
"""Entry containing a set of files
@@ -54,4 +53,4 @@
state.AddString(subnode, 'compress', self._compress)
# Read entries again, now that we have some
- self._section._ReadEntries()
+ self._ReadEntries()
diff --git a/tools/binman/etype/fmap.py b/tools/binman/etype/fmap.py
index e6b5c5c..f8d8d86 100644
--- a/tools/binman/etype/fmap.py
+++ b/tools/binman/etype/fmap.py
@@ -49,7 +49,7 @@
areas.append(fmap_util.FmapArea(pos or 0, entry.size or 0,
tools.FromUnicode(entry.name), 0))
- entries = self.section._image.GetEntries()
+ entries = self.section.image.GetEntries()
areas = []
for entry in entries.values():
_AddEntries(areas, entry)
@@ -62,4 +62,4 @@
return True
def ProcessContents(self):
- self.SetContents(self._GetFmap())
+ return self.ProcessContentsUpdate(self._GetFmap())
diff --git a/tools/binman/etype/image_header.py b/tools/binman/etype/image_header.py
new file mode 100644
index 0000000..8f9c5aa
--- /dev/null
+++ b/tools/binman/etype/image_header.py
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+
+"""Entry-type module for an image header which points to the FDT map
+
+This creates an 8-byte entry with a magic number and the offset of the FDT map
+(which is another entry in the image), relative to the start or end of the
+image.
+"""
+
+import struct
+
+from entry import Entry
+import fdt_util
+
+IMAGE_HEADER_MAGIC = b'BinM'
+IMAGE_HEADER_LEN = 8
+
+def LocateHeaderOffset(data):
+ """Search an image for an image header
+
+ Args:
+ data: Data to search
+
+ Returns:
+ Offset of image header in the image, or None if not found
+ """
+ hdr_pos = data.find(IMAGE_HEADER_MAGIC)
+ if hdr_pos != -1:
+ size = len(data)
+ hdr = data[hdr_pos:hdr_pos + IMAGE_HEADER_LEN]
+ if len(hdr) == IMAGE_HEADER_LEN:
+ offset = struct.unpack('<I', hdr[4:])[0]
+ if hdr_pos == len(data) - IMAGE_HEADER_LEN:
+ pos = size + offset - (1 << 32)
+ else:
+ pos = offset
+ return pos
+ return None
+
+class Entry_image_header(Entry):
+ """An entry which contains a pointer to the FDT map
+
+ Properties / Entry arguments:
+ location: Location of header ("start" or "end" of image). This is
+ optional. If omitted then the entry must have an offset property.
+
+ This adds an 8-byte entry to the start or end of the image, pointing to the
+ location of the FDT map. The format is a magic number followed by an offset
+ from the start or end of the image, in twos-compliment format.
+
+ This entry must be in the top-level part of the image.
+
+ NOTE: If the location is at the start/end, you will probably need to specify
+ sort-by-offset for the image, unless you actually put the image header
+ first/last in the entry list.
+ """
+ def __init__(self, section, etype, node):
+ Entry.__init__(self, section, etype, node)
+ self.location = fdt_util.GetString(self._node, 'location')
+
+ def _GetHeader(self):
+ image_pos = self.GetSiblingImagePos('fdtmap')
+ if image_pos == False:
+ self.Raise("'image_header' section must have an 'fdtmap' sibling")
+ elif image_pos is None:
+ # This will be available when called from ProcessContents(), but not
+ # when called from ObtainContents()
+ offset = 0xffffffff
+ else:
+ image_size = self.section.GetImageSize() or 0
+ base = (0 if self.location != 'end' else image_size)
+ offset = (image_pos - base) & 0xffffffff
+ data = IMAGE_HEADER_MAGIC + struct.pack('<I', offset)
+ return data
+
+ def ObtainContents(self):
+ """Obtain a placeholder for the header contents"""
+ self.SetContents(self._GetHeader())
+ return True
+
+ def Pack(self, offset):
+ """Special pack method to set the offset to start/end of image"""
+ if not self.offset:
+ if self.location not in ['start', 'end']:
+ self.Raise("Invalid location '%s', expected 'start' or 'end'" %
+ self.location)
+ image_size = self.section.GetImageSize() or 0
+ self.offset = (0 if self.location != 'end' else image_size - 8)
+ return Entry.Pack(self, offset)
+
+ def ProcessContents(self):
+ """Write an updated version of the FDT map to this entry
+
+ This is necessary since image_pos is not available when ObtainContents()
+ is called, since by then the entries have not been packed in the image.
+ """
+ return self.ProcessContentsUpdate(self._GetHeader())
diff --git a/tools/binman/etype/intel_descriptor.py b/tools/binman/etype/intel_descriptor.py
index 6acbbd8..adea578 100644
--- a/tools/binman/etype/intel_descriptor.py
+++ b/tools/binman/etype/intel_descriptor.py
@@ -47,17 +47,25 @@
def __init__(self, section, etype, node):
Entry_blob.__init__(self, section, etype, node)
self._regions = []
+ if self.offset is None:
+ self.offset = self.section.GetStartOffset()
def GetOffsets(self):
offset = self.data.find(FD_SIGNATURE)
if offset == -1:
- self.Raise('Cannot find FD signature')
+ self.Raise('Cannot find Intel Flash Descriptor (FD) signature')
flvalsig, flmap0, flmap1, flmap2 = struct.unpack('<LLLL',
self.data[offset:offset + 16])
frba = ((flmap0 >> 16) & 0xff) << 4
for i in range(MAX_REGIONS):
self._regions.append(Region(self.data, frba, i))
- # Set the offset for ME only, for now, since the others are not used
- return {'intel-me': [self._regions[REGION_ME].base,
- self._regions[REGION_ME].size]}
+ # Set the offset for ME (Management Engine) and IFWI (Integrated
+ # Firmware Image), for now, since the others are not used.
+ info = {}
+ if self.HasSibling('intel-me'):
+ info['intel-me'] = [self._regions[REGION_ME].base,
+ self._regions[REGION_ME].size]
+ if self.HasSibling('intel-ifwi'):
+ info['intel-ifwi'] = [self._regions[REGION_BIOS].base, None]
+ return info
diff --git a/tools/binman/etype/intel_ifwi.py b/tools/binman/etype/intel_ifwi.py
new file mode 100644
index 0000000..8c79b2d
--- /dev/null
+++ b/tools/binman/etype/intel_ifwi.py
@@ -0,0 +1,100 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type module for Intel Management Engine binary blob
+#
+
+from collections import OrderedDict
+
+from entry import Entry
+from blob import Entry_blob
+import fdt_util
+import tools
+
+class Entry_intel_ifwi(Entry_blob):
+ """Entry containing an Intel Integrated Firmware Image (IFWI) file
+
+ Properties / Entry arguments:
+ - filename: Filename of file to read into entry. This is either the
+ IFWI file itself, or a file that can be converted into one using a
+ tool
+ - convert-fit: If present this indicates that the ifwitool should be
+ used to convert the provided file into a IFWI.
+
+ This file contains code and data used by the SoC that is required to make
+ it work. It includes U-Boot TPL, microcode, things related to the CSE
+ (Converged Security Engine, the microcontroller that loads all the firmware)
+ and other items beyond the wit of man.
+
+ A typical filename is 'ifwi.bin' for an IFWI file, or 'fitimage.bin' for a
+ file that will be converted to an IFWI.
+
+ The position of this entry is generally set by the intel-descriptor entry.
+
+ The contents of the IFWI are specified by the subnodes of the IFWI node.
+ Each subnode describes an entry which is placed into the IFWFI with a given
+ sub-partition (and optional entry name).
+
+ See README.x86 for information about x86 binary blobs.
+ """
+ def __init__(self, section, etype, node):
+ Entry_blob.__init__(self, section, etype, node)
+ self._convert_fit = fdt_util.GetBool(self._node, 'convert-fit')
+ self._ifwi_entries = OrderedDict()
+ self._ReadSubnodes()
+
+ def ObtainContents(self):
+ """Get the contects for the IFWI
+
+ Unfortunately we cannot create anything from scratch here, as Intel has
+ tools which create precursor binaries with lots of data and settings,
+ and these are not incorporated into binman.
+
+ The first step is to get a file in the IFWI format. This is either
+ supplied directly or is extracted from a fitimage using the 'create'
+ subcommand.
+
+ After that we delete the OBBP sub-partition and add each of the files
+ that we want in the IFWI file, one for each sub-entry of the IWFI node.
+ """
+ self._pathname = tools.GetInputFilename(self._filename)
+
+ # Create the IFWI file if needed
+ if self._convert_fit:
+ inname = self._pathname
+ outname = tools.GetOutputFilename('ifwi.bin')
+ tools.RunIfwiTool(inname, tools.CMD_CREATE, outname)
+ self._filename = 'ifwi.bin'
+ self._pathname = outname
+ else:
+ # Provide a different code path here to ensure we have test coverage
+ inname = self._pathname
+
+ # Delete OBBP if it is there, then add the required new items.
+ tools.RunIfwiTool(inname, tools.CMD_DELETE, subpart='OBBP')
+
+ for entry in self._ifwi_entries.values():
+ # First get the input data and put it in a file
+ if not entry.ObtainContents():
+ return False
+ data = entry.GetData()
+ uniq = self.GetUniqueName()
+ input_fname = tools.GetOutputFilename('input.%s' % uniq)
+ tools.WriteFile(input_fname, data)
+
+ tools.RunIfwiTool(inname,
+ tools.CMD_REPLACE if entry._ifwi_replace else tools.CMD_ADD,
+ input_fname, entry._ifwi_subpart, entry._ifwi_entry_name)
+
+ self.ReadBlobContents()
+ return True
+
+ def _ReadSubnodes(self):
+ """Read the subnodes to find out what should go in this IFWI"""
+ for node in self._node.subnodes:
+ entry = Entry.Create(self.section, node)
+ entry._ifwi_replace = fdt_util.GetBool(node, 'replace')
+ entry._ifwi_subpart = fdt_util.GetString(node, 'ifwi-subpart')
+ entry._ifwi_entry_name = fdt_util.GetString(node, 'ifwi-entry')
+ self._ifwi_entries[entry._ifwi_subpart] = entry
diff --git a/tools/binman/etype/intel_me.py b/tools/binman/etype/intel_me.py
index 247c5b3..c932ec5 100644
--- a/tools/binman/etype/intel_me.py
+++ b/tools/binman/etype/intel_me.py
@@ -22,6 +22,8 @@
A typical filename is 'me.bin'.
+ The position of this entry is generally set by the intel-descriptor entry.
+
See README.x86 for information about x86 binary blobs.
"""
def __init__(self, section, etype, node):
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index 3681a48..6db3c7a 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -1,59 +1,155 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2018 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
-#
-# Entry-type module for sections, which are entries which can contain other
-# entries.
-#
+
+"""Entry-type module for sections (groups of entries)
+
+Sections are entries which can contain other entries. This allows hierarchical
+images to be created.
+"""
+
+from __future__ import print_function
+
+from collections import OrderedDict
+import re
+import sys
from entry import Entry
import fdt_util
import tools
-import bsection
class Entry_section(Entry):
"""Entry that contains other entries
Properties / Entry arguments: (see binman README for more information)
- - size: Size of section in bytes
- - align-size: Align size to a particular power of two
- - pad-before: Add padding before the entry
- - pad-after: Add padding after the entry
- - pad-byte: Pad byte to use when padding
- - sort-by-offset: Reorder the entries by offset
- - end-at-4gb: Used to build an x86 ROM which ends at 4GB (2^32)
- - name-prefix: Adds a prefix to the name of every entry in the section
+ pad-byte: Pad byte to use when padding
+ sort-by-offset: True if entries should be sorted by offset, False if
+ they must be in-order in the device tree description
+ end-at-4gb: Used to build an x86 ROM which ends at 4GB (2^32)
+ skip-at-start: Number of bytes before the first entry starts. These
+ effectively adjust the starting offset of entries. For example,
+ if this is 16, then the first entry would start at 16. An entry
+ with offset = 20 would in fact be written at offset 4 in the image
+ file, since the first 16 bytes are skipped when writing.
+ name-prefix: Adds a prefix to the name of every entry in the section
when writing out the map
+ Since a section is also an entry, it inherits all the properies of entries
+ too.
+
A section is an entry which can contain other entries, thus allowing
hierarchical images to be created. See 'Sections and hierarchical images'
in the binman README for more information.
"""
- def __init__(self, section, etype, node):
- Entry.__init__(self, section, etype, node)
- self._section = bsection.Section(node.name, section, node,
- section._image)
+ def __init__(self, section, etype, node, test=False):
+ if not test:
+ Entry.__init__(self, section, etype, node)
+ if section:
+ self.image = section.image
+ self._entries = OrderedDict()
+ self._pad_byte = 0
+ self._sort = False
+ self._skip_at_start = None
+ self._end_4gb = False
+ if not test:
+ self._ReadNode()
+ self._ReadEntries()
+
+ def _Raise(self, msg):
+ """Raises an error for this section
+
+ Args:
+ msg: Error message to use in the raise string
+ Raises:
+ ValueError()
+ """
+ raise ValueError("Section '%s': %s" % (self._node.path, msg))
+
+ def _ReadNode(self):
+ """Read properties from the image node"""
+ self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 0)
+ self._sort = fdt_util.GetBool(self._node, 'sort-by-offset')
+ self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb')
+ self._skip_at_start = fdt_util.GetInt(self._node, 'skip-at-start')
+ if self._end_4gb:
+ if not self.size:
+ self.Raise("Section size must be provided when using end-at-4gb")
+ if self._skip_at_start is not None:
+ self.Raise("Provide either 'end-at-4gb' or 'skip-at-start'")
+ else:
+ self._skip_at_start = 0x100000000 - self.size
+ else:
+ if self._skip_at_start is None:
+ self._skip_at_start = 0
+ self._name_prefix = fdt_util.GetString(self._node, 'name-prefix')
+ filename = fdt_util.GetString(self._node, 'filename')
+ if filename:
+ self._filename = filename
+
+ def _ReadEntries(self):
+ for node in self._node.subnodes:
+ if node.name == 'hash':
+ continue
+ entry = Entry.Create(self, node)
+ entry.SetPrefix(self._name_prefix)
+ self._entries[node.name] = entry
def GetFdtSet(self):
- return self._section.GetFdtSet()
+ fdt_set = set()
+ for entry in self._entries.values():
+ fdt_set.update(entry.GetFdtSet())
+ return fdt_set
def ProcessFdt(self, fdt):
- return self._section.ProcessFdt(fdt)
+ """Allow entries to adjust the device tree
+
+ Some entries need to adjust the device tree for their purposes. This
+ may involve adding or deleting properties.
+ """
+ todo = self._entries.values()
+ for passnum in range(3):
+ next_todo = []
+ for entry in todo:
+ if not entry.ProcessFdt(fdt):
+ next_todo.append(entry)
+ todo = next_todo
+ if not todo:
+ break
+ if todo:
+ self.Raise('Internal error: Could not complete processing of Fdt: remaining %s' %
+ todo)
+ return True
def ExpandEntries(self):
+ """Expand out any entries which have calculated sub-entries
+
+ Some entries are expanded out at runtime, e.g. 'files', which produces
+ a section containing a list of files. Process these entries so that
+ this information is added to the device tree.
+ """
Entry.ExpandEntries(self)
- self._section.ExpandEntries()
+ for entry in self._entries.values():
+ entry.ExpandEntries()
def AddMissingProperties(self):
+ """Add new properties to the device tree as needed for this entry"""
Entry.AddMissingProperties(self)
- self._section.AddMissingProperties()
+ for entry in self._entries.values():
+ entry.AddMissingProperties()
def ObtainContents(self):
- return self._section.GetEntryContents()
+ return self.GetEntryContents()
def GetData(self):
- return self._section.GetData()
+ section_data = tools.GetBytes(self._pad_byte, self.size)
+
+ for entry in self._entries.values():
+ data = entry.GetData()
+ base = self.pad_before + entry.offset - self._skip_at_start
+ section_data = (section_data[:base] + data +
+ section_data[base + len(data):])
+ return section_data
def GetOffsets(self):
"""Handle entries that want to set the offset/size of other entries
@@ -61,35 +157,94 @@
This calls each entry's GetOffsets() method. If it returns a list
of entries to update, it updates them.
"""
- self._section.GetEntryOffsets()
+ self.GetEntryOffsets()
return {}
+ def ResetForPack(self):
+ """Reset offset/size fields so that packing can be done again"""
+ Entry.ResetForPack(self)
+ for entry in self._entries.values():
+ entry.ResetForPack()
+
def Pack(self, offset):
"""Pack all entries into the section"""
- self._section.PackEntries()
- if self._section._offset is None:
- self._section.SetOffset(offset)
- self.size = self._section.GetSize()
- return super(Entry_section, self).Pack(offset)
+ self._PackEntries()
+ return Entry.Pack(self, offset)
- def SetImagePos(self, image_pos):
- Entry.SetImagePos(self, image_pos)
- self._section.SetImagePos(image_pos + self.offset)
+ def _PackEntries(self):
+ """Pack all entries into the image"""
+ offset = self._skip_at_start
+ for entry in self._entries.values():
+ offset = entry.Pack(offset)
+ self.size = self.CheckSize()
+
+ def _ExpandEntries(self):
+ """Expand any entries that are permitted to"""
+ exp_entry = None
+ for entry in self._entries.values():
+ if exp_entry:
+ exp_entry.ExpandToLimit(entry.offset)
+ exp_entry = None
+ if entry.expand_size:
+ exp_entry = entry
+ if exp_entry:
+ exp_entry.ExpandToLimit(self.size)
+
+ def _SortEntries(self):
+ """Sort entries by offset"""
+ entries = sorted(self._entries.values(), key=lambda entry: entry.offset)
+ self._entries.clear()
+ for entry in entries:
+ self._entries[entry._node.name] = entry
+
+ def CheckEntries(self):
+ """Check that entries do not overlap or extend outside the image"""
+ if self._sort:
+ self._SortEntries()
+ self._ExpandEntries()
+ offset = 0
+ prev_name = 'None'
+ for entry in self._entries.values():
+ entry.CheckOffset()
+ if (entry.offset < self._skip_at_start or
+ entry.offset + entry.size > self._skip_at_start +
+ self.size):
+ entry.Raise("Offset %#x (%d) is outside the section starting "
+ "at %#x (%d)" %
+ (entry.offset, entry.offset, self._skip_at_start,
+ self._skip_at_start))
+ if entry.offset < offset:
+ entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
+ "ending at %#x (%d)" %
+ (entry.offset, entry.offset, prev_name, offset, offset))
+ offset = entry.offset + entry.size
+ prev_name = entry.GetPath()
def WriteSymbols(self, section):
"""Write symbol values into binary files for access at run time"""
- self._section.WriteSymbols()
+ for entry in self._entries.values():
+ entry.WriteSymbols(self)
def SetCalculatedProperties(self):
Entry.SetCalculatedProperties(self)
- self._section.SetCalculatedProperties()
+ for entry in self._entries.values():
+ entry.SetCalculatedProperties()
+
+ def SetImagePos(self, image_pos):
+ Entry.SetImagePos(self, image_pos)
+ for entry in self._entries.values():
+ entry.SetImagePos(image_pos + self.offset)
def ProcessContents(self):
- self._section.ProcessEntryContents()
- super(Entry_section, self).ProcessContents()
+ sizes_ok_base = super(Entry_section, self).ProcessContents()
+ sizes_ok = True
+ for entry in self._entries.values():
+ if not entry.ProcessContents():
+ sizes_ok = False
+ return sizes_ok and sizes_ok_base
def CheckOffset(self):
- self._section.CheckEntries()
+ self.CheckEntries()
def WriteMap(self, fd, indent):
"""Write a map of the section to a .map file
@@ -97,11 +252,211 @@
Args:
fd: File to write the map to
"""
- self._section.WriteMap(fd, indent)
+ Entry.WriteMapLine(fd, indent, self.name, self.offset or 0,
+ self.size, self.image_pos)
+ for entry in self._entries.values():
+ entry.WriteMap(fd, indent + 1)
def GetEntries(self):
- return self._section.GetEntries()
+ return self._entries
+
+ def GetContentsByPhandle(self, phandle, source_entry):
+ """Get the data contents of an entry specified by a phandle
+
+ This uses a phandle to look up a node and and find the entry
+ associated with it. Then it returnst he contents of that entry.
+
+ Args:
+ phandle: Phandle to look up (integer)
+ source_entry: Entry containing that phandle (used for error
+ reporting)
+
+ Returns:
+ data from associated entry (as a string), or None if not found
+ """
+ node = self._node.GetFdt().LookupPhandle(phandle)
+ if not node:
+ source_entry.Raise("Cannot find node for phandle %d" % phandle)
+ for entry in self._entries.values():
+ if entry._node == node:
+ return entry.GetData()
+ source_entry.Raise("Cannot find entry for node '%s'" % node.name)
+
+ def LookupSymbol(self, sym_name, optional, msg):
+ """Look up a symbol in an ELF file
+
+ Looks up a symbol in an ELF file. Only entry types which come from an
+ ELF image can be used by this function.
+
+ At present the only entry property supported is offset.
+
+ Args:
+ sym_name: Symbol name in the ELF file to look up in the format
+ _binman_<entry>_prop_<property> where <entry> is the name of
+ the entry and <property> is the property to find (e.g.
+ _binman_u_boot_prop_offset). As a special case, you can append
+ _any to <entry> to have it search for any matching entry. E.g.
+ _binman_u_boot_any_prop_offset will match entries called u-boot,
+ u-boot-img and u-boot-nodtb)
+ optional: True if the symbol is optional. If False this function
+ will raise if the symbol is not found
+ msg: Message to display if an error occurs
+
+ Returns:
+ Value that should be assigned to that symbol, or None if it was
+ optional and not found
+
+ Raises:
+ ValueError if the symbol is invalid or not found, or references a
+ property which is not supported
+ """
+ m = re.match(r'^_binman_(\w+)_prop_(\w+)$', sym_name)
+ if not m:
+ raise ValueError("%s: Symbol '%s' has invalid format" %
+ (msg, sym_name))
+ entry_name, prop_name = m.groups()
+ entry_name = entry_name.replace('_', '-')
+ entry = self._entries.get(entry_name)
+ if not entry:
+ if entry_name.endswith('-any'):
+ root = entry_name[:-4]
+ for name in self._entries:
+ if name.startswith(root):
+ rest = name[len(root):]
+ if rest in ['', '-img', '-nodtb']:
+ entry = self._entries[name]
+ if not entry:
+ err = ("%s: Entry '%s' not found in list (%s)" %
+ (msg, entry_name, ','.join(self._entries.keys())))
+ if optional:
+ print('Warning: %s' % err, file=sys.stderr)
+ return None
+ raise ValueError(err)
+ if prop_name == 'offset':
+ return entry.offset
+ elif prop_name == 'image_pos':
+ return entry.image_pos
+ else:
+ raise ValueError("%s: No such property '%s'" % (msg, prop_name))
+
+ def GetRootSkipAtStart(self):
+ """Get the skip-at-start value for the top-level section
+
+ This is used to find out the starting offset for root section that
+ contains this section. If this is a top-level section then it returns
+ the skip-at-start offset for this section.
+
+ This is used to get the absolute position of section within the image.
+
+ Returns:
+ Integer skip-at-start value for the root section containing this
+ section
+ """
+ if self.section:
+ return self.section.GetRootSkipAtStart()
+ return self._skip_at_start
+
+ def GetStartOffset(self):
+ """Get the start offset for this section
+
+ Returns:
+ The first available offset in this section (typically 0)
+ """
+ return self._skip_at_start
+
+ def GetImageSize(self):
+ """Get the size of the image containing this section
+
+ Returns:
+ Image size as an integer number of bytes, which may be None if the
+ image size is dynamic and its sections have not yet been packed
+ """
+ return self.image.size
+
+ def FindEntryType(self, etype):
+ """Find an entry type in the section
+
+ Args:
+ etype: Entry type to find
+ Returns:
+ entry matching that type, or None if not found
+ """
+ for entry in self._entries.values():
+ if entry.etype == etype:
+ return entry
+ return None
+
+ def GetEntryContents(self):
+ """Call ObtainContents() for the section
+ """
+ todo = self._entries.values()
+ for passnum in range(3):
+ next_todo = []
+ for entry in todo:
+ if not entry.ObtainContents():
+ next_todo.append(entry)
+ todo = next_todo
+ if not todo:
+ break
+ if todo:
+ self.Raise('Internal error: Could not complete processing of contents: remaining %s' %
+ todo)
+ return True
+
+ def _SetEntryOffsetSize(self, name, offset, size):
+ """Set the offset and size of an entry
+
+ Args:
+ name: Entry name to update
+ offset: New offset, or None to leave alone
+ size: New size, or None to leave alone
+ """
+ entry = self._entries.get(name)
+ if not entry:
+ self._Raise("Unable to set offset/size for unknown entry '%s'" %
+ name)
+ entry.SetOffsetSize(self._skip_at_start + offset if offset else None,
+ size)
+
+ def GetEntryOffsets(self):
+ """Handle entries that want to set the offset/size of other entries
+
+ This calls each entry's GetOffsets() method. If it returns a list
+ of entries to update, it updates them.
+ """
+ for entry in self._entries.values():
+ offset_dict = entry.GetOffsets()
+ for name, info in offset_dict.items():
+ self._SetEntryOffsetSize(name, *info)
+
+
+ def CheckSize(self):
+ """Check that the image contents does not exceed its size, etc."""
+ contents_size = 0
+ for entry in self._entries.values():
+ contents_size = max(contents_size, entry.offset + entry.size)
+
+ contents_size -= self._skip_at_start
+
+ size = self.size
+ if not size:
+ size = self.pad_before + contents_size + self.pad_after
+ size = tools.Align(size, self.align_size)
+
+ if self.size and contents_size > self.size:
+ self._Raise("contents size %#x (%d) exceeds section size %#x (%d)" %
+ (contents_size, contents_size, self.size, self.size))
+ if not self.size:
+ self.size = size
+ if self.size != tools.Align(self.size, self.align_size):
+ self._Raise("Size %#x (%d) does not match align-size %#x (%d)" %
+ (self.size, self.size, self.align_size,
+ self.align_size))
+ return size
- def ExpandToLimit(self, limit):
- super(Entry_section, self).ExpandToLimit(limit)
- self._section.ExpandSize(self.size)
+ def ListEntries(self, entries, indent):
+ """List the files in the section"""
+ Entry.AddEntryInfo(entries, indent, self.name, 'section', self.size,
+ self.image_pos, None, self.offset, self)
+ for entry in self._entries.values():
+ entry.ListEntries(entries, indent + 1)
diff --git a/tools/binman/etype/text.py b/tools/binman/etype/text.py
index 9ee04d7..da1813a 100644
--- a/tools/binman/etype/text.py
+++ b/tools/binman/etype/text.py
@@ -22,6 +22,8 @@
that contains the string to place in the entry
<xxx> (actual name is the value of text-label): contains the string to
place in the entry.
+ <text>: The text to place in the entry (overrides the above mechanism).
+ This is useful when the text is constant.
Example node:
@@ -44,15 +46,28 @@
message = "a message directly in the node"
};
+ or just:
+
+ text {
+ size = <8>;
+ text = "some text directly in the node"
+ };
+
The text is not itself nul-terminated. This can be achieved, if required,
by setting the size of the entry to something larger than the text.
"""
def __init__(self, section, etype, node):
Entry.__init__(self, section, etype, node)
- label, = self.GetEntryArgsOrProps([EntryArg('text-label', str)])
- self.text_label = tools.ToStr(label) if type(label) != str else label
- value, = self.GetEntryArgsOrProps([EntryArg(self.text_label, str)])
- value = tools.ToBytes(value) if value is not None else value
+ value = fdt_util.GetString(self._node, 'text')
+ if value:
+ value = tools.ToBytes(value)
+ else:
+ label, = self.GetEntryArgsOrProps([EntryArg('text-label', str)])
+ self.text_label = label
+ if self.text_label:
+ value, = self.GetEntryArgsOrProps([EntryArg(self.text_label,
+ str)])
+ value = tools.ToBytes(value) if value is not None else value
self.value = value
def ObtainContents(self):
diff --git a/tools/binman/etype/u_boot_spl_elf.py b/tools/binman/etype/u_boot_spl_elf.py
index da328ae..24ee772 100644
--- a/tools/binman/etype/u_boot_spl_elf.py
+++ b/tools/binman/etype/u_boot_spl_elf.py
@@ -12,7 +12,7 @@
"""U-Boot SPL ELF image
Properties / Entry arguments:
- - filename: Filename of SPL u-boot (default 'spl/u-boot')
+ - filename: Filename of SPL u-boot (default 'spl/u-boot-spl')
This is the U-Boot SPL ELF image. It does not include a device tree but can
be relocated to any address for execution.
diff --git a/tools/binman/etype/u_boot_tpl_elf.py b/tools/binman/etype/u_boot_tpl_elf.py
new file mode 100644
index 0000000..9cc1cc2
--- /dev/null
+++ b/tools/binman/etype/u_boot_tpl_elf.py
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type module for U-Boot TPL ELF image
+#
+
+from entry import Entry
+from blob import Entry_blob
+
+class Entry_u_boot_tpl_elf(Entry_blob):
+ """U-Boot TPL ELF image
+
+ Properties / Entry arguments:
+ - filename: Filename of TPL u-boot (default 'tpl/u-boot-tpl')
+
+ This is the U-Boot TPL ELF image. It does not include a device tree but can
+ be relocated to any address for execution.
+ """
+ def __init__(self, section, etype, node):
+ Entry_blob.__init__(self, section, etype, node)
+
+ def GetDefaultFilename(self):
+ return 'tpl/u-boot-tpl'
diff --git a/tools/binman/etype/u_boot_with_ucode_ptr.py b/tools/binman/etype/u_boot_with_ucode_ptr.py
index da0e124..cb7dbc6 100644
--- a/tools/binman/etype/u_boot_with_ucode_ptr.py
+++ b/tools/binman/etype/u_boot_with_ucode_ptr.py
@@ -49,7 +49,7 @@
def ProcessContents(self):
# If the image does not need microcode, there is nothing to do
if not self.target_offset:
- return
+ return True
# Get the offset of the microcode
ucode_entry = self.section.FindEntryType('u-boot-ucode')
@@ -91,6 +91,6 @@
# Write the microcode offset and size into the entry
offset_and_size = struct.pack('<2L', offset, size)
self.target_offset -= self.image_pos
- self.ProcessContentsUpdate(self.data[:self.target_offset] +
- offset_and_size +
- self.data[self.target_offset + 8:])
+ return self.ProcessContentsUpdate(self.data[:self.target_offset] +
+ offset_and_size +
+ self.data[self.target_offset + 8:])
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index cc57ef3..6a40d1f 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -6,6 +6,8 @@
#
# python -m unittest func_test.TestFunctional.testHelp
+from __future__ import print_function
+
import hashlib
from optparse import OptionParser
import os
@@ -16,14 +18,19 @@
import unittest
import binman
+import cbfs_util
import cmdline
import command
import control
import elf
import fdt
+from etype import fdtmap
+from etype import image_header
import fdt_util
import fmap_util
import test_util
+import gzip
+from image import Image
import state
import tools
import tout
@@ -59,9 +66,11 @@
VBLOCK_DATA = b'vblk'
FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
b"sorry you're alive\n")
-COMPRESS_DATA = b'data to compress'
+COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
REFCODE_DATA = b'refcode'
+EXTRACT_DTB_SIZE = 0x3c9
+
class TestFunctional(unittest.TestCase):
"""Functional tests for binman
@@ -131,13 +140,46 @@
TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
+ # Travis-CI may have an old lz4
+ self.have_lz4 = True
+ try:
+ tools.Run('lz4', '--no-frame-crc', '-c',
+ os.path.join(self._indir, 'u-boot.bin'))
+ except:
+ self.have_lz4 = False
+
@classmethod
def tearDownClass(self):
"""Remove the temporary input directory and its contents"""
- if self._indir:
- shutil.rmtree(self._indir)
+ if self.preserve_indir:
+ print('Preserving input dir: %s' % self._indir)
+ else:
+ if self._indir:
+ shutil.rmtree(self._indir)
self._indir = None
+ @classmethod
+ def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
+ toolpath=None, verbosity=None):
+ """Accept arguments controlling test execution
+
+ Args:
+ preserve_indir: Preserve the shared input directory used by all
+ tests in this class.
+ preserve_outdir: Preserve the output directories used by tests. Each
+ test has its own, so this is normally only useful when running a
+ single test.
+ toolpath: ist of paths to use for tools
+ """
+ cls.preserve_indir = preserve_indir
+ cls.preserve_outdirs = preserve_outdirs
+ cls.toolpath = toolpath
+ cls.verbosity = verbosity
+
+ def _CheckLz4(self):
+ if not self.have_lz4:
+ self.skipTest('lz4 --no-frame-crc not available')
+
def setUp(self):
# Enable this to turn on debugging output
# tout.Init(tout.DEBUG)
@@ -145,7 +187,10 @@
def tearDown(self):
"""Remove the temporary output directory"""
- tools._FinaliseForTest()
+ if self.preserve_outdirs:
+ print('Preserving output dir: %s' % tools.outdir)
+ else:
+ tools._FinaliseForTest()
@classmethod
def _ResetDtbs(self):
@@ -167,7 +212,7 @@
result.stdout + result.stderr))
return result
- def _DoBinman(self, *args):
+ def _DoBinman(self, *argv):
"""Run binman using directly (in the same process)
Args:
@@ -175,16 +220,14 @@
Returns:
Return value (0 for success)
"""
- args = list(args)
- if '-D' in sys.argv:
- args = args + ['-D']
- (options, args) = cmdline.ParseArgs(args)
- options.pager = 'binman-invalid-pager'
- options.build_dir = self._indir
+ argv = list(argv)
+ args = cmdline.ParseArgs(argv)
+ args.pager = 'binman-invalid-pager'
+ args.build_dir = self._indir
# For testing, you can force an increase in verbosity here
- # options.verbosity = tout.DEBUG
- return control.Binman(options, args)
+ # args.verbosity = tout.DEBUG
+ return control.Binman(args)
def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
entry_args=None, images=None, use_real_dtb=False,
@@ -202,17 +245,23 @@
value: value of that arg
images: List of image names to build
"""
- args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
+ args = []
if debug:
args.append('-D')
+ if verbosity is not None:
+ args.append('-v%d' % verbosity)
+ elif self.verbosity:
+ args.append('-v%d' % self.verbosity)
+ if self.toolpath:
+ for path in self.toolpath:
+ args += ['--toolpath', path]
+ args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
if map:
args.append('-m')
if update_dtb:
- args.append('-up')
+ args.append('-u')
if not use_real_dtb:
args.append('--fake-dtb')
- if verbosity is not None:
- args.append('-v%d' % verbosity)
if entry_args:
for arg, value in entry_args.items():
args.append('-a%s=%s' % (arg, value))
@@ -323,6 +372,17 @@
if reset_dtbs and use_real_dtb:
self._ResetDtbs()
+ def _DoReadFileRealDtb(self, fname):
+ """Run binman with a real .dtb file and return the resulting data
+
+ Args:
+ fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
+
+ Returns:
+ Resulting image contents
+ """
+ return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
+
def _DoReadFile(self, fname, use_real_dtb=False):
"""Helper function which discards the device-tree binary
@@ -419,16 +479,16 @@
"""
return struct.unpack('>L', dtb[4:8])[0]
- def _GetPropTree(self, dtb, prop_names):
+ def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
def AddNode(node, path):
if node.name != '/':
path += '/' + node.name
+ for prop in node.props.values():
+ if prop.name in prop_names:
+ prop_path = path + ':' + prop.name
+ tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
+ prop.value)
for subnode in node.subnodes:
- for prop in subnode.props.values():
- if prop.name in prop_names:
- prop_path = path + '/' + subnode.name + ':' + prop.name
- tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
- prop.value)
AddNode(subnode, path)
tree = {}
@@ -470,20 +530,20 @@
"""Test that we can run it with a specific board"""
self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
- result = self._DoBinman('-b', 'sandbox')
+ result = self._DoBinman('build', '-b', 'sandbox')
self.assertEqual(0, result)
def testNeedBoard(self):
"""Test that we get an error when no board ius supplied"""
with self.assertRaises(ValueError) as e:
- result = self._DoBinman()
+ result = self._DoBinman('build')
self.assertIn("Must provide a board to process (use -b <board>)",
str(e.exception))
def testMissingDt(self):
"""Test that an invalid device-tree file generates an error"""
with self.assertRaises(Exception) as e:
- self._RunBinman('-d', 'missing_file')
+ self._RunBinman('build', '-d', 'missing_file')
# We get one error from libfdt, and a different one from fdtget.
self.AssertInList(["Couldn't open blob from 'missing_file'",
'No such file or directory'], str(e.exception))
@@ -495,26 +555,26 @@
will come from the device-tree compiler (dtc).
"""
with self.assertRaises(Exception) as e:
- self._RunBinman('-d', self.TestFile('001_invalid.dts'))
+ self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
self.assertIn("FATAL ERROR: Unable to parse input tree",
str(e.exception))
def testMissingNode(self):
"""Test that a device tree without a 'binman' node generates an error"""
with self.assertRaises(Exception) as e:
- self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
+ self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
self.assertIn("does not have a 'binman' node", str(e.exception))
def testEmpty(self):
"""Test that an empty binman node works OK (i.e. does nothing)"""
- result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
+ result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
self.assertEqual(0, len(result.stderr))
self.assertEqual(0, result.return_code)
def testInvalidEntry(self):
"""Test that an invalid entry is flagged"""
with self.assertRaises(Exception) as e:
- result = self._RunBinman('-d',
+ result = self._RunBinman('build', '-d',
self.TestFile('004_invalid_entry.dts'))
self.assertIn("Unknown entry type 'not-a-valid-type' in node "
"'/binman/not-a-valid-type'", str(e.exception))
@@ -526,7 +586,7 @@
def testSimpleDebug(self):
"""Test a simple binman run with debugging enabled"""
- data = self._DoTestFile('005_simple.dts', debug=True)
+ self._DoTestFile('005_simple.dts', debug=True)
def testDual(self):
"""Test that we can handle creating two images
@@ -537,7 +597,7 @@
self.assertEqual(0, retcode)
image = control.images['image1']
- self.assertEqual(len(U_BOOT_DATA), image._size)
+ self.assertEqual(len(U_BOOT_DATA), image.size)
fname = tools.GetOutputFilename('image1.bin')
self.assertTrue(os.path.exists(fname))
with open(fname, 'rb') as fd:
@@ -545,7 +605,7 @@
self.assertEqual(U_BOOT_DATA, data)
image = control.images['image2']
- self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
+ self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
fname = tools.GetOutputFilename('image2.bin')
self.assertTrue(os.path.exists(fname))
with open(fname, 'rb') as fd:
@@ -601,7 +661,7 @@
self.assertEqual(61, entry.offset)
self.assertEqual(len(U_BOOT_DATA), entry.size)
- self.assertEqual(65, image._size)
+ self.assertEqual(65, image.size)
def testPackExtra(self):
"""Test that extra packing feature works as expected"""
@@ -645,7 +705,7 @@
self.assertEqual(64, entry.size)
self.CheckNoGaps(entries)
- self.assertEqual(128, image._size)
+ self.assertEqual(128, image.size)
def testPackAlignPowerOf2(self):
"""Test that invalid entry alignment is detected"""
@@ -703,7 +763,7 @@
self.assertEqual(0, retcode)
self.assertIn('image', control.images)
image = control.images['image']
- self.assertEqual(7, image._size)
+ self.assertEqual(7, image.size)
def testPackImageSizeAlign(self):
"""Test that image size alignemnt works as expected"""
@@ -711,7 +771,7 @@
self.assertEqual(0, retcode)
self.assertIn('image', control.images)
image = control.images['image']
- self.assertEqual(16, image._size)
+ self.assertEqual(16, image.size)
def testPackInvalidImageAlign(self):
"""Test that invalid image alignment is detected"""
@@ -724,7 +784,7 @@
"""Test that invalid image alignment is detected"""
with self.assertRaises(ValueError) as e:
self._DoTestFile('020_pack_inv_image_align_power2.dts')
- self.assertIn("Section '/binman': Alignment size 131 must be a power of "
+ self.assertIn("Image '/binman': Alignment size 131 must be a power of "
"two", str(e.exception))
def testImagePadByte(self):
@@ -775,7 +835,7 @@
"""Test that the end-at-4gb property requires a size property"""
with self.assertRaises(ValueError) as e:
self._DoTestFile('027_pack_4gb_no_size.dts')
- self.assertIn("Section '/binman': Section size must be provided when "
+ self.assertIn("Image '/binman': Section size must be provided when "
"using end-at-4gb", str(e.exception))
def test4gbAndSkipAtStartTogether(self):
@@ -783,7 +843,7 @@
together"""
with self.assertRaises(ValueError) as e:
self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
- self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
+ self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
"'skip-at-start'", str(e.exception))
def testPackX86RomOutside(self):
@@ -806,8 +866,8 @@
TestFunctional._MakeInputFile('descriptor.bin', b'')
with self.assertRaises(ValueError) as e:
self._DoTestFile('031_x86-rom-me.dts')
- self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
- "signature", str(e.exception))
+ self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
+ str(e.exception))
def testPackX86RomBadDesc(self):
"""Test that the Intel requires a descriptor entry"""
@@ -820,6 +880,9 @@
def testPackX86RomMe(self):
"""Test that an x86 ROM with an ME region can be created"""
data = self._DoReadFile('031_x86-rom-me.dts')
+ expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
+ if data[:0x1000] != expected_desc:
+ self.fail('Expected descriptor binary at start of image')
self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
def testPackVga(self):
@@ -1156,16 +1219,20 @@
"""Test that obtaining the contents works as expected"""
with self.assertRaises(ValueError) as e:
self._DoReadFile('057_unknown_contents.dts', True)
- self.assertIn("Section '/binman': Internal error: Could not complete "
+ self.assertIn("Image '/binman': Internal error: Could not complete "
"processing of contents: remaining [<_testing.Entry__testing ",
str(e.exception))
def testBadChangeSize(self):
"""Test that trying to change the size of an entry fails"""
- with self.assertRaises(ValueError) as e:
- self._DoReadFile('059_change_size.dts', True)
- self.assertIn("Node '/binman/_testing': Cannot update entry size from "
- '2 to 1', str(e.exception))
+ try:
+ state.SetAllowEntryExpansion(False)
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFile('059_change_size.dts', True)
+ self.assertIn("Node '/binman/_testing': Cannot update entry size from 1 to 2",
+ str(e.exception))
+ finally:
+ state.SetAllowEntryExpansion(True)
def testUpdateFdt(self):
"""Test that we can update the device tree with offset/size info"""
@@ -1242,7 +1309,8 @@
def testEntryArgsInvalidFormat(self):
"""Test that an invalid entry-argument format is detected"""
- args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
+ args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
+ '-ano-value']
with self.assertRaises(ValueError) as e:
self._DoBinman(*args)
self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
@@ -1286,7 +1354,7 @@
expected = (tools.ToBytes(TEXT_DATA) +
tools.GetBytes(0, 8 - len(TEXT_DATA)) +
tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
- b'some text')
+ b'some text' + b'more text')
self.assertEqual(expected, data)
def testEntryDocs(self):
@@ -1471,7 +1539,7 @@
expected = 'Skipping images: image1'
# We should only get the expected message in verbose mode
- for verbosity in (None, 2):
+ for verbosity in (0, 2):
with test_util.capture_sys_output() as (stdout, stderr):
retcode = self._DoTestFile('006_dual_image.dts',
verbosity=verbosity,
@@ -1487,8 +1555,7 @@
def testUpdateFdtAll(self):
"""Test that all device trees are updated with offset/size info"""
- data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
- use_real_dtb=True, update_dtb=True)
+ data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
base_expected = {
'section:image-pos': 0,
@@ -1560,19 +1627,11 @@
self._ResetDtbs()
def _decompress(self, data):
- out = os.path.join(self._indir, 'lz4.tmp')
- with open(out, 'wb') as fd:
- fd.write(data)
- return tools.Run('lz4', '-dc', out, binary=True)
- '''
- try:
- orig = lz4.frame.decompress(data)
- except AttributeError:
- orig = lz4.decompress(data)
- '''
+ return tools.Decompress(data, 'lz4')
def testCompress(self):
"""Test compression of blobs"""
+ self._CheckLz4()
data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
use_real_dtb=True, update_dtb=True)
dtb = fdt.Fdt(out_dtb_fname)
@@ -1594,12 +1653,13 @@
def testFilesCompress(self):
"""Test bringing in multiple files and compressing them"""
+ self._CheckLz4()
data = self._DoReadFile('085_files_compress.dts')
image = control.images['image']
entries = image.GetEntries()
files = entries['files']
- entries = files._section._entries
+ entries = files._entries
orig = b''
for i in range(1, 3):
@@ -1755,10 +1815,12 @@
"""Basic test of ELF entries"""
self._SetupSplElf()
with open(self.TestFile('bss_data'), 'rb') as fd:
+ TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
+ with open(self.TestFile('bss_data'), 'rb') as fd:
TestFunctional._MakeInputFile('-boot', fd.read())
data = self._DoReadFile('096_elf.dts')
- def testElfStripg(self):
+ def testElfStrip(self):
"""Basic test of ELF entries"""
self._SetupSplElf()
with open(self.TestFile('bss_data'), 'rb') as fd:
@@ -1784,7 +1846,7 @@
<none> 00000003 00000004 u-boot-align
''', map_data)
- def testPacRefCode(self):
+ def testPackRefCode(self):
"""Test that an image with an Intel Reference code binary works"""
data = self._DoReadFile('100_intel_refcode.dts')
self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
@@ -1810,6 +1872,853 @@
tools.GetBytes(0x26, 4) + U_BOOT_DATA +
tools.GetBytes(0x26, 8))
+ def testCbfsRaw(self):
+ """Test base handling of a Coreboot Filesystem (CBFS)
+
+ The exact contents of the CBFS is verified by similar tests in
+ cbfs_util_test.py. The tests here merely check that the files added to
+ the CBFS can be found in the final image.
+ """
+ data = self._DoReadFile('102_cbfs_raw.dts')
+ size = 0xb0
+
+ cbfs = cbfs_util.CbfsReader(data)
+ self.assertEqual(size, cbfs.rom_size)
+
+ self.assertIn('u-boot-dtb', cbfs.files)
+ cfile = cbfs.files['u-boot-dtb']
+ self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
+
+ def testCbfsArch(self):
+ """Test on non-x86 architecture"""
+ data = self._DoReadFile('103_cbfs_raw_ppc.dts')
+ size = 0x100
+
+ cbfs = cbfs_util.CbfsReader(data)
+ self.assertEqual(size, cbfs.rom_size)
+
+ self.assertIn('u-boot-dtb', cbfs.files)
+ cfile = cbfs.files['u-boot-dtb']
+ self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
+
+ def testCbfsStage(self):
+ """Tests handling of a Coreboot Filesystem (CBFS)"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
+ elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
+ elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
+ size = 0xb0
+
+ data = self._DoReadFile('104_cbfs_stage.dts')
+ cbfs = cbfs_util.CbfsReader(data)
+ self.assertEqual(size, cbfs.rom_size)
+
+ self.assertIn('u-boot', cbfs.files)
+ cfile = cbfs.files['u-boot']
+ self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
+
+ def testCbfsRawCompress(self):
+ """Test handling of compressing raw files"""
+ self._CheckLz4()
+ data = self._DoReadFile('105_cbfs_raw_compress.dts')
+ size = 0x140
+
+ cbfs = cbfs_util.CbfsReader(data)
+ self.assertIn('u-boot', cbfs.files)
+ cfile = cbfs.files['u-boot']
+ self.assertEqual(COMPRESS_DATA, cfile.data)
+
+ def testCbfsBadArch(self):
+ """Test handling of a bad architecture"""
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFile('106_cbfs_bad_arch.dts')
+ self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
+
+ def testCbfsNoSize(self):
+ """Test handling of a missing size property"""
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFile('107_cbfs_no_size.dts')
+ self.assertIn('entry must have a size property', str(e.exception))
+
+ def testCbfsNoCOntents(self):
+ """Test handling of a CBFS entry which does not provide contentsy"""
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFile('108_cbfs_no_contents.dts')
+ self.assertIn('Could not complete processing of contents',
+ str(e.exception))
+
+ def testCbfsBadCompress(self):
+ """Test handling of a bad architecture"""
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFile('109_cbfs_bad_compress.dts')
+ self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
+ str(e.exception))
+
+ def testCbfsNamedEntries(self):
+ """Test handling of named entries"""
+ data = self._DoReadFile('110_cbfs_name.dts')
+
+ cbfs = cbfs_util.CbfsReader(data)
+ self.assertIn('FRED', cbfs.files)
+ cfile1 = cbfs.files['FRED']
+ self.assertEqual(U_BOOT_DATA, cfile1.data)
+
+ self.assertIn('hello', cbfs.files)
+ cfile2 = cbfs.files['hello']
+ self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
+
+ def _SetupIfwi(self, fname):
+ """Set up to run an IFWI test
+
+ Args:
+ fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
+ """
+ self._SetupSplElf()
+
+ # Intel Integrated Firmware Image (IFWI) file
+ with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
+ data = fd.read()
+ TestFunctional._MakeInputFile(fname,data)
+
+ def _CheckIfwi(self, data):
+ """Check that an image with an IFWI contains the correct output
+
+ Args:
+ data: Conents of output file
+ """
+ expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
+ if data[:0x1000] != expected_desc:
+ self.fail('Expected descriptor binary at start of image')
+
+ # We expect to find the TPL wil in subpart IBBP entry IBBL
+ image_fname = tools.GetOutputFilename('image.bin')
+ tpl_fname = tools.GetOutputFilename('tpl.out')
+ tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
+ subpart='IBBP', entry_name='IBBL')
+
+ tpl_data = tools.ReadFile(tpl_fname)
+ self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
+
+ def testPackX86RomIfwi(self):
+ """Test that an x86 ROM with Integrated Firmware Image can be created"""
+ self._SetupIfwi('fitimage.bin')
+ data = self._DoReadFile('111_x86-rom-ifwi.dts')
+ self._CheckIfwi(data)
+
+ def testPackX86RomIfwiNoDesc(self):
+ """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
+ self._SetupIfwi('ifwi.bin')
+ data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
+ self._CheckIfwi(data)
+
+ def testPackX86RomIfwiNoData(self):
+ """Test that an x86 ROM with IFWI handles missing data"""
+ self._SetupIfwi('ifwi.bin')
+ with self.assertRaises(ValueError) as e:
+ data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
+ self.assertIn('Could not complete processing of contents',
+ str(e.exception))
+
+ def testCbfsOffset(self):
+ """Test a CBFS with files at particular offsets
+
+ Like all CFBS tests, this is just checking the logic that calls
+ cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
+ """
+ data = self._DoReadFile('114_cbfs_offset.dts')
+ size = 0x200
+
+ cbfs = cbfs_util.CbfsReader(data)
+ self.assertEqual(size, cbfs.rom_size)
+
+ self.assertIn('u-boot', cbfs.files)
+ cfile = cbfs.files['u-boot']
+ self.assertEqual(U_BOOT_DATA, cfile.data)
+ self.assertEqual(0x40, cfile.cbfs_offset)
+
+ self.assertIn('u-boot-dtb', cbfs.files)
+ cfile2 = cbfs.files['u-boot-dtb']
+ self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
+ self.assertEqual(0x140, cfile2.cbfs_offset)
+
+ def testFdtmap(self):
+ """Test an FDT map can be inserted in the image"""
+ data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
+ fdtmap_data = data[len(U_BOOT_DATA):]
+ magic = fdtmap_data[:8]
+ self.assertEqual('_FDTMAP_', magic)
+ self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
+
+ fdt_data = fdtmap_data[16:]
+ dtb = fdt.Fdt.FromData(fdt_data)
+ dtb.Scan()
+ props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'],
+ prefix='/')
+ self.assertEqual({
+ 'image-pos': 0,
+ 'offset': 0,
+ 'u-boot:offset': 0,
+ 'u-boot:size': len(U_BOOT_DATA),
+ 'u-boot:image-pos': 0,
+ 'fdtmap:image-pos': 4,
+ 'fdtmap:offset': 4,
+ 'fdtmap:size': len(fdtmap_data),
+ 'size': len(data),
+ }, props)
+
+ def testFdtmapNoMatch(self):
+ """Check handling of an FDT map when the section cannot be found"""
+ self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
+
+ # Mangle the section name, which should cause a mismatch between the
+ # correct FDT path and the one expected by the section
+ image = control.images['image']
+ image._node.path += '-suffix'
+ entries = image.GetEntries()
+ fdtmap = entries['fdtmap']
+ with self.assertRaises(ValueError) as e:
+ fdtmap._GetFdtmap()
+ self.assertIn("Cannot locate node for path '/binman-suffix'",
+ str(e.exception))
+
+ def testFdtmapHeader(self):
+ """Test an FDT map and image header can be inserted in the image"""
+ data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
+ fdtmap_pos = len(U_BOOT_DATA)
+ fdtmap_data = data[fdtmap_pos:]
+ fdt_data = fdtmap_data[16:]
+ dtb = fdt.Fdt.FromData(fdt_data)
+ fdt_size = dtb.GetFdtObj().totalsize()
+ hdr_data = data[-8:]
+ self.assertEqual('BinM', hdr_data[:4])
+ offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
+ self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
+
+ def testFdtmapHeaderStart(self):
+ """Test an image header can be inserted at the image start"""
+ data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
+ fdtmap_pos = 0x100 + len(U_BOOT_DATA)
+ hdr_data = data[:8]
+ self.assertEqual('BinM', hdr_data[:4])
+ offset = struct.unpack('<I', hdr_data[4:])[0]
+ self.assertEqual(fdtmap_pos, offset)
+
+ def testFdtmapHeaderPos(self):
+ """Test an image header can be inserted at a chosen position"""
+ data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
+ fdtmap_pos = 0x100 + len(U_BOOT_DATA)
+ hdr_data = data[0x80:0x88]
+ self.assertEqual('BinM', hdr_data[:4])
+ offset = struct.unpack('<I', hdr_data[4:])[0]
+ self.assertEqual(fdtmap_pos, offset)
+
+ def testHeaderMissingFdtmap(self):
+ """Test an image header requires an fdtmap"""
+ with self.assertRaises(ValueError) as e:
+ self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
+ self.assertIn("'image_header' section must have an 'fdtmap' sibling",
+ str(e.exception))
+
+ def testHeaderNoLocation(self):
+ """Test an image header with a no specified location is detected"""
+ with self.assertRaises(ValueError) as e:
+ self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
+ self.assertIn("Invalid location 'None', expected 'start' or 'end'",
+ str(e.exception))
+
+ def testEntryExpand(self):
+ """Test expanding an entry after it is packed"""
+ data = self._DoReadFile('121_entry_expand.dts')
+ self.assertEqual(b'aa', data[:2])
+ self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
+ self.assertEqual(b'aa', data[-2:])
+
+ def testEntryExpandBad(self):
+ """Test expanding an entry after it is packed, twice"""
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFile('122_entry_expand_twice.dts')
+ self.assertIn("Image '/binman': Entries expanded after packing",
+ str(e.exception))
+
+ def testEntryExpandSection(self):
+ """Test expanding an entry within a section after it is packed"""
+ data = self._DoReadFile('123_entry_expand_section.dts')
+ self.assertEqual(b'aa', data[:2])
+ self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
+ self.assertEqual(b'aa', data[-2:])
+
+ def testCompressDtb(self):
+ """Test that compress of device-tree files is supported"""
+ self._CheckLz4()
+ data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
+ self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
+ comp_data = data[len(U_BOOT_DATA):]
+ orig = self._decompress(comp_data)
+ dtb = fdt.Fdt.FromData(orig)
+ dtb.Scan()
+ props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
+ expected = {
+ 'u-boot:size': len(U_BOOT_DATA),
+ 'u-boot-dtb:uncomp-size': len(orig),
+ 'u-boot-dtb:size': len(comp_data),
+ 'size': len(data),
+ }
+ self.assertEqual(expected, props)
+
+ def testCbfsUpdateFdt(self):
+ """Test that we can update the device tree with CBFS offset/size info"""
+ self._CheckLz4()
+ data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
+ update_dtb=True)
+ dtb = fdt.Fdt(out_dtb_fname)
+ dtb.Scan()
+ props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
+ 'uncomp-size'])
+ del props['cbfs/u-boot:size']
+ self.assertEqual({
+ 'offset': 0,
+ 'size': len(data),
+ 'image-pos': 0,
+ 'cbfs:offset': 0,
+ 'cbfs:size': len(data),
+ 'cbfs:image-pos': 0,
+ 'cbfs/u-boot:offset': 0x38,
+ 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
+ 'cbfs/u-boot:image-pos': 0x38,
+ 'cbfs/u-boot-dtb:offset': 0xb8,
+ 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
+ 'cbfs/u-boot-dtb:image-pos': 0xb8,
+ }, props)
+
+ def testCbfsBadType(self):
+ """Test an image header with a no specified location is detected"""
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFile('126_cbfs_bad_type.dts')
+ self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
+
+ def testList(self):
+ """Test listing the files in an image"""
+ self._CheckLz4()
+ data = self._DoReadFile('127_list.dts')
+ image = control.images['image']
+ entries = image.BuildEntryList()
+ self.assertEqual(7, len(entries))
+
+ ent = entries[0]
+ self.assertEqual(0, ent.indent)
+ self.assertEqual('main-section', ent.name)
+ self.assertEqual('section', ent.etype)
+ self.assertEqual(len(data), ent.size)
+ self.assertEqual(0, ent.image_pos)
+ self.assertEqual(None, ent.uncomp_size)
+ self.assertEqual(0, ent.offset)
+
+ ent = entries[1]
+ self.assertEqual(1, ent.indent)
+ self.assertEqual('u-boot', ent.name)
+ self.assertEqual('u-boot', ent.etype)
+ self.assertEqual(len(U_BOOT_DATA), ent.size)
+ self.assertEqual(0, ent.image_pos)
+ self.assertEqual(None, ent.uncomp_size)
+ self.assertEqual(0, ent.offset)
+
+ ent = entries[2]
+ self.assertEqual(1, ent.indent)
+ self.assertEqual('section', ent.name)
+ self.assertEqual('section', ent.etype)
+ section_size = ent.size
+ self.assertEqual(0x100, ent.image_pos)
+ self.assertEqual(None, ent.uncomp_size)
+ self.assertEqual(0x100, ent.offset)
+
+ ent = entries[3]
+ self.assertEqual(2, ent.indent)
+ self.assertEqual('cbfs', ent.name)
+ self.assertEqual('cbfs', ent.etype)
+ self.assertEqual(0x400, ent.size)
+ self.assertEqual(0x100, ent.image_pos)
+ self.assertEqual(None, ent.uncomp_size)
+ self.assertEqual(0, ent.offset)
+
+ ent = entries[4]
+ self.assertEqual(3, ent.indent)
+ self.assertEqual('u-boot', ent.name)
+ self.assertEqual('u-boot', ent.etype)
+ self.assertEqual(len(U_BOOT_DATA), ent.size)
+ self.assertEqual(0x138, ent.image_pos)
+ self.assertEqual(None, ent.uncomp_size)
+ self.assertEqual(0x38, ent.offset)
+
+ ent = entries[5]
+ self.assertEqual(3, ent.indent)
+ self.assertEqual('u-boot-dtb', ent.name)
+ self.assertEqual('text', ent.etype)
+ self.assertGreater(len(COMPRESS_DATA), ent.size)
+ self.assertEqual(0x178, ent.image_pos)
+ self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
+ self.assertEqual(0x78, ent.offset)
+
+ ent = entries[6]
+ self.assertEqual(2, ent.indent)
+ self.assertEqual('u-boot-dtb', ent.name)
+ self.assertEqual('u-boot-dtb', ent.etype)
+ self.assertEqual(0x500, ent.image_pos)
+ self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
+ dtb_size = ent.size
+ # Compressing this data expands it since headers are added
+ self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
+ self.assertEqual(0x400, ent.offset)
+
+ self.assertEqual(len(data), 0x100 + section_size)
+ self.assertEqual(section_size, 0x400 + dtb_size)
+
+ def testFindFdtmap(self):
+ """Test locating an FDT map in an image"""
+ self._CheckLz4()
+ data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
+ image = control.images['image']
+ entries = image.GetEntries()
+ entry = entries['fdtmap']
+ self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
+
+ def testFindFdtmapMissing(self):
+ """Test failing to locate an FDP map"""
+ data = self._DoReadFile('005_simple.dts')
+ self.assertEqual(None, fdtmap.LocateFdtmap(data))
+
+ def testFindImageHeader(self):
+ """Test locating a image header"""
+ self._CheckLz4()
+ data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
+ image = control.images['image']
+ entries = image.GetEntries()
+ entry = entries['fdtmap']
+ # The header should point to the FDT map
+ self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
+
+ def testFindImageHeaderStart(self):
+ """Test locating a image header located at the start of an image"""
+ data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
+ image = control.images['image']
+ entries = image.GetEntries()
+ entry = entries['fdtmap']
+ # The header should point to the FDT map
+ self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
+
+ def testFindImageHeaderMissing(self):
+ """Test failing to locate an image header"""
+ data = self._DoReadFile('005_simple.dts')
+ self.assertEqual(None, image_header.LocateHeaderOffset(data))
+
+ def testReadImage(self):
+ """Test reading an image and accessing its FDT map"""
+ self._CheckLz4()
+ data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ orig_image = control.images['image']
+ image = Image.FromFile(image_fname)
+ self.assertEqual(orig_image.GetEntries().keys(),
+ image.GetEntries().keys())
+
+ orig_entry = orig_image.GetEntries()['fdtmap']
+ entry = image.GetEntries()['fdtmap']
+ self.assertEquals(orig_entry.offset, entry.offset)
+ self.assertEquals(orig_entry.size, entry.size)
+ self.assertEquals(orig_entry.image_pos, entry.image_pos)
+
+ def testReadImageNoHeader(self):
+ """Test accessing an image's FDT map without an image header"""
+ self._CheckLz4()
+ data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ image = Image.FromFile(image_fname)
+ self.assertTrue(isinstance(image, Image))
+ self.assertEqual('image', image.image_name)
+
+ def testReadImageFail(self):
+ """Test failing to read an image image's FDT map"""
+ self._DoReadFile('005_simple.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ with self.assertRaises(ValueError) as e:
+ image = Image.FromFile(image_fname)
+ self.assertIn("Cannot find FDT map in image", str(e.exception))
+
+ def testListCmd(self):
+ """Test listing the files in an image using an Fdtmap"""
+ self._CheckLz4()
+ data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
+
+ # lz4 compression size differs depending on the version
+ image = control.images['image']
+ entries = image.GetEntries()
+ section_size = entries['section'].size
+ fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
+ fdtmap_offset = entries['fdtmap'].offset
+
+ image_fname = tools.GetOutputFilename('image.bin')
+ with test_util.capture_sys_output() as (stdout, stderr):
+ self._DoBinman('ls', '-i', image_fname)
+ lines = stdout.getvalue().splitlines()
+ expected = [
+'Name Image-pos Size Entry-type Offset Uncomp-size',
+'----------------------------------------------------------------------',
+'main-section 0 c00 section 0',
+' u-boot 0 4 u-boot 0',
+' section 100 %x section 100' % section_size,
+' cbfs 100 400 cbfs 0',
+' u-boot 138 4 u-boot 38',
+' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
+' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
+' fdtmap %x 395 fdtmap %x' %
+ (fdtmap_offset, fdtmap_offset),
+' image-header bf8 8 image-header bf8',
+ ]
+ self.assertEqual(expected, lines)
+
+ def testListCmdFail(self):
+ """Test failing to list an image"""
+ self._DoReadFile('005_simple.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ with self.assertRaises(ValueError) as e:
+ self._DoBinman('ls', '-i', image_fname)
+ self.assertIn("Cannot find FDT map in image", str(e.exception))
+
+ def _RunListCmd(self, paths, expected):
+ """List out entries and check the result
+
+ Args:
+ paths: List of paths to pass to the list command
+ expected: Expected list of filenames to be returned, in order
+ """
+ self._CheckLz4()
+ self._DoReadFileRealDtb('130_list_fdtmap.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ image = Image.FromFile(image_fname)
+ lines = image.GetListEntries(paths)[1]
+ files = [line[0].strip() for line in lines[1:]]
+ self.assertEqual(expected, files)
+
+ def testListCmdSection(self):
+ """Test listing the files in a section"""
+ self._RunListCmd(['section'],
+ ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
+
+ def testListCmdFile(self):
+ """Test listing a particular file"""
+ self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
+
+ def testListCmdWildcard(self):
+ """Test listing a wildcarded file"""
+ self._RunListCmd(['*boot*'],
+ ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
+
+ def testListCmdWildcardMulti(self):
+ """Test listing a wildcarded file"""
+ self._RunListCmd(['*cb*', '*head*'],
+ ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
+
+ def testListCmdEmpty(self):
+ """Test listing a wildcarded file"""
+ self._RunListCmd(['nothing'], [])
+
+ def testListCmdPath(self):
+ """Test listing the files in a sub-entry of a section"""
+ self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
+
+ def _RunExtractCmd(self, entry_name, decomp=True):
+ """Extract an entry from an image
+
+ Args:
+ entry_name: Entry name to extract
+ decomp: True to decompress the data if compressed, False to leave
+ it in its raw uncompressed format
+
+ Returns:
+ data from entry
+ """
+ self._CheckLz4()
+ self._DoReadFileRealDtb('130_list_fdtmap.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ return control.ReadEntry(image_fname, entry_name, decomp)
+
+ def testExtractSimple(self):
+ """Test extracting a single file"""
+ data = self._RunExtractCmd('u-boot')
+ self.assertEqual(U_BOOT_DATA, data)
+
+ def testExtractSection(self):
+ """Test extracting the files in a section"""
+ data = self._RunExtractCmd('section')
+ cbfs_data = data[:0x400]
+ cbfs = cbfs_util.CbfsReader(cbfs_data)
+ self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
+ dtb_data = data[0x400:]
+ dtb = self._decompress(dtb_data)
+ self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
+
+ def testExtractCompressed(self):
+ """Test extracting compressed data"""
+ data = self._RunExtractCmd('section/u-boot-dtb')
+ self.assertEqual(EXTRACT_DTB_SIZE, len(data))
+
+ def testExtractRaw(self):
+ """Test extracting compressed data without decompressing it"""
+ data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
+ dtb = self._decompress(data)
+ self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
+
+ def testExtractCbfs(self):
+ """Test extracting CBFS data"""
+ data = self._RunExtractCmd('section/cbfs/u-boot')
+ self.assertEqual(U_BOOT_DATA, data)
+
+ def testExtractCbfsCompressed(self):
+ """Test extracting CBFS compressed data"""
+ data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
+ self.assertEqual(EXTRACT_DTB_SIZE, len(data))
+
+ def testExtractCbfsRaw(self):
+ """Test extracting CBFS compressed data without decompressing it"""
+ data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
+ dtb = tools.Decompress(data, 'lzma')
+ self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
+
+ def testExtractBadEntry(self):
+ """Test extracting a bad section path"""
+ with self.assertRaises(ValueError) as e:
+ self._RunExtractCmd('section/does-not-exist')
+ self.assertIn("Entry 'does-not-exist' not found in '/section'",
+ str(e.exception))
+
+ def testExtractMissingFile(self):
+ """Test extracting file that does not exist"""
+ with self.assertRaises(IOError) as e:
+ control.ReadEntry('missing-file', 'name')
+
+ def testExtractBadFile(self):
+ """Test extracting an invalid file"""
+ fname = os.path.join(self._indir, 'badfile')
+ tools.WriteFile(fname, b'')
+ with self.assertRaises(ValueError) as e:
+ control.ReadEntry(fname, 'name')
+
+ def testExtractCmd(self):
+ """Test extracting a file fron an image on the command line"""
+ self._CheckLz4()
+ self._DoReadFileRealDtb('130_list_fdtmap.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ fname = os.path.join(self._indir, 'output.extact')
+ with test_util.capture_sys_output() as (stdout, stderr):
+ self._DoBinman('extract', '-i', image_fname, 'u-boot', '-f', fname)
+ data = tools.ReadFile(fname)
+ self.assertEqual(U_BOOT_DATA, data)
+
+ def testExtractOneEntry(self):
+ """Test extracting a single entry fron an image """
+ self._CheckLz4()
+ self._DoReadFileRealDtb('130_list_fdtmap.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ fname = os.path.join(self._indir, 'output.extact')
+ control.ExtractEntries(image_fname, fname, None, ['u-boot'])
+ data = tools.ReadFile(fname)
+ self.assertEqual(U_BOOT_DATA, data)
+
+ def _CheckExtractOutput(self, decomp):
+ """Helper to test file output with and without decompression
+
+ Args:
+ decomp: True to decompress entry data, False to output it raw
+ """
+ def _CheckPresent(entry_path, expect_data, expect_size=None):
+ """Check and remove expected file
+
+ This checks the data/size of a file and removes the file both from
+ the outfiles set and from the output directory. Once all files are
+ processed, both the set and directory should be empty.
+
+ Args:
+ entry_path: Entry path
+ expect_data: Data to expect in file, or None to skip check
+ expect_size: Size of data to expect in file, or None to skip
+ """
+ path = os.path.join(outdir, entry_path)
+ data = tools.ReadFile(path)
+ os.remove(path)
+ if expect_data:
+ self.assertEqual(expect_data, data)
+ elif expect_size:
+ self.assertEqual(expect_size, len(data))
+ outfiles.remove(path)
+
+ def _CheckDirPresent(name):
+ """Remove expected directory
+
+ This gives an error if the directory does not exist as expected
+
+ Args:
+ name: Name of directory to remove
+ """
+ path = os.path.join(outdir, name)
+ os.rmdir(path)
+
+ self._DoReadFileRealDtb('130_list_fdtmap.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ outdir = os.path.join(self._indir, 'extract')
+ einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
+
+ # Create a set of all file that were output (should be 9)
+ outfiles = set()
+ for root, dirs, files in os.walk(outdir):
+ outfiles |= set([os.path.join(root, fname) for fname in files])
+ self.assertEqual(9, len(outfiles))
+ self.assertEqual(9, len(einfos))
+
+ image = control.images['image']
+ entries = image.GetEntries()
+
+ # Check the 9 files in various ways
+ section = entries['section']
+ section_entries = section.GetEntries()
+ cbfs_entries = section_entries['cbfs'].GetEntries()
+ _CheckPresent('u-boot', U_BOOT_DATA)
+ _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
+ dtb_len = EXTRACT_DTB_SIZE
+ if not decomp:
+ dtb_len = cbfs_entries['u-boot-dtb'].size
+ _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
+ if not decomp:
+ dtb_len = section_entries['u-boot-dtb'].size
+ _CheckPresent('section/u-boot-dtb', None, dtb_len)
+
+ fdtmap = entries['fdtmap']
+ _CheckPresent('fdtmap', fdtmap.data)
+ hdr = entries['image-header']
+ _CheckPresent('image-header', hdr.data)
+
+ _CheckPresent('section/root', section.data)
+ cbfs = section_entries['cbfs']
+ _CheckPresent('section/cbfs/root', cbfs.data)
+ data = tools.ReadFile(image_fname)
+ _CheckPresent('root', data)
+
+ # There should be no files left. Remove all the directories to check.
+ # If there are any files/dirs remaining, one of these checks will fail.
+ self.assertEqual(0, len(outfiles))
+ _CheckDirPresent('section/cbfs')
+ _CheckDirPresent('section')
+ _CheckDirPresent('')
+ self.assertFalse(os.path.exists(outdir))
+
+ def testExtractAllEntries(self):
+ """Test extracting all entries"""
+ self._CheckLz4()
+ self._CheckExtractOutput(decomp=True)
+
+ def testExtractAllEntriesRaw(self):
+ """Test extracting all entries without decompressing them"""
+ self._CheckLz4()
+ self._CheckExtractOutput(decomp=False)
+
+ def testExtractSelectedEntries(self):
+ """Test extracting some entries"""
+ self._CheckLz4()
+ self._DoReadFileRealDtb('130_list_fdtmap.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ outdir = os.path.join(self._indir, 'extract')
+ einfos = control.ExtractEntries(image_fname, None, outdir,
+ ['*cb*', '*head*'])
+
+ # File output is tested by testExtractAllEntries(), so just check that
+ # the expected entries are selected
+ names = [einfo.name for einfo in einfos]
+ self.assertEqual(names,
+ ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
+
+ def testExtractNoEntryPaths(self):
+ """Test extracting some entries"""
+ self._CheckLz4()
+ self._DoReadFileRealDtb('130_list_fdtmap.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ with self.assertRaises(ValueError) as e:
+ control.ExtractEntries(image_fname, 'fname', None, [])
+ self.assertIn('Must specify an entry path to write with -o',
+ str(e.exception))
+
+ def testExtractTooManyEntryPaths(self):
+ """Test extracting some entries"""
+ self._CheckLz4()
+ self._DoReadFileRealDtb('130_list_fdtmap.dts')
+ image_fname = tools.GetOutputFilename('image.bin')
+ with self.assertRaises(ValueError) as e:
+ control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
+ self.assertIn('Must specify exactly one entry path to write with -o',
+ str(e.exception))
+
+ def testPackAlignSection(self):
+ """Test that sections can have alignment"""
+ self._DoReadFile('131_pack_align_section.dts')
+
+ self.assertIn('image', control.images)
+ image = control.images['image']
+ entries = image.GetEntries()
+ self.assertEqual(3, len(entries))
+
+ # First u-boot
+ self.assertIn('u-boot', entries)
+ entry = entries['u-boot']
+ self.assertEqual(0, entry.offset)
+ self.assertEqual(0, entry.image_pos)
+ self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
+ self.assertEqual(len(U_BOOT_DATA), entry.size)
+
+ # Section0
+ self.assertIn('section0', entries)
+ section0 = entries['section0']
+ self.assertEqual(0x10, section0.offset)
+ self.assertEqual(0x10, section0.image_pos)
+ self.assertEqual(len(U_BOOT_DATA), section0.size)
+
+ # Second u-boot
+ section_entries = section0.GetEntries()
+ self.assertIn('u-boot', section_entries)
+ entry = section_entries['u-boot']
+ self.assertEqual(0, entry.offset)
+ self.assertEqual(0x10, entry.image_pos)
+ self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
+ self.assertEqual(len(U_BOOT_DATA), entry.size)
+
+ # Section1
+ self.assertIn('section1', entries)
+ section1 = entries['section1']
+ self.assertEqual(0x14, section1.offset)
+ self.assertEqual(0x14, section1.image_pos)
+ self.assertEqual(0x20, section1.size)
+
+ # Second u-boot
+ section_entries = section1.GetEntries()
+ self.assertIn('u-boot', section_entries)
+ entry = section_entries['u-boot']
+ self.assertEqual(0, entry.offset)
+ self.assertEqual(0x14, entry.image_pos)
+ self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
+ self.assertEqual(len(U_BOOT_DATA), entry.size)
+
+ # Section2
+ self.assertIn('section2', section_entries)
+ section2 = section_entries['section2']
+ self.assertEqual(0x4, section2.offset)
+ self.assertEqual(0x18, section2.image_pos)
+ self.assertEqual(4, section2.size)
+
+ # Third u-boot
+ section_entries = section2.GetEntries()
+ self.assertIn('u-boot', section_entries)
+ entry = section_entries['u-boot']
+ self.assertEqual(0, entry.offset)
+ self.assertEqual(0x18, entry.image_pos)
+ self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
+ self.assertEqual(len(U_BOOT_DATA), entry.size)
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/image.py b/tools/binman/image.py
index f237ae3..fb6e591 100644
--- a/tools/binman/image.py
+++ b/tools/binman/image.py
@@ -8,15 +8,21 @@
from __future__ import print_function
from collections import OrderedDict
+import fnmatch
from operator import attrgetter
import re
import sys
+from entry import Entry
+from etype import fdtmap
+from etype import image_header
+from etype import section
+import fdt
import fdt_util
-import bsection
import tools
+import tout
-class Image:
+class Image(section.Entry_section):
"""A Image, representing an output from binman
An image is comprised of a collection of entries each containing binary
@@ -24,12 +30,8 @@
This class implements the various operations needed for images.
- Atrtributes:
- _node: Node object that contains the image definition in device tree
- _name: Image name
- _size: Image size in bytes, or None if not known yet
- _filename: Output filename for image
- _sections: Sections present in this image (may be one or more)
+ Attributes:
+ filename: Output filename for image
Args:
test: True if this is being called from a test of Images. This this case
@@ -37,106 +39,94 @@
we create a section manually.
"""
def __init__(self, name, node, test=False):
- self._node = node
- self._name = name
- self._size = None
- self._filename = '%s.bin' % self._name
- if test:
- self._section = bsection.Section('main-section', None, self._node,
- self, True)
- else:
- self._ReadNode()
+ self.image = self
+ section.Entry_section.__init__(self, None, 'section', node, test)
+ self.name = 'main-section'
+ self.image_name = name
+ self._filename = '%s.bin' % self.image_name
+ if not test:
+ filename = fdt_util.GetString(self._node, 'filename')
+ if filename:
+ self._filename = filename
- def _ReadNode(self):
- """Read properties from the image node"""
- self._size = fdt_util.GetInt(self._node, 'size')
- filename = fdt_util.GetString(self._node, 'filename')
- if filename:
- self._filename = filename
- self._section = bsection.Section('main-section', None, self._node, self)
+ @classmethod
+ def FromFile(cls, fname):
+ """Convert an image file into an Image for use in binman
- def GetFdtSet(self):
- """Get the set of device tree files used by this image"""
- return self._section.GetFdtSet()
+ Args:
+ fname: Filename of image file to read
- def ExpandEntries(self):
- """Expand out any entries which have calculated sub-entries
-
- Some entries are expanded out at runtime, e.g. 'files', which produces
- a section containing a list of files. Process these entries so that
- this information is added to the device tree.
- """
- self._section.ExpandEntries()
-
- def AddMissingProperties(self):
- """Add properties that are not present in the device tree
+ Returns:
+ Image object on success
- When binman has completed packing the entries the offset and size of
- each entry are known. But before this the device tree may not specify
- these. Add any missing properties, with a dummy value, so that the
- size of the entry is correct. That way we can insert the correct values
- later.
+ Raises:
+ ValueError if something goes wrong
"""
- self._section.AddMissingProperties()
+ data = tools.ReadFile(fname)
+ size = len(data)
- def ProcessFdt(self, fdt):
- """Allow entries to adjust the device tree
-
- Some entries need to adjust the device tree for their purposes. This
- may involve adding or deleting properties.
- """
- return self._section.ProcessFdt(fdt)
+ # First look for an image header
+ pos = image_header.LocateHeaderOffset(data)
+ if pos is None:
+ # Look for the FDT map
+ pos = fdtmap.LocateFdtmap(data)
+ if pos is None:
+ raise ValueError('Cannot find FDT map in image')
- def GetEntryContents(self):
- """Call ObtainContents() for the section
- """
- self._section.GetEntryContents()
+ # We don't know the FDT size, so check its header first
+ probe_dtb = fdt.Fdt.FromData(
+ data[pos + fdtmap.FDTMAP_HDR_LEN:pos + 256])
+ dtb_size = probe_dtb.GetFdtObj().totalsize()
+ fdtmap_data = data[pos:pos + dtb_size + fdtmap.FDTMAP_HDR_LEN]
+ dtb = fdt.Fdt.FromData(fdtmap_data[fdtmap.FDTMAP_HDR_LEN:])
+ dtb.Scan()
- def GetEntryOffsets(self):
- """Handle entries that want to set the offset/size of other entries
+ # Return an Image with the associated nodes
+ image = Image('image', dtb.GetRoot())
+ image._data = data
+ return image
- This calls each entry's GetOffsets() method. If it returns a list
- of entries to update, it updates them.
- """
- self._section.GetEntryOffsets()
+ def Raise(self, msg):
+ """Convenience function to raise an error referencing an image"""
+ raise ValueError("Image '%s': %s" % (self._node.path, msg))
def PackEntries(self):
"""Pack all entries into the image"""
- self._section.PackEntries()
-
- def CheckSize(self):
- """Check that the image contents does not exceed its size, etc."""
- self._size = self._section.CheckSize()
-
- def CheckEntries(self):
- """Check that entries do not overlap or extend outside the image"""
- self._section.CheckEntries()
-
- def SetCalculatedProperties(self):
- self._section.SetCalculatedProperties()
+ section.Entry_section.Pack(self, 0)
def SetImagePos(self):
- self._section.SetImagePos(0)
+ # This first section in the image so it starts at 0
+ section.Entry_section.SetImagePos(self, 0)
def ProcessEntryContents(self):
"""Call the ProcessContents() method for each entry
This is intended to adjust the contents as needed by the entry type.
+
+ Returns:
+ True if the new data size is OK, False if expansion is needed
"""
- self._section.ProcessEntryContents()
+ sizes_ok = True
+ for entry in self._entries.values():
+ if not entry.ProcessContents():
+ sizes_ok = False
+ tout.Debug("Entry '%s' size change" % self._node.path)
+ return sizes_ok
def WriteSymbols(self):
"""Write symbol values into binary files for access at run time"""
- self._section.WriteSymbols()
+ section.Entry_section.WriteSymbols(self, self)
+
+ def BuildSection(self, fd, base_offset):
+ """Write the section to a file"""
+ fd.seek(base_offset)
+ fd.write(self.GetData())
def BuildImage(self):
"""Write the image to a file"""
fname = tools.GetOutputFilename(self._filename)
with open(fname, 'wb') as fd:
- self._section.BuildSection(fd, 0)
-
- def GetEntries(self):
- return self._section.GetEntries()
+ self.BuildSection(fd, 0)
def WriteMap(self):
"""Write a map of the image to a .map file
@@ -144,10 +134,169 @@
Returns:
Filename of map file written
"""
- filename = '%s.map' % self._name
+ filename = '%s.map' % self.image_name
fname = tools.GetOutputFilename(filename)
with open(fname, 'w') as fd:
print('%8s %8s %8s %s' % ('ImagePos', 'Offset', 'Size', 'Name'),
file=fd)
- self._section.WriteMap(fd, 0)
+ section.Entry_section.WriteMap(self, fd, 0)
return fname
+
+ def BuildEntryList(self):
+ """List the files in an image
+
+ Returns:
+ List of entry.EntryInfo objects describing all entries in the image
+ """
+ entries = []
+ self.ListEntries(entries, 0)
+ return entries
+
+ def FindEntryPath(self, entry_path):
+ """Find an entry at a given path in the image
+
+ Args:
+ entry_path: Path to entry (e.g. /ro-section/u-boot')
+
+ Returns:
+ Entry object corresponding to that past
+
+ Raises:
+ ValueError if no entry found
+ """
+ parts = entry_path.split('/')
+ entries = self.GetEntries()
+ parent = '/'
+ for part in parts:
+ entry = entries.get(part)
+ if not entry:
+ raise ValueError("Entry '%s' not found in '%s'" %
+ (part, parent))
+ parent = entry.GetPath()
+ entries = entry.GetEntries()
+ return entry
+
+ def ReadData(self, decomp=True):
+ return self._data
+
+ def GetListEntries(self, entry_paths):
+ """List the entries in an image
+
+ This decodes the supplied image and returns a list of entries from that
+ image, preceded by a header.
+
+ Args:
+ entry_paths: List of paths to match (each can have wildcards). Only
+ entries whose names match one of these paths will be printed
+
+ Returns:
+ String error message if something went wrong, otherwise
+ 3-Tuple:
+ List of EntryInfo objects
+ List of lines, each
+ List of text columns, each a string
+ List of widths of each column
+ """
+ def _EntryToStrings(entry):
+ """Convert an entry to a list of strings, one for each column
+
+ Args:
+ entry: EntryInfo object containing information to output
+
+ Returns:
+ List of strings, one for each field in entry
+ """
+ def _AppendHex(val):
+ """Append a hex value, or an empty string if val is None
+
+ Args:
+ val: Integer value, or None if none
+ """
+ args.append('' if val is None else '>%x' % val)
+
+ args = [' ' * entry.indent + entry.name]
+ _AppendHex(entry.image_pos)
+ _AppendHex(entry.size)
+ args.append(entry.etype)
+ _AppendHex(entry.offset)
+ _AppendHex(entry.uncomp_size)
+ return args
+
+ def _DoLine(lines, line):
+ """Add a line to the output list
+
+ This adds a line (a list of columns) to the output list. It also updates
+ the widths[] array with the maximum width of each column
+
+ Args:
+ lines: List of lines to add to
+ line: List of strings, one for each column
+ """
+ for i, item in enumerate(line):
+ widths[i] = max(widths[i], len(item))
+ lines.append(line)
+
+ def _NameInPaths(fname, entry_paths):
+ """Check if a filename is in a list of wildcarded paths
+
+ Args:
+ fname: Filename to check
+ entry_paths: List of wildcarded paths (e.g. ['*dtb*', 'u-boot*',
+ 'section/u-boot'])
+
+ Returns:
+ True if any wildcard matches the filename (using Unix filename
+ pattern matching, not regular expressions)
+ False if not
+ """
+ for path in entry_paths:
+ if fnmatch.fnmatch(fname, path):
+ return True
+ return False
+
+ entries = self.BuildEntryList()
+
+ # This is our list of lines. Each item in the list is a list of strings, one
+ # for each column
+ lines = []
+ HEADER = ['Name', 'Image-pos', 'Size', 'Entry-type', 'Offset',
+ 'Uncomp-size']
+ num_columns = len(HEADER)
+
+ # This records the width of each column, calculated as the maximum width of
+ # all the strings in that column
+ widths = [0] * num_columns
+ _DoLine(lines, HEADER)
+
+ # We won't print anything unless it has at least this indent. So at the
+ # start we will print nothing, unless a path matches (or there are no
+ # entry paths)
+ MAX_INDENT = 100
+ min_indent = MAX_INDENT
+ path_stack = []
+ path = ''
+ indent = 0
+ selected_entries = []
+ for entry in entries:
+ if entry.indent > indent:
+ path_stack.append(path)
+ elif entry.indent < indent:
+ path_stack.pop()
+ if path_stack:
+ path = path_stack[-1] + '/' + entry.name
+ indent = entry.indent
+
+ # If there are entry paths to match and we are not looking at a
+ # sub-entry of a previously matched entry, we need to check the path
+ if entry_paths and indent <= min_indent:
+ if _NameInPaths(path[1:], entry_paths):
+ # Print this entry and all sub-entries (=higher indent)
+ min_indent = indent
+ else:
+ # Don't print this entry, nor any following entries until we get
+ # a path match
+ min_indent = MAX_INDENT
+ continue
+ _DoLine(lines, _EntryToStrings(entry))
+ selected_entries.append(entry)
+ return selected_entries, lines, widths
diff --git a/tools/binman/image_test.py b/tools/binman/image_test.py
index 3775e1a..4004f78 100644
--- a/tools/binman/image_test.py
+++ b/tools/binman/image_test.py
@@ -12,28 +12,25 @@
class TestImage(unittest.TestCase):
def testInvalidFormat(self):
image = Image('name', 'node', test=True)
- section = image._section
with self.assertRaises(ValueError) as e:
- section.LookupSymbol('_binman_something_prop_', False, 'msg')
+ image.LookupSymbol('_binman_something_prop_', False, 'msg')
self.assertIn(
"msg: Symbol '_binman_something_prop_' has invalid format",
str(e.exception))
def testMissingSymbol(self):
image = Image('name', 'node', test=True)
- section = image._section
- section._entries = {}
+ image._entries = {}
with self.assertRaises(ValueError) as e:
- section.LookupSymbol('_binman_type_prop_pname', False, 'msg')
+ image.LookupSymbol('_binman_type_prop_pname', False, 'msg')
self.assertIn("msg: Entry 'type' not found in list ()",
str(e.exception))
def testMissingSymbolOptional(self):
image = Image('name', 'node', test=True)
- section = image._section
- section._entries = {}
+ image._entries = {}
with capture_sys_output() as (stdout, stderr):
- val = section.LookupSymbol('_binman_type_prop_pname', True, 'msg')
+ val = image.LookupSymbol('_binman_type_prop_pname', True, 'msg')
self.assertEqual(val, None)
self.assertEqual("Warning: msg: Entry 'type' not found in list ()\n",
stderr.getvalue())
@@ -41,8 +38,7 @@
def testBadProperty(self):
image = Image('name', 'node', test=True)
- section = image._section
- section._entries = {'u-boot': 1}
+ image._entries = {'u-boot': 1}
with self.assertRaises(ValueError) as e:
- section.LookupSymbol('_binman_u_boot_prop_bad', False, 'msg')
+ image.LookupSymbol('_binman_u_boot_prop_bad', False, 'msg')
self.assertIn("msg: No such property 'bad", str(e.exception))
diff --git a/tools/binman/state.py b/tools/binman/state.py
index af96786..382bda3 100644
--- a/tools/binman/state.py
+++ b/tools/binman/state.py
@@ -31,6 +31,11 @@
# The DTB which contains the full image information
main_dtb = None
+# Allow entries to expand after they have been packed. This is detected and
+# forces a re-pack. If not allowed, any attempted expansion causes an error in
+# Entry.ProcessContentsUpdate()
+allow_entry_expansion = True
+
def GetFdt(fname):
"""Get the Fdt object for a particular device-tree filename
@@ -59,7 +64,7 @@
"""
return fdt_files[fname]._fname
-def GetFdtContents(fname):
+def GetFdtContents(fname='u-boot.dtb'):
"""Looks up the FDT pathname and contents
This is used to obtain the Fdt pathname and contents when needed by an
@@ -250,3 +255,22 @@
data = m.digest()
for n in GetUpdateNodes(hash_node):
n.SetData('value', data)
+
+def SetAllowEntryExpansion(allow):
+ """Set whether post-pack expansion of entries is allowed
+
+ Args:
+ allow: True to allow expansion, False to raise an exception
+ """
+ global allow_entry_expansion
+
+ allow_entry_expansion = allow
+
+def AllowEntryExpansion():
+ """Check whether post-pack expansion of entries is allowed
+
+ Returns:
+ True if expansion should be allowed, False if an exception should be
+ raised
+ """
+ return allow_entry_expansion
diff --git a/tools/binman/test/066_text.dts b/tools/binman/test/066_text.dts
index 59b1fed..f23a75a 100644
--- a/tools/binman/test/066_text.dts
+++ b/tools/binman/test/066_text.dts
@@ -24,5 +24,10 @@
text-label = "test-id4";
test-id4 = "some text";
};
+ /* Put text directly in the node */
+ text5 {
+ type = "text";
+ text = "more text";
+ };
};
};
diff --git a/tools/binman/test/096_elf.dts b/tools/binman/test/096_elf.dts
index df3440c..8e3f3f1 100644
--- a/tools/binman/test/096_elf.dts
+++ b/tools/binman/test/096_elf.dts
@@ -10,5 +10,7 @@
};
u-boot-spl-elf {
};
+ u-boot-tpl-elf {
+ };
};
};
diff --git a/tools/binman/test/102_cbfs_raw.dts b/tools/binman/test/102_cbfs_raw.dts
new file mode 100644
index 0000000..779cbc1
--- /dev/null
+++ b/tools/binman/test/102_cbfs_raw.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ size = <0xb0>;
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/103_cbfs_raw_ppc.dts b/tools/binman/test/103_cbfs_raw_ppc.dts
new file mode 100644
index 0000000..df1caf0
--- /dev/null
+++ b/tools/binman/test/103_cbfs_raw_ppc.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ size = <0x100>;
+ cbfs-arch = "ppc64";
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/104_cbfs_stage.dts b/tools/binman/test/104_cbfs_stage.dts
new file mode 100644
index 0000000..215e2f2
--- /dev/null
+++ b/tools/binman/test/104_cbfs_stage.dts
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ size = <0xb0>;
+ u-boot {
+ type = "blob";
+ filename = "cbfs-stage.elf";
+ cbfs-type = "stage";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/105_cbfs_raw_compress.dts b/tools/binman/test/105_cbfs_raw_compress.dts
new file mode 100644
index 0000000..646168d
--- /dev/null
+++ b/tools/binman/test/105_cbfs_raw_compress.dts
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ size = <0x140>;
+ u-boot {
+ type = "text";
+ text = "compress xxxxxxxxxxxxxxxxxxxxxx data";
+ cbfs-type = "raw";
+ cbfs-compress = "lz4";
+ };
+ u-boot-dtb {
+ type = "text";
+ text = "compress xxxxxxxxxxxxxxxxxxxxxx data";
+ cbfs-type = "raw";
+ cbfs-compress = "lzma";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/106_cbfs_bad_arch.dts b/tools/binman/test/106_cbfs_bad_arch.dts
new file mode 100644
index 0000000..4318d45
--- /dev/null
+++ b/tools/binman/test/106_cbfs_bad_arch.dts
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ size = <0x100>;
+ cbfs-arch = "bad-arch";
+ };
+ };
+};
diff --git a/tools/binman/test/107_cbfs_no_size.dts b/tools/binman/test/107_cbfs_no_size.dts
new file mode 100644
index 0000000..3592f62
--- /dev/null
+++ b/tools/binman/test/107_cbfs_no_size.dts
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ };
+ };
+};
diff --git a/tools/binman/test/108_cbfs_no_contents.dts b/tools/binman/test/108_cbfs_no_contents.dts
new file mode 100644
index 0000000..6233467
--- /dev/null
+++ b/tools/binman/test/108_cbfs_no_contents.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ size = <0x100>;
+ _testing {
+ return-unknown-contents;
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/109_cbfs_bad_compress.dts b/tools/binman/test/109_cbfs_bad_compress.dts
new file mode 100644
index 0000000..9695024
--- /dev/null
+++ b/tools/binman/test/109_cbfs_bad_compress.dts
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ size = <0xb0>;
+ u-boot {
+ cbfs-type = "raw";
+ cbfs-compress = "invalid-algo";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/110_cbfs_name.dts b/tools/binman/test/110_cbfs_name.dts
new file mode 100644
index 0000000..98c16f3
--- /dev/null
+++ b/tools/binman/test/110_cbfs_name.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ size = <0x100>;
+ u-boot {
+ cbfs-name = "FRED";
+ cbfs-type = "raw";
+ };
+
+ hello {
+ type = "blob";
+ filename = "u-boot.dtb";
+ cbfs-type = "raw";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/111_x86-rom-ifwi.dts b/tools/binman/test/111_x86-rom-ifwi.dts
new file mode 100644
index 0000000..63b5972
--- /dev/null
+++ b/tools/binman/test/111_x86-rom-ifwi.dts
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ sort-by-offset;
+ end-at-4gb;
+ size = <0x800000>;
+ intel-descriptor {
+ filename = "descriptor.bin";
+ };
+
+ intel-ifwi {
+ offset-unset;
+ filename = "fitimage.bin";
+ convert-fit;
+
+ u-boot-tpl {
+ replace;
+ ifwi-subpart = "IBBP";
+ ifwi-entry = "IBBL";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/112_x86-rom-ifwi-nodesc.dts b/tools/binman/test/112_x86-rom-ifwi-nodesc.dts
new file mode 100644
index 0000000..21ec465
--- /dev/null
+++ b/tools/binman/test/112_x86-rom-ifwi-nodesc.dts
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ sort-by-offset;
+ end-at-4gb;
+ size = <0x800000>;
+ intel-descriptor {
+ filename = "descriptor.bin";
+ };
+
+ intel-ifwi {
+ offset-unset;
+ filename = "ifwi.bin";
+
+ u-boot-tpl {
+ replace;
+ ifwi-subpart = "IBBP";
+ ifwi-entry = "IBBL";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/113_x86-rom-ifwi-nodata.dts b/tools/binman/test/113_x86-rom-ifwi-nodata.dts
new file mode 100644
index 0000000..62486fd
--- /dev/null
+++ b/tools/binman/test/113_x86-rom-ifwi-nodata.dts
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ sort-by-offset;
+ end-at-4gb;
+ size = <0x800000>;
+ intel-descriptor {
+ filename = "descriptor.bin";
+ };
+
+ intel-ifwi {
+ offset-unset;
+ filename = "ifwi.bin";
+
+ _testing {
+ return-unknown-contents;
+ replace;
+ ifwi-subpart = "IBBP";
+ ifwi-entry = "IBBL";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/114_cbfs_offset.dts b/tools/binman/test/114_cbfs_offset.dts
new file mode 100644
index 0000000..7aa9d9d
--- /dev/null
+++ b/tools/binman/test/114_cbfs_offset.dts
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ sort-by-offset;
+ end-at-4gb;
+ size = <0x200>;
+ cbfs {
+ size = <0x200>;
+ offset = <0xfffffe00>;
+ u-boot {
+ cbfs-offset = <0x40>;
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-offset = <0x140>;
+ cbfs-type = "raw";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/115_fdtmap.dts b/tools/binman/test/115_fdtmap.dts
new file mode 100644
index 0000000..2450c41
--- /dev/null
+++ b/tools/binman/test/115_fdtmap.dts
@@ -0,0 +1,13 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot {
+ };
+ fdtmap {
+ };
+ };
+};
diff --git a/tools/binman/test/116_fdtmap_hdr.dts b/tools/binman/test/116_fdtmap_hdr.dts
new file mode 100644
index 0000000..77a2194
--- /dev/null
+++ b/tools/binman/test/116_fdtmap_hdr.dts
@@ -0,0 +1,17 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <0x400>;
+ u-boot {
+ };
+ fdtmap {
+ };
+ image-header {
+ location = "end";
+ };
+ };
+};
diff --git a/tools/binman/test/117_fdtmap_hdr_start.dts b/tools/binman/test/117_fdtmap_hdr_start.dts
new file mode 100644
index 0000000..17b6be0
--- /dev/null
+++ b/tools/binman/test/117_fdtmap_hdr_start.dts
@@ -0,0 +1,19 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <0x400>;
+ sort-by-offset;
+ u-boot {
+ offset = <0x100>;
+ };
+ fdtmap {
+ };
+ image-header {
+ location = "start";
+ };
+ };
+};
diff --git a/tools/binman/test/118_fdtmap_hdr_pos.dts b/tools/binman/test/118_fdtmap_hdr_pos.dts
new file mode 100644
index 0000000..fd803f5
--- /dev/null
+++ b/tools/binman/test/118_fdtmap_hdr_pos.dts
@@ -0,0 +1,19 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <0x400>;
+ sort-by-offset;
+ u-boot {
+ offset = <0x100>;
+ };
+ fdtmap {
+ };
+ image-header {
+ offset = <0x80>;
+ };
+ };
+};
diff --git a/tools/binman/test/119_fdtmap_hdr_missing.dts b/tools/binman/test/119_fdtmap_hdr_missing.dts
new file mode 100644
index 0000000..41bb680
--- /dev/null
+++ b/tools/binman/test/119_fdtmap_hdr_missing.dts
@@ -0,0 +1,16 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ sort-by-offset;
+ u-boot {
+ };
+ image-header {
+ offset = <0x80>;
+ location = "start";
+ };
+ };
+};
diff --git a/tools/binman/test/120_hdr_no_location.dts b/tools/binman/test/120_hdr_no_location.dts
new file mode 100644
index 0000000..585e21f
--- /dev/null
+++ b/tools/binman/test/120_hdr_no_location.dts
@@ -0,0 +1,16 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ sort-by-offset;
+ u-boot {
+ };
+ fdtmap {
+ };
+ image-header {
+ };
+ };
+};
diff --git a/tools/binman/test/121_entry_expand.dts b/tools/binman/test/121_entry_expand.dts
new file mode 100644
index 0000000..ebb7816
--- /dev/null
+++ b/tools/binman/test/121_entry_expand.dts
@@ -0,0 +1,20 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ _testing {
+ bad-update-contents;
+ };
+
+ u-boot {
+ };
+
+ _testing2 {
+ type = "_testing";
+ bad-update-contents;
+ };
+ };
+};
diff --git a/tools/binman/test/122_entry_expand_twice.dts b/tools/binman/test/122_entry_expand_twice.dts
new file mode 100644
index 0000000..258cf85
--- /dev/null
+++ b/tools/binman/test/122_entry_expand_twice.dts
@@ -0,0 +1,21 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ _testing {
+ bad-update-contents;
+ bad-update-contents-twice;
+ };
+
+ u-boot {
+ };
+
+ _testing2 {
+ type = "_testing";
+ bad-update-contents;
+ };
+ };
+};
diff --git a/tools/binman/test/123_entry_expand_section.dts b/tools/binman/test/123_entry_expand_section.dts
new file mode 100644
index 0000000..046f723
--- /dev/null
+++ b/tools/binman/test/123_entry_expand_section.dts
@@ -0,0 +1,22 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ _testing {
+ bad-update-contents;
+ };
+
+ u-boot {
+ };
+
+ section {
+ _testing2 {
+ type = "_testing";
+ bad-update-contents;
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/124_compress_dtb.dts b/tools/binman/test/124_compress_dtb.dts
new file mode 100644
index 0000000..46bfd8b
--- /dev/null
+++ b/tools/binman/test/124_compress_dtb.dts
@@ -0,0 +1,14 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot {
+ };
+ u-boot-dtb {
+ compress = "lz4";
+ };
+ };
+};
diff --git a/tools/binman/test/125_cbfs_update.dts b/tools/binman/test/125_cbfs_update.dts
new file mode 100644
index 0000000..6d2e8a0
--- /dev/null
+++ b/tools/binman/test/125_cbfs_update.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ size = <0x100>;
+ u-boot {
+ cbfs-type = "raw";
+ cbfs-compress = "lz4";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/126_cbfs_bad_type.dts b/tools/binman/test/126_cbfs_bad_type.dts
new file mode 100644
index 0000000..2cd6fc6
--- /dev/null
+++ b/tools/binman/test/126_cbfs_bad_type.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ cbfs {
+ size = <0x100>;
+ u-boot {
+ cbfs-type = "badtype";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/127_list.dts b/tools/binman/test/127_list.dts
new file mode 100644
index 0000000..c1d6fce
--- /dev/null
+++ b/tools/binman/test/127_list.dts
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot {
+ };
+ section {
+ align = <0x100>;
+ cbfs {
+ size = <0x400>;
+ u-boot {
+ cbfs-type = "raw";
+ cbfs-offset = <0x38>;
+ };
+ u-boot-dtb {
+ type = "text";
+ text = "compress xxxxxxxxxxxxxxxxxxxxxx data";
+ cbfs-type = "raw";
+ cbfs-compress = "lzma";
+ cbfs-offset = <0x78>;
+ };
+ };
+ u-boot-dtb {
+ compress = "lz4";
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/128_decode_image.dts b/tools/binman/test/128_decode_image.dts
new file mode 100644
index 0000000..449fccc
--- /dev/null
+++ b/tools/binman/test/128_decode_image.dts
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <0xc00>;
+ u-boot {
+ };
+ section {
+ align = <0x100>;
+ cbfs {
+ size = <0x400>;
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ cbfs-compress = "lzma";
+ cbfs-offset = <0x80>;
+ };
+ };
+ u-boot-dtb {
+ compress = "lz4";
+ };
+ };
+ fdtmap {
+ };
+ image-header {
+ location = "end";
+ };
+ };
+};
diff --git a/tools/binman/test/129_decode_image_nohdr.dts b/tools/binman/test/129_decode_image_nohdr.dts
new file mode 100644
index 0000000..90fdd88
--- /dev/null
+++ b/tools/binman/test/129_decode_image_nohdr.dts
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <0xc00>;
+ u-boot {
+ };
+ section {
+ align = <0x100>;
+ cbfs {
+ size = <0x400>;
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ cbfs-compress = "lzma";
+ cbfs-offset = <0x80>;
+ };
+ };
+ u-boot-dtb {
+ compress = "lz4";
+ };
+ };
+ fdtmap {
+ };
+ };
+};
diff --git a/tools/binman/test/130_list_fdtmap.dts b/tools/binman/test/130_list_fdtmap.dts
new file mode 100644
index 0000000..449fccc
--- /dev/null
+++ b/tools/binman/test/130_list_fdtmap.dts
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <0xc00>;
+ u-boot {
+ };
+ section {
+ align = <0x100>;
+ cbfs {
+ size = <0x400>;
+ u-boot {
+ cbfs-type = "raw";
+ };
+ u-boot-dtb {
+ cbfs-type = "raw";
+ cbfs-compress = "lzma";
+ cbfs-offset = <0x80>;
+ };
+ };
+ u-boot-dtb {
+ compress = "lz4";
+ };
+ };
+ fdtmap {
+ };
+ image-header {
+ location = "end";
+ };
+ };
+};
diff --git a/tools/binman/test/131_pack_align_section.dts b/tools/binman/test/131_pack_align_section.dts
new file mode 100644
index 0000000..4447885
--- /dev/null
+++ b/tools/binman/test/131_pack_align_section.dts
@@ -0,0 +1,28 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot {
+ };
+ section0 {
+ type = "section";
+ align = <0x10>;
+ u-boot {
+ };
+ };
+ section1 {
+ type = "section";
+ align-size = <0x20>;
+ u-boot {
+ };
+ section2 {
+ type = "section";
+ u-boot {
+ };
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/fitimage.bin.gz b/tools/binman/test/fitimage.bin.gz
new file mode 100644
index 0000000..0a9dcfc
--- /dev/null
+++ b/tools/binman/test/fitimage.bin.gz
Binary files differ
diff --git a/tools/binman/test/ifwi.bin.gz b/tools/binman/test/ifwi.bin.gz
new file mode 100644
index 0000000..25d7289
--- /dev/null
+++ b/tools/binman/test/ifwi.bin.gz
Binary files differ
diff --git a/tools/buildman/README b/tools/buildman/README
index 56a99c7..e366192 100644
--- a/tools/buildman/README
+++ b/tools/buildman/README
@@ -137,7 +137,7 @@
You can also use -x to specifically exclude some boards. For example:
- buildmand arm -x nvidia,freescale,.*ball$
+ buildman arm -x nvidia,freescale,.*ball$
means to build all arm boards except nvidia, freescale and anything ending
with 'ball'.
@@ -146,7 +146,7 @@
comma-separated list of board target names and be used multiple times on
the command line:
- buidman --boards sandbox,snow --boards
+ buildman --boards sandbox,snow --boards
It is convenient to use the -n option to see what will be built based on
the subset given. Use -v as well to get an actual list of boards.
diff --git a/tools/ifwitool.c b/tools/ifwitool.c
new file mode 100644
index 0000000..2e020a8
--- /dev/null
+++ b/tools/ifwitool.c
@@ -0,0 +1,2304 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ifwitool, CLI utility for Integrated Firmware Image (IFWI) manipulation
+ *
+ * This is taken from the Coreboot project
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <getopt.h>
+#include "os_support.h"
+
+#define __packed __attribute__((packed))
+#define KiB 1024
+#define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a) - 1)
+#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/*
+ * min()/max()/clamp() macros that also do
+ * strict type-checking.. See the
+ * "unnecessary" pointer comparison.
+ */
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void)&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({ \
+ typeof(x) _max1 = (x); \
+ typeof(y) _max2 = (y); \
+ (void)(&_max1 == &_max2); \
+ _max1 > _max2 ? _max1 : _max2; })
+
+static int verbose = 1;
+
+/* Buffer and file I/O */
+struct buffer {
+ char *name;
+ char *data;
+ size_t offset;
+ size_t size;
+};
+
+#define ERROR(...) { fprintf(stderr, "E: " __VA_ARGS__); }
+#define INFO(...) { if (verbose > 0) fprintf(stderr, "INFO: " __VA_ARGS__); }
+#define DEBUG(...) { if (verbose > 1) fprintf(stderr, "DEBUG: " __VA_ARGS__); }
+
+/*
+ * BPDT is Boot Partition Descriptor Table. It is located at the start of a
+ * logical boot partition(LBP). It stores information about the critical
+ * sub-partitions present within the LBP.
+ *
+ * S-BPDT is Secondary Boot Partition Descriptor Table. It is located after the
+ * critical sub-partitions and contains information about the non-critical
+ * sub-partitions present within the LBP.
+ *
+ * Both tables are identified by BPDT_SIGNATURE stored at the start of the
+ * table.
+ */
+#define BPDT_SIGNATURE (0x000055AA)
+
+/* Parameters passed in by caller */
+static struct param {
+ const char *file_name;
+ const char *subpart_name;
+ const char *image_name;
+ bool dir_ops;
+ const char *dentry_name;
+} param;
+
+struct bpdt_header {
+ /*
+ * This is used to identify start of BPDT. It should always be
+ * BPDT_SIGNATURE.
+ */
+ uint32_t signature;
+ /* Count of BPDT entries present */
+ uint16_t descriptor_count;
+ /* Version - Currently supported = 1 */
+ uint16_t bpdt_version;
+ /* Unused - Should be 0 */
+ uint32_t xor_redundant_block;
+ /* Version of IFWI build */
+ uint32_t ifwi_version;
+ /* Version of FIT tool used to create IFWI */
+ uint64_t fit_tool_version;
+} __packed;
+#define BPDT_HEADER_SIZE (sizeof(struct bpdt_header))
+
+struct bpdt_entry {
+ /* Type of sub-partition */
+ uint16_t type;
+ /* Attributes of sub-partition */
+ uint16_t flags;
+ /* Offset of sub-partition from beginning of LBP */
+ uint32_t offset;
+ /* Size in bytes of sub-partition */
+ uint32_t size;
+} __packed;
+#define BPDT_ENTRY_SIZE (sizeof(struct bpdt_entry))
+
+struct bpdt {
+ struct bpdt_header h;
+ /* In practice, this could be an array of 0 to n entries */
+ struct bpdt_entry e[0];
+} __packed;
+
+static inline size_t get_bpdt_size(struct bpdt_header *h)
+{
+ return (sizeof(*h) + BPDT_ENTRY_SIZE * h->descriptor_count);
+}
+
+/* Minimum size in bytes allocated to BPDT in IFWI */
+#define BPDT_MIN_SIZE ((size_t)512)
+
+/* Header to define directory header for sub-partition */
+struct subpart_dir_header {
+ /* Should be SUBPART_DIR_MARKER */
+ uint32_t marker;
+ /* Number of directory entries in the sub-partition */
+ uint32_t num_entries;
+ /* Currenty supported - 1 */
+ uint8_t header_version;
+ /* Currenty supported - 1 */
+ uint8_t entry_version;
+ /* Length of directory header in bytes */
+ uint8_t header_length;
+ /*
+ * 2s complement of 8-bit sum from first byte of header to last byte of
+ * last directory entry.
+ */
+ uint8_t checksum;
+ /* ASCII short name of sub-partition */
+ uint8_t name[4];
+} __packed;
+#define SUBPART_DIR_HEADER_SIZE \
+ (sizeof(struct subpart_dir_header))
+#define SUBPART_DIR_MARKER 0x44504324
+#define SUBPART_DIR_HEADER_VERSION_SUPPORTED 1
+#define SUBPART_DIR_ENTRY_VERSION_SUPPORTED 1
+
+/* Structure for each directory entry for sub-partition */
+struct subpart_dir_entry {
+ /* Name of directory entry - Not guaranteed to be NULL-terminated */
+ uint8_t name[12];
+ /* Offset of entry from beginning of sub-partition */
+ uint32_t offset;
+ /* Length in bytes of sub-directory entry */
+ uint32_t length;
+ /* Must be zero */
+ uint32_t rsvd;
+} __packed;
+#define SUBPART_DIR_ENTRY_SIZE \
+ (sizeof(struct subpart_dir_entry))
+
+struct subpart_dir {
+ struct subpart_dir_header h;
+ /* In practice, this could be an array of 0 to n entries */
+ struct subpart_dir_entry e[0];
+} __packed;
+
+static inline size_t subpart_dir_size(struct subpart_dir_header *h)
+{
+ return (sizeof(*h) + SUBPART_DIR_ENTRY_SIZE * h->num_entries);
+}
+
+struct manifest_header {
+ uint32_t header_type;
+ uint32_t header_length;
+ uint32_t header_version;
+ uint32_t flags;
+ uint32_t vendor;
+ uint32_t date;
+ uint32_t size;
+ uint32_t id;
+ uint32_t rsvd;
+ uint64_t version;
+ uint32_t svn;
+ uint64_t rsvd1;
+ uint8_t rsvd2[64];
+ uint32_t modulus_size;
+ uint32_t exponent_size;
+ uint8_t public_key[256];
+ uint32_t exponent;
+ uint8_t signature[256];
+} __packed;
+
+#define DWORD_SIZE 4
+#define MANIFEST_HDR_SIZE (sizeof(struct manifest_header))
+#define MANIFEST_ID_MAGIC (0x324e4d24)
+
+struct module {
+ uint8_t name[12];
+ uint8_t type;
+ uint8_t hash_alg;
+ uint16_t hash_size;
+ uint32_t metadata_size;
+ uint8_t metadata_hash[32];
+} __packed;
+
+#define MODULE_SIZE (sizeof(struct module))
+
+struct signed_pkg_info_ext {
+ uint32_t ext_type;
+ uint32_t ext_length;
+ uint8_t name[4];
+ uint32_t vcn;
+ uint8_t bitmap[16];
+ uint32_t svn;
+ uint8_t rsvd[16];
+} __packed;
+
+#define SIGNED_PKG_INFO_EXT_TYPE 0x15
+#define SIGNED_PKG_INFO_EXT_SIZE \
+ (sizeof(struct signed_pkg_info_ext))
+
+/*
+ * Attributes for various IFWI sub-partitions.
+ * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
+ * BPDT.
+ * NON_CRITICAL_SUBPART = Sub-Partition entry should be present in S-BPDT.
+ * CONTAINS_DIR = Sub-Partition contains directory.
+ * AUTO_GENERATED = Sub-Partition is generated by the tool.
+ * MANDATORY_BPDT_ENTRY = Even if sub-partition is deleted, BPDT should contain
+ * an entry for it with size 0 and offset 0.
+ */
+enum subpart_attributes {
+ LIES_WITHIN_BPDT_4K = (1 << 0),
+ NON_CRITICAL_SUBPART = (1 << 1),
+ CONTAINS_DIR = (1 << 2),
+ AUTO_GENERATED = (1 << 3),
+ MANDATORY_BPDT_ENTRY = (1 << 4),
+};
+
+/* Type value for various IFWI sub-partitions */
+enum bpdt_entry_type {
+ SMIP_TYPE = 0,
+ CSE_RBE_TYPE = 1,
+ CSE_BUP_TYPE = 2,
+ UCODE_TYPE = 3,
+ IBB_TYPE = 4,
+ S_BPDT_TYPE = 5,
+ OBB_TYPE = 6,
+ CSE_MAIN_TYPE = 7,
+ ISH_TYPE = 8,
+ CSE_IDLM_TYPE = 9,
+ IFP_OVERRIDE_TYPE = 10,
+ DEBUG_TOKENS_TYPE = 11,
+ UFS_PHY_TYPE = 12,
+ UFS_GPP_TYPE = 13,
+ PMC_TYPE = 14,
+ IUNIT_TYPE = 15,
+ NVM_CONFIG_TYPE = 16,
+ UEP_TYPE = 17,
+ UFS_RATE_B_TYPE = 18,
+ MAX_SUBPARTS = 19,
+};
+
+/*
+ * There are two order requirements for an IFWI image:
+ * 1. Order in which the sub-partitions lie within the BPDT entries.
+ * 2. Order in which the sub-partitions lie within the image.
+ *
+ * header_order defines #1 i.e. the order in which the sub-partitions should
+ * appear in the BPDT entries. pack_order defines #2 i.e. the order in which
+ * sub-partitions appear in the IFWI image. pack_order controls the offset and
+ * thus sub-partitions would have increasing offsets as we loop over pack_order.
+ */
+const enum bpdt_entry_type bpdt_header_order[MAX_SUBPARTS] = {
+ /* Order of the following entries is mandatory */
+ CSE_IDLM_TYPE,
+ IFP_OVERRIDE_TYPE,
+ S_BPDT_TYPE,
+ CSE_RBE_TYPE,
+ UFS_PHY_TYPE,
+ UFS_GPP_TYPE,
+ /* Order of the following entries is recommended */
+ UEP_TYPE,
+ NVM_CONFIG_TYPE,
+ UFS_RATE_B_TYPE,
+ IBB_TYPE,
+ SMIP_TYPE,
+ PMC_TYPE,
+ CSE_BUP_TYPE,
+ UCODE_TYPE,
+ DEBUG_TOKENS_TYPE,
+ IUNIT_TYPE,
+ CSE_MAIN_TYPE,
+ ISH_TYPE,
+ OBB_TYPE,
+};
+
+const enum bpdt_entry_type bpdt_pack_order[MAX_SUBPARTS] = {
+ /* Order of the following entries is mandatory */
+ UFS_GPP_TYPE,
+ UFS_PHY_TYPE,
+ IFP_OVERRIDE_TYPE,
+ UEP_TYPE,
+ NVM_CONFIG_TYPE,
+ UFS_RATE_B_TYPE,
+ /* Order of the following entries is recommended */
+ IBB_TYPE,
+ SMIP_TYPE,
+ CSE_RBE_TYPE,
+ PMC_TYPE,
+ CSE_BUP_TYPE,
+ UCODE_TYPE,
+ CSE_IDLM_TYPE,
+ DEBUG_TOKENS_TYPE,
+ S_BPDT_TYPE,
+ IUNIT_TYPE,
+ CSE_MAIN_TYPE,
+ ISH_TYPE,
+ OBB_TYPE,
+};
+
+/* Utility functions */
+enum ifwi_ret {
+ COMMAND_ERR = -1,
+ NO_ACTION_REQUIRED = 0,
+ REPACK_REQUIRED = 1,
+};
+
+struct dir_ops {
+ enum ifwi_ret (*dir_add)(int type);
+};
+
+static enum ifwi_ret ibbp_dir_add(int type);
+
+const struct subpart_info {
+ const char *name;
+ const char *readable_name;
+ uint32_t attr;
+ struct dir_ops dir_ops;
+} subparts[MAX_SUBPARTS] = {
+ /* OEM SMIP */
+ [SMIP_TYPE] = {"SMIP", "SMIP", CONTAINS_DIR, {NULL} },
+ /* CSE RBE */
+ [CSE_RBE_TYPE] = {"RBEP", "CSE_RBE", CONTAINS_DIR |
+ MANDATORY_BPDT_ENTRY, {NULL} },
+ /* CSE BUP */
+ [CSE_BUP_TYPE] = {"FTPR", "CSE_BUP", CONTAINS_DIR |
+ MANDATORY_BPDT_ENTRY, {NULL} },
+ /* uCode */
+ [UCODE_TYPE] = {"UCOD", "Microcode", CONTAINS_DIR, {NULL} },
+ /* IBB */
+ [IBB_TYPE] = {"IBBP", "Bootblock", CONTAINS_DIR, {ibbp_dir_add} },
+ /* S-BPDT */
+ [S_BPDT_TYPE] = {"S_BPDT", "S-BPDT", AUTO_GENERATED |
+ MANDATORY_BPDT_ENTRY, {NULL} },
+ /* OBB */
+ [OBB_TYPE] = {"OBBP", "OEM boot block", CONTAINS_DIR |
+ NON_CRITICAL_SUBPART, {NULL} },
+ /* CSE Main */
+ [CSE_MAIN_TYPE] = {"NFTP", "CSE_MAIN", CONTAINS_DIR |
+ NON_CRITICAL_SUBPART, {NULL} },
+ /* ISH */
+ [ISH_TYPE] = {"ISHP", "ISH", NON_CRITICAL_SUBPART, {NULL} },
+ /* CSE IDLM */
+ [CSE_IDLM_TYPE] = {"DLMP", "CSE_IDLM", CONTAINS_DIR |
+ MANDATORY_BPDT_ENTRY, {NULL} },
+ /* IFP Override */
+ [IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
+ LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
+ {NULL} },
+ /* Debug Tokens */
+ [DEBUG_TOKENS_TYPE] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL} },
+ /* UFS Phy Configuration */
+ [UFS_PHY_TYPE] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K |
+ MANDATORY_BPDT_ENTRY, {NULL} },
+ /* UFS GPP LUN ID */
+ [UFS_GPP_TYPE] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K |
+ MANDATORY_BPDT_ENTRY, {NULL} },
+ /* PMC */
+ [PMC_TYPE] = {"PMCP", "PMC firmware", CONTAINS_DIR, {NULL} },
+ /* IUNIT */
+ [IUNIT_TYPE] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART, {NULL} },
+ /* NVM Config */
+ [NVM_CONFIG_TYPE] = {"NVM_CONFIG", "NVM Config", 0, {NULL} },
+ /* UEP */
+ [UEP_TYPE] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
+ {NULL} },
+ /* UFS Rate B Config */
+ [UFS_RATE_B_TYPE] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL} },
+};
+
+struct ifwi_image {
+ /* Data read from input file */
+ struct buffer input_buff;
+
+ /* BPDT header and entries */
+ struct buffer bpdt;
+ size_t input_ifwi_start_offset;
+ size_t input_ifwi_end_offset;
+
+ /* Subpartition content */
+ struct buffer subpart_buf[MAX_SUBPARTS];
+} ifwi_image;
+
+/* Buffer and file I/O */
+static off_t get_file_size(FILE *f)
+{
+ off_t fsize;
+
+ fseek(f, 0, SEEK_END);
+ fsize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ return fsize;
+}
+
+static inline void *buffer_get(const struct buffer *b)
+{
+ return b->data;
+}
+
+static inline size_t buffer_size(const struct buffer *b)
+{
+ return b->size;
+}
+
+static inline size_t buffer_offset(const struct buffer *b)
+{
+ return b->offset;
+}
+
+/*
+ * Shrink a buffer toward the beginning of its previous space.
+ * Afterward, buffer_delete() remains the means of cleaning it up
+ */
+static inline void buffer_set_size(struct buffer *b, size_t size)
+{
+ b->size = size;
+}
+
+/* Splice a buffer into another buffer. Note that it's up to the caller to
+ * bounds check the offset and size. The resulting buffer is backed by the same
+ * storage as the original, so although it is valid to buffer_delete() either
+ * one of them, doing so releases both simultaneously
+ */
+static void buffer_splice(struct buffer *dest, const struct buffer *src,
+ size_t offset, size_t size)
+{
+ dest->name = src->name;
+ dest->data = src->data + offset;
+ dest->offset = src->offset + offset;
+ dest->size = size;
+}
+
+/*
+ * Shrink a buffer toward the end of its previous space.
+ * Afterward, buffer_delete() remains the means of cleaning it up
+ */
+static inline void buffer_seek(struct buffer *b, size_t size)
+{
+ b->offset += size;
+ b->size -= size;
+ b->data += size;
+}
+
+/* Returns the start of the underlying buffer, with the offset undone */
+static inline void *buffer_get_original_backing(const struct buffer *b)
+{
+ if (!b)
+ return NULL;
+ return buffer_get(b) - buffer_offset(b);
+}
+
+int buffer_create(struct buffer *buffer, size_t size, const char *name)
+{
+ buffer->name = strdup(name);
+ buffer->offset = 0;
+ buffer->size = size;
+ buffer->data = (char *)malloc(buffer->size);
+ if (!buffer->data) {
+ fprintf(stderr, "%s: Insufficient memory (0x%zx).\n", __func__,
+ size);
+ }
+
+ return !buffer->data;
+}
+
+int buffer_write_file(struct buffer *buffer, const char *filename)
+{
+ FILE *fp = fopen(filename, "wb");
+
+ if (!fp) {
+ perror(filename);
+ return -1;
+ }
+ assert(buffer && buffer->data);
+ if (fwrite(buffer->data, 1, buffer->size, fp) != buffer->size) {
+ fprintf(stderr, "incomplete write: %s\n", filename);
+ fclose(fp);
+ return -1;
+ }
+ fclose(fp);
+ return 0;
+}
+
+void buffer_delete(struct buffer *buffer)
+{
+ assert(buffer);
+ if (buffer->name) {
+ free(buffer->name);
+ buffer->name = NULL;
+ }
+ if (buffer->data) {
+ free(buffer_get_original_backing(buffer));
+ buffer->data = NULL;
+ }
+ buffer->offset = 0;
+ buffer->size = 0;
+}
+
+int buffer_from_file(struct buffer *buffer, const char *filename)
+{
+ FILE *fp = fopen(filename, "rb");
+
+ if (!fp) {
+ perror(filename);
+ return -1;
+ }
+ buffer->offset = 0;
+ off_t file_size = get_file_size(fp);
+
+ if (file_size < 0) {
+ fprintf(stderr, "could not determine size of %s\n", filename);
+ fclose(fp);
+ return -1;
+ }
+ buffer->size = file_size;
+ buffer->name = strdup(filename);
+ buffer->data = (char *)malloc(buffer->size);
+ assert(buffer->data);
+ if (fread(buffer->data, 1, buffer->size, fp) != buffer->size) {
+ fprintf(stderr, "incomplete read: %s\n", filename);
+ fclose(fp);
+ buffer_delete(buffer);
+ return -1;
+ }
+ fclose(fp);
+ return 0;
+}
+
+static void alloc_buffer(struct buffer *b, size_t s, const char *n)
+{
+ if (buffer_create(b, s, n) == 0)
+ return;
+
+ ERROR("Buffer allocation failure for %s (size = %zx).\n", n, s);
+ exit(-1);
+}
+
+/* Little-Endian functions */
+static inline uint8_t read_ble8(const void *src)
+{
+ const uint8_t *s = src;
+ return *s;
+}
+
+static inline uint8_t read_at_ble8(const void *src, size_t offset)
+{
+ const uint8_t *s = src;
+
+ s += offset;
+ return read_ble8(s);
+}
+
+static inline void write_ble8(void *dest, uint8_t val)
+{
+ *(uint8_t *)dest = val;
+}
+
+static inline void write_at_ble8(void *dest, uint8_t val, size_t offset)
+{
+ uint8_t *d = dest;
+
+ d += offset;
+ write_ble8(d, val);
+}
+
+static inline uint8_t read_at_le8(const void *src, size_t offset)
+{
+ return read_at_ble8(src, offset);
+}
+
+static inline void write_le8(void *dest, uint8_t val)
+{
+ write_ble8(dest, val);
+}
+
+static inline void write_at_le8(void *dest, uint8_t val, size_t offset)
+{
+ write_at_ble8(dest, val, offset);
+}
+
+static inline uint16_t read_le16(const void *src)
+{
+ const uint8_t *s = src;
+
+ return (((uint16_t)s[1]) << 8) | (((uint16_t)s[0]) << 0);
+}
+
+static inline uint16_t read_at_le16(const void *src, size_t offset)
+{
+ const uint8_t *s = src;
+
+ s += offset;
+ return read_le16(s);
+}
+
+static inline void write_le16(void *dest, uint16_t val)
+{
+ write_le8(dest, val >> 0);
+ write_at_le8(dest, val >> 8, sizeof(uint8_t));
+}
+
+static inline void write_at_le16(void *dest, uint16_t val, size_t offset)
+{
+ uint8_t *d = dest;
+
+ d += offset;
+ write_le16(d, val);
+}
+
+static inline uint32_t read_le32(const void *src)
+{
+ const uint8_t *s = src;
+
+ return (((uint32_t)s[3]) << 24) | (((uint32_t)s[2]) << 16) |
+ (((uint32_t)s[1]) << 8) | (((uint32_t)s[0]) << 0);
+}
+
+static inline uint32_t read_at_le32(const void *src, size_t offset)
+{
+ const uint8_t *s = src;
+
+ s += offset;
+ return read_le32(s);
+}
+
+static inline void write_le32(void *dest, uint32_t val)
+{
+ write_le16(dest, val >> 0);
+ write_at_le16(dest, val >> 16, sizeof(uint16_t));
+}
+
+static inline void write_at_le32(void *dest, uint32_t val, size_t offset)
+{
+ uint8_t *d = dest;
+
+ d += offset;
+ write_le32(d, val);
+}
+
+static inline uint64_t read_le64(const void *src)
+{
+ uint64_t val;
+
+ val = read_at_le32(src, sizeof(uint32_t));
+ val <<= 32;
+ val |= read_le32(src);
+ return val;
+}
+
+static inline uint64_t read_at_le64(const void *src, size_t offset)
+{
+ const uint8_t *s = src;
+
+ s += offset;
+ return read_le64(s);
+}
+
+static inline void write_le64(void *dest, uint64_t val)
+{
+ write_le32(dest, val >> 0);
+ write_at_le32(dest, val >> 32, sizeof(uint32_t));
+}
+
+static inline void write_at_le64(void *dest, uint64_t val, size_t offset)
+{
+ uint8_t *d = dest;
+
+ d += offset;
+ write_le64(d, val);
+}
+
+/*
+ * Read header/entry members in little-endian format.
+ * Returns the offset upto which the read was performed.
+ */
+static size_t read_member(void *src, size_t offset, size_t size_bytes,
+ void *dst)
+{
+ switch (size_bytes) {
+ case 1:
+ *(uint8_t *)dst = read_at_le8(src, offset);
+ break;
+ case 2:
+ *(uint16_t *)dst = read_at_le16(src, offset);
+ break;
+ case 4:
+ *(uint32_t *)dst = read_at_le32(src, offset);
+ break;
+ case 8:
+ *(uint64_t *)dst = read_at_le64(src, offset);
+ break;
+ default:
+ ERROR("Read size not supported %zd\n", size_bytes);
+ exit(-1);
+ }
+
+ return (offset + size_bytes);
+}
+
+/*
+ * Convert to little endian format.
+ * Returns the offset upto which the fixup was performed.
+ */
+static size_t fix_member(void *data, size_t offset, size_t size_bytes)
+{
+ uint8_t *src = (uint8_t *)data + offset;
+
+ switch (size_bytes) {
+ case 1:
+ write_at_le8(data, *(uint8_t *)src, offset);
+ break;
+ case 2:
+ write_at_le16(data, *(uint16_t *)src, offset);
+ break;
+ case 4:
+ write_at_le32(data, *(uint32_t *)src, offset);
+ break;
+ case 8:
+ write_at_le64(data, *(uint64_t *)src, offset);
+ break;
+ default:
+ ERROR("Write size not supported %zd\n", size_bytes);
+ exit(-1);
+ }
+ return (offset + size_bytes);
+}
+
+static void print_subpart_dir(struct subpart_dir *s)
+{
+ if (verbose == 0)
+ return;
+
+ size_t i;
+
+ printf("%-25s 0x%-23.8x\n", "Marker", s->h.marker);
+ printf("%-25s %-25d\n", "Num entries", s->h.num_entries);
+ printf("%-25s %-25d\n", "Header Version", s->h.header_version);
+ printf("%-25s %-25d\n", "Entry Version", s->h.entry_version);
+ printf("%-25s 0x%-23x\n", "Header Length", s->h.header_length);
+ printf("%-25s 0x%-23x\n", "Checksum", s->h.checksum);
+ printf("%-25s ", "Name");
+ for (i = 0; i < sizeof(s->h.name); i++)
+ printf("%c", s->h.name[i]);
+
+ printf("\n");
+
+ printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
+ "Length", "Rsvd");
+
+ printf("=========================================================================================================================\n");
+
+ for (i = 0; i < s->h.num_entries; i++) {
+ printf("%-25zd%-25.12s0x%-23x0x%-23x0x%-23x\n", i + 1,
+ s->e[i].name, s->e[i].offset, s->e[i].length,
+ s->e[i].rsvd);
+ }
+
+ printf("=========================================================================================================================\n");
+}
+
+static void bpdt_print_header(struct bpdt_header *h, const char *name)
+{
+ if (verbose == 0)
+ return;
+
+ printf("%-25s %-25s\n", "Header", name);
+ printf("%-25s 0x%-23.8x\n", "Signature", h->signature);
+ printf("%-25s %-25d\n", "Descriptor count", h->descriptor_count);
+ printf("%-25s %-25d\n", "BPDT Version", h->bpdt_version);
+ printf("%-25s 0x%-23x\n", "XOR checksum", h->xor_redundant_block);
+ printf("%-25s 0x%-23x\n", "IFWI Version", h->ifwi_version);
+ printf("%-25s 0x%-23llx\n", "FIT Tool Version",
+ (long long)h->fit_tool_version);
+}
+
+static void bpdt_print_entries(struct bpdt_entry *e, size_t count,
+ const char *name)
+{
+ size_t i;
+
+ if (verbose == 0)
+ return;
+
+ printf("%s entries\n", name);
+
+ printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
+ "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
+ "File Offset");
+
+ printf("=========================================================================================================================================================================================================\n");
+
+ for (i = 0; i < count; i++) {
+ printf("%-25zd%-25s%-25s%-25d0x%-23.08x0x%-23x0x%-23x0x%-23zx\n",
+ i + 1, subparts[e[i].type].name,
+ subparts[e[i].type].readable_name, e[i].type, e[i].flags,
+ e[i].offset, e[i].size,
+ e[i].offset + ifwi_image.input_ifwi_start_offset);
+ }
+
+ printf("=========================================================================================================================================================================================================\n");
+}
+
+static void bpdt_validate_header(struct bpdt_header *h, const char *name)
+{
+ assert(h->signature == BPDT_SIGNATURE);
+
+ if (h->bpdt_version != 1) {
+ ERROR("Invalid header : %s\n", name);
+ exit(-1);
+ }
+
+ DEBUG("Validated header : %s\n", name);
+}
+
+static void bpdt_read_header(void *data, struct bpdt_header *h,
+ const char *name)
+{
+ size_t offset = 0;
+
+ offset = read_member(data, offset, sizeof(h->signature), &h->signature);
+ offset = read_member(data, offset, sizeof(h->descriptor_count),
+ &h->descriptor_count);
+ offset = read_member(data, offset, sizeof(h->bpdt_version),
+ &h->bpdt_version);
+ offset = read_member(data, offset, sizeof(h->xor_redundant_block),
+ &h->xor_redundant_block);
+ offset = read_member(data, offset, sizeof(h->ifwi_version),
+ &h->ifwi_version);
+ read_member(data, offset, sizeof(h->fit_tool_version),
+ &h->fit_tool_version);
+
+ bpdt_validate_header(h, name);
+ bpdt_print_header(h, name);
+}
+
+static void bpdt_read_entries(void *data, struct bpdt *bpdt, const char *name)
+{
+ size_t i, offset = 0;
+ struct bpdt_entry *e = &bpdt->e[0];
+ size_t count = bpdt->h.descriptor_count;
+
+ for (i = 0; i < count; i++) {
+ offset = read_member(data, offset, sizeof(e[i].type),
+ &e[i].type);
+ offset = read_member(data, offset, sizeof(e[i].flags),
+ &e[i].flags);
+ offset = read_member(data, offset, sizeof(e[i].offset),
+ &e[i].offset);
+ offset = read_member(data, offset, sizeof(e[i].size),
+ &e[i].size);
+ }
+
+ bpdt_print_entries(e, count, name);
+}
+
+/*
+ * Given type of sub-partition, identify BPDT entry for it.
+ * Sub-Partition could lie either within BPDT or S-BPDT.
+ */
+static struct bpdt_entry *__find_entry_by_type(struct bpdt_entry *e,
+ size_t count, int type)
+{
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ if (e[i].type == type)
+ break;
+ }
+
+ if (i == count)
+ return NULL;
+
+ return &e[i];
+}
+
+static struct bpdt_entry *find_entry_by_type(int type)
+{
+ struct bpdt *b = buffer_get(&ifwi_image.bpdt);
+
+ if (!b)
+ return NULL;
+
+ struct bpdt_entry *curr = __find_entry_by_type(&b->e[0],
+ b->h.descriptor_count,
+ type);
+
+ if (curr)
+ return curr;
+
+ b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
+ if (!b)
+ return NULL;
+
+ return __find_entry_by_type(&b->e[0], b->h.descriptor_count, type);
+}
+
+/*
+ * Find sub-partition type given its name. If the name does not exist, returns
+ * -1.
+ */
+static int find_type_by_name(const char *name)
+{
+ int i;
+
+ for (i = 0; i < MAX_SUBPARTS; i++) {
+ if ((strlen(subparts[i].name) == strlen(name)) &&
+ (!strcmp(subparts[i].name, name)))
+ break;
+ }
+
+ if (i == MAX_SUBPARTS) {
+ ERROR("Invalid sub-partition name %s.\n", name);
+ return -1;
+ }
+
+ return i;
+}
+
+/*
+ * Read the content of a sub-partition from input file and store it in
+ * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
+ *
+ * Returns the maximum offset occupied by the sub-partitions.
+ */
+static size_t read_subpart_buf(void *data, size_t size, struct bpdt_entry *e,
+ size_t count)
+{
+ size_t i, type;
+ struct buffer *buf;
+ size_t max_offset = 0;
+
+ for (i = 0; i < count; i++) {
+ type = e[i].type;
+
+ if (type >= MAX_SUBPARTS) {
+ ERROR("Invalid sub-partition type %zd.\n", type);
+ exit(-1);
+ }
+
+ if (buffer_size(&ifwi_image.subpart_buf[type])) {
+ ERROR("Multiple sub-partitions of type %zd(%s).\n",
+ type, subparts[type].name);
+ exit(-1);
+ }
+
+ if (e[i].size == 0) {
+ INFO("Dummy sub-partition %zd(%s). Skipping.\n", type,
+ subparts[type].name);
+ continue;
+ }
+
+ assert((e[i].offset + e[i].size) <= size);
+
+ /*
+ * Sub-partitions in IFWI image are not in the same order as
+ * in BPDT entries. BPDT entires are in header_order whereas
+ * sub-partition offsets in the image are in pack_order.
+ */
+ if ((e[i].offset + e[i].size) > max_offset)
+ max_offset = e[i].offset + e[i].size;
+
+ /*
+ * S-BPDT sub-partition contains information about all the
+ * non-critical sub-partitions. Thus, size of S-BPDT
+ * sub-partition equals size of S-BPDT plus size of all the
+ * non-critical sub-partitions. Thus, reading whole of S-BPDT
+ * here would be redundant as the non-critical partitions are
+ * read and allocated buffers separately. Also, S-BPDT requires
+ * special handling for reading header and entries.
+ */
+ if (type == S_BPDT_TYPE)
+ continue;
+
+ buf = &ifwi_image.subpart_buf[type];
+
+ alloc_buffer(buf, e[i].size, subparts[type].name);
+ memcpy(buffer_get(buf), (uint8_t *)data + e[i].offset,
+ e[i].size);
+ }
+
+ assert(max_offset);
+ return max_offset;
+}
+
+/*
+ * Allocate buffer for bpdt header, entries and all sub-partition content.
+ * Returns offset in data where BPDT ends.
+ */
+static size_t alloc_bpdt_buffer(void *data, size_t size, size_t offset,
+ struct buffer *b, const char *name)
+{
+ struct bpdt_header bpdt_header;
+
+ assert((offset + BPDT_HEADER_SIZE) < size);
+ bpdt_read_header((uint8_t *)data + offset, &bpdt_header, name);
+
+ /* Buffer to read BPDT header and entries */
+ alloc_buffer(b, get_bpdt_size(&bpdt_header), name);
+
+ struct bpdt *bpdt = buffer_get(b);
+
+ memcpy(&bpdt->h, &bpdt_header, BPDT_HEADER_SIZE);
+
+ /*
+ * If no entries are present, maximum offset occupied is (offset +
+ * BPDT_HEADER_SIZE).
+ */
+ if (bpdt->h.descriptor_count == 0)
+ return (offset + BPDT_HEADER_SIZE);
+
+ /* Read all entries */
+ assert((offset + get_bpdt_size(&bpdt->h)) < size);
+ bpdt_read_entries((uint8_t *)data + offset + BPDT_HEADER_SIZE, bpdt,
+ name);
+
+ /* Read all sub-partition content in subpart_buf */
+ return read_subpart_buf(data, size, &bpdt->e[0],
+ bpdt->h.descriptor_count);
+}
+
+static void parse_sbpdt(void *data, size_t size)
+{
+ struct bpdt_entry *s;
+
+ s = find_entry_by_type(S_BPDT_TYPE);
+ if (!s)
+ return;
+
+ assert(size > s->offset);
+
+ alloc_bpdt_buffer(data, size, s->offset,
+ &ifwi_image.subpart_buf[S_BPDT_TYPE],
+ "S-BPDT");
+}
+
+static uint8_t calc_checksum(struct subpart_dir *s)
+{
+ size_t size = subpart_dir_size(&s->h);
+ uint8_t *data = (uint8_t *)s;
+ uint8_t checksum = 0;
+ size_t i;
+ uint8_t old_checksum = s->h.checksum;
+
+ s->h.checksum = 0;
+
+ for (i = 0; i < size; i++)
+ checksum += data[i];
+
+ s->h.checksum = old_checksum;
+
+ /* 2s complement */
+ return -checksum;
+}
+
+static void validate_subpart_dir(struct subpart_dir *s, const char *name,
+ bool checksum_check)
+{
+ if (s->h.marker != SUBPART_DIR_MARKER ||
+ s->h.header_version != SUBPART_DIR_HEADER_VERSION_SUPPORTED ||
+ s->h.entry_version != SUBPART_DIR_ENTRY_VERSION_SUPPORTED ||
+ s->h.header_length != SUBPART_DIR_HEADER_SIZE) {
+ ERROR("Invalid subpart_dir for %s.\n", name);
+ exit(-1);
+ }
+
+ if (!checksum_check)
+ return;
+
+ uint8_t checksum = calc_checksum(s);
+
+ if (checksum != s->h.checksum)
+ ERROR("Invalid checksum for %s (Expected=0x%x, Actual=0x%x).\n",
+ name, checksum, s->h.checksum);
+}
+
+static void validate_subpart_dir_without_checksum(struct subpart_dir *s,
+ const char *name)
+{
+ validate_subpart_dir(s, name, 0);
+}
+
+static void validate_subpart_dir_with_checksum(struct subpart_dir *s,
+ const char *name)
+{
+ validate_subpart_dir(s, name, 1);
+}
+
+static void parse_subpart_dir(struct buffer *subpart_dir_buf,
+ struct buffer *input_buf, const char *name)
+{
+ struct subpart_dir_header hdr;
+ size_t offset = 0;
+ uint8_t *data = buffer_get(input_buf);
+ size_t size = buffer_size(input_buf);
+
+ /* Read Subpart_Dir header */
+ assert(size >= SUBPART_DIR_HEADER_SIZE);
+ offset = read_member(data, offset, sizeof(hdr.marker), &hdr.marker);
+ offset = read_member(data, offset, sizeof(hdr.num_entries),
+ &hdr.num_entries);
+ offset = read_member(data, offset, sizeof(hdr.header_version),
+ &hdr.header_version);
+ offset = read_member(data, offset, sizeof(hdr.entry_version),
+ &hdr.entry_version);
+ offset = read_member(data, offset, sizeof(hdr.header_length),
+ &hdr.header_length);
+ offset = read_member(data, offset, sizeof(hdr.checksum), &hdr.checksum);
+ memcpy(hdr.name, data + offset, sizeof(hdr.name));
+ offset += sizeof(hdr.name);
+
+ validate_subpart_dir_without_checksum((struct subpart_dir *)&hdr, name);
+
+ assert(size > subpart_dir_size(&hdr));
+ alloc_buffer(subpart_dir_buf, subpart_dir_size(&hdr), "Subpart Dir");
+ memcpy(buffer_get(subpart_dir_buf), &hdr, SUBPART_DIR_HEADER_SIZE);
+
+ /* Read Subpart Dir entries */
+ struct subpart_dir *subpart_dir = buffer_get(subpart_dir_buf);
+ struct subpart_dir_entry *e = &subpart_dir->e[0];
+ uint32_t i;
+
+ for (i = 0; i < hdr.num_entries; i++) {
+ memcpy(e[i].name, data + offset, sizeof(e[i].name));
+ offset += sizeof(e[i].name);
+ offset = read_member(data, offset, sizeof(e[i].offset),
+ &e[i].offset);
+ offset = read_member(data, offset, sizeof(e[i].length),
+ &e[i].length);
+ offset = read_member(data, offset, sizeof(e[i].rsvd),
+ &e[i].rsvd);
+ }
+
+ validate_subpart_dir_with_checksum(subpart_dir, name);
+
+ print_subpart_dir(subpart_dir);
+}
+
+/* Parse input image file to identify different sub-partitions */
+static int ifwi_parse(void)
+{
+ struct buffer *buff = &ifwi_image.input_buff;
+ const char *image_name = param.image_name;
+
+ DEBUG("Parsing IFWI image...\n");
+
+ /* Read input file */
+ if (buffer_from_file(buff, image_name)) {
+ ERROR("Failed to read input file %s.\n", image_name);
+ return -1;
+ }
+
+ INFO("Buffer %p size 0x%zx\n", buff->data, buff->size);
+
+ /* Look for BPDT signature at 4K intervals */
+ size_t offset = 0;
+ void *data = buffer_get(buff);
+
+ while (offset < buffer_size(buff)) {
+ if (read_at_le32(data, offset) == BPDT_SIGNATURE)
+ break;
+ offset += 4 * KiB;
+ }
+
+ if (offset >= buffer_size(buff)) {
+ ERROR("Image does not contain BPDT!!\n");
+ return -1;
+ }
+
+ ifwi_image.input_ifwi_start_offset = offset;
+ INFO("BPDT starts at offset 0x%zx.\n", offset);
+
+ data = (uint8_t *)data + offset;
+ size_t ifwi_size = buffer_size(buff) - offset;
+
+ /* Read BPDT and sub-partitions */
+ uintptr_t end_offset;
+
+ end_offset = ifwi_image.input_ifwi_start_offset +
+ alloc_bpdt_buffer(data, ifwi_size, 0, &ifwi_image.bpdt, "BPDT");
+
+ /* Parse S-BPDT, if any */
+ parse_sbpdt(data, ifwi_size);
+
+ /*
+ * Store end offset of IFWI. Required for copying any trailing non-IFWI
+ * part of the image.
+ * ASSUMPTION: IFWI image always ends on a 4K boundary.
+ */
+ ifwi_image.input_ifwi_end_offset = ALIGN(end_offset, 4 * KiB);
+ DEBUG("Parsing done.\n");
+
+ return 0;
+}
+
+/*
+ * This function is used by repack to count the number of BPDT and S-BPDT
+ * entries that are present. It frees the current buffers used by the entries
+ * and allocates fresh buffers that can be used for repacking. Returns BPDT
+ * entries which are empty and need to be filled in.
+ */
+static void __bpdt_reset(struct buffer *b, size_t count, size_t size)
+{
+ size_t bpdt_size = BPDT_HEADER_SIZE + count * BPDT_ENTRY_SIZE;
+
+ assert(size >= bpdt_size);
+
+ /*
+ * If buffer does not have the required size, allocate a fresh buffer.
+ */
+ if (buffer_size(b) != size) {
+ struct buffer temp;
+
+ alloc_buffer(&temp, size, b->name);
+ memcpy(buffer_get(&temp), buffer_get(b), buffer_size(b));
+ buffer_delete(b);
+ *b = temp;
+ }
+
+ struct bpdt *bpdt = buffer_get(b);
+ uint8_t *ptr = (uint8_t *)&bpdt->e[0];
+ size_t entries_size = BPDT_ENTRY_SIZE * count;
+
+ /* Zero out BPDT entries */
+ memset(ptr, 0, entries_size);
+ /* Fill any pad-space with FF */
+ memset(ptr + entries_size, 0xFF, size - bpdt_size);
+
+ bpdt->h.descriptor_count = count;
+}
+
+static void bpdt_reset(void)
+{
+ size_t i;
+ size_t bpdt_count = 0, sbpdt_count = 0, dummy_bpdt_count = 0;
+
+ /* Count number of BPDT and S-BPDT entries */
+ for (i = 0; i < MAX_SUBPARTS; i++) {
+ if (buffer_size(&ifwi_image.subpart_buf[i]) == 0) {
+ if (subparts[i].attr & MANDATORY_BPDT_ENTRY) {
+ bpdt_count++;
+ dummy_bpdt_count++;
+ }
+ continue;
+ }
+
+ if (subparts[i].attr & NON_CRITICAL_SUBPART)
+ sbpdt_count++;
+ else
+ bpdt_count++;
+ }
+
+ DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count,
+ dummy_bpdt_count, sbpdt_count);
+
+ /* Update BPDT if required */
+ size_t bpdt_size = max(BPDT_MIN_SIZE,
+ BPDT_HEADER_SIZE + bpdt_count * BPDT_ENTRY_SIZE);
+ __bpdt_reset(&ifwi_image.bpdt, bpdt_count, bpdt_size);
+
+ /* Update S-BPDT if required */
+ bpdt_size = ALIGN(BPDT_HEADER_SIZE + sbpdt_count * BPDT_ENTRY_SIZE,
+ 4 * KiB);
+ __bpdt_reset(&ifwi_image.subpart_buf[S_BPDT_TYPE], sbpdt_count,
+ bpdt_size);
+}
+
+/* Initialize BPDT entries in header order */
+static void bpdt_entries_init_header_order(void)
+{
+ int i, type;
+ size_t size;
+
+ struct bpdt *bpdt, *sbpdt, *curr;
+ size_t bpdt_curr = 0, sbpdt_curr = 0, *count_ptr;
+
+ bpdt = buffer_get(&ifwi_image.bpdt);
+ sbpdt = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
+
+ for (i = 0; i < MAX_SUBPARTS; i++) {
+ type = bpdt_header_order[i];
+ size = buffer_size(&ifwi_image.subpart_buf[type]);
+
+ if (size == 0 && !(subparts[type].attr & MANDATORY_BPDT_ENTRY))
+ continue;
+
+ if (subparts[type].attr & NON_CRITICAL_SUBPART) {
+ curr = sbpdt;
+ count_ptr = &sbpdt_curr;
+ } else {
+ curr = bpdt;
+ count_ptr = &bpdt_curr;
+ }
+
+ assert(*count_ptr < curr->h.descriptor_count);
+ curr->e[*count_ptr].type = type;
+ curr->e[*count_ptr].flags = 0;
+ curr->e[*count_ptr].offset = 0;
+ curr->e[*count_ptr].size = size;
+
+ (*count_ptr)++;
+ }
+}
+
+static void pad_buffer(struct buffer *b, size_t size)
+{
+ size_t buff_size = buffer_size(b);
+
+ assert(buff_size <= size);
+
+ if (buff_size == size)
+ return;
+
+ struct buffer temp;
+
+ alloc_buffer(&temp, size, b->name);
+ uint8_t *data = buffer_get(&temp);
+
+ memcpy(data, buffer_get(b), buff_size);
+ memset(data + buff_size, 0xFF, size - buff_size);
+
+ *b = temp;
+}
+
+/* Initialize offsets of entries using pack order */
+static void bpdt_entries_init_pack_order(void)
+{
+ int i, type;
+ struct bpdt_entry *curr;
+ size_t curr_offset, curr_end;
+
+ curr_offset = max(BPDT_MIN_SIZE, buffer_size(&ifwi_image.bpdt));
+
+ /*
+ * There are two types of sub-partitions that need to be handled here:
+ * 1. Sub-partitions that lie within the same 4K as BPDT
+ * 2. Sub-partitions that lie outside the 4K of BPDT
+ *
+ * For sub-partitions of type # 1, there is no requirement on the start
+ * or end of the sub-partition. They need to be packed in without any
+ * holes left in between. If there is any empty space left after the end
+ * of the last sub-partition in 4K of BPDT, then that space needs to be
+ * padded with FF bytes, but the size of the last sub-partition remains
+ * unchanged.
+ *
+ * For sub-partitions of type # 2, both the start and end should be a
+ * multiple of 4K. If not, then it needs to be padded with FF bytes and
+ * size adjusted such that the sub-partition ends on 4K boundary.
+ */
+
+ /* #1 Sub-partitions that lie within same 4K as BPDT */
+ struct buffer *last_bpdt_buff = &ifwi_image.bpdt;
+
+ for (i = 0; i < MAX_SUBPARTS; i++) {
+ type = bpdt_pack_order[i];
+ curr = find_entry_by_type(type);
+
+ if (!curr || curr->size == 0)
+ continue;
+
+ if (!(subparts[type].attr & LIES_WITHIN_BPDT_4K))
+ continue;
+
+ curr->offset = curr_offset;
+ curr_offset = curr->offset + curr->size;
+ last_bpdt_buff = &ifwi_image.subpart_buf[type];
+ DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
+ type, curr_offset, curr->offset, curr->size,
+ buffer_size(&ifwi_image.subpart_buf[type]));
+ }
+
+ /* Pad ff bytes if there is any empty space left in BPDT 4K */
+ curr_end = ALIGN(curr_offset, 4 * KiB);
+ pad_buffer(last_bpdt_buff,
+ buffer_size(last_bpdt_buff) + (curr_end - curr_offset));
+ curr_offset = curr_end;
+
+ /* #2 Sub-partitions that lie outside of BPDT 4K */
+ for (i = 0; i < MAX_SUBPARTS; i++) {
+ type = bpdt_pack_order[i];
+ curr = find_entry_by_type(type);
+
+ if (!curr || curr->size == 0)
+ continue;
+
+ if (subparts[type].attr & LIES_WITHIN_BPDT_4K)
+ continue;
+
+ assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
+ curr->offset = curr_offset;
+ curr_end = ALIGN(curr->offset + curr->size, 4 * KiB);
+ curr->size = curr_end - curr->offset;
+
+ pad_buffer(&ifwi_image.subpart_buf[type], curr->size);
+
+ curr_offset = curr_end;
+ DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
+ type, curr_offset, curr->offset, curr->size,
+ buffer_size(&ifwi_image.subpart_buf[type]));
+ }
+
+ /*
+ * Update size of S-BPDT to include size of all non-critical
+ * sub-partitions.
+ *
+ * Assumption: S-BPDT always lies at the end of IFWI image.
+ */
+ curr = find_entry_by_type(S_BPDT_TYPE);
+ assert(curr);
+
+ assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
+ curr->size = curr_offset - curr->offset;
+}
+
+/* Convert all members of BPDT to little-endian format */
+static void bpdt_fixup_write_buffer(struct buffer *buf)
+{
+ struct bpdt *s = buffer_get(buf);
+
+ struct bpdt_header *h = &s->h;
+ struct bpdt_entry *e = &s->e[0];
+
+ size_t count = h->descriptor_count;
+
+ size_t offset = 0;
+
+ offset = fix_member(&h->signature, offset, sizeof(h->signature));
+ offset = fix_member(&h->descriptor_count, offset,
+ sizeof(h->descriptor_count));
+ offset = fix_member(&h->bpdt_version, offset, sizeof(h->bpdt_version));
+ offset = fix_member(&h->xor_redundant_block, offset,
+ sizeof(h->xor_redundant_block));
+ offset = fix_member(&h->ifwi_version, offset, sizeof(h->ifwi_version));
+ offset = fix_member(&h->fit_tool_version, offset,
+ sizeof(h->fit_tool_version));
+
+ uint32_t i;
+
+ for (i = 0; i < count; i++) {
+ offset = fix_member(&e[i].type, offset, sizeof(e[i].type));
+ offset = fix_member(&e[i].flags, offset, sizeof(e[i].flags));
+ offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
+ offset = fix_member(&e[i].size, offset, sizeof(e[i].size));
+ }
+}
+
+/* Write BPDT to output buffer after fixup */
+static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src)
+{
+ bpdt_fixup_write_buffer(src);
+ memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src));
+}
+
+/*
+ * Follows these steps to re-create image:
+ * 1. Write any non-IFWI prefix.
+ * 2. Write out BPDT header and entries.
+ * 3. Write sub-partition buffers to respective offsets.
+ * 4. Write any non-IFWI suffix.
+ *
+ * While performing the above steps, make sure that any empty holes are filled
+ * with FF.
+ */
+static void ifwi_write(const char *image_name)
+{
+ struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE);
+
+ assert(s);
+
+ size_t ifwi_start, ifwi_end, file_end;
+
+ ifwi_start = ifwi_image.input_ifwi_start_offset;
+ ifwi_end = ifwi_start + ALIGN(s->offset + s->size, 4 * KiB);
+ file_end = ifwi_end + (buffer_size(&ifwi_image.input_buff) -
+ ifwi_image.input_ifwi_end_offset);
+
+ struct buffer b;
+
+ alloc_buffer(&b, file_end, "Final-IFWI");
+
+ uint8_t *input_data = buffer_get(&ifwi_image.input_buff);
+ uint8_t *output_data = buffer_get(&b);
+
+ DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start,
+ ifwi_end, file_end);
+
+ /* Copy non-IFWI prefix, if any */
+ memcpy(output_data, input_data, ifwi_start);
+
+ DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start);
+
+ struct buffer ifwi;
+
+ buffer_splice(&ifwi, &b, ifwi_start, ifwi_end - ifwi_start);
+ uint8_t *ifwi_data = buffer_get(&ifwi);
+
+ /* Copy sub-partitions using pack_order */
+ struct bpdt_entry *curr;
+ struct buffer *subpart_buf;
+ int i, type;
+
+ for (i = 0; i < MAX_SUBPARTS; i++) {
+ type = bpdt_pack_order[i];
+
+ if (type == S_BPDT_TYPE)
+ continue;
+
+ curr = find_entry_by_type(type);
+
+ if (!curr || !curr->size)
+ continue;
+
+ subpart_buf = &ifwi_image.subpart_buf[type];
+
+ DEBUG("curr->offset=0x%x, curr->size=0x%x, type=%d, write_size=0x%zx\n",
+ curr->offset, curr->size, type, buffer_size(subpart_buf));
+
+ assert((curr->offset + buffer_size(subpart_buf)) <=
+ buffer_size(&ifwi));
+
+ memcpy(ifwi_data + curr->offset, buffer_get(subpart_buf),
+ buffer_size(subpart_buf));
+ }
+
+ /* Copy non-IFWI suffix, if any */
+ if (ifwi_end != file_end) {
+ memcpy(output_data + ifwi_end,
+ input_data + ifwi_image.input_ifwi_end_offset,
+ file_end - ifwi_end);
+ DEBUG("Copied non-IFWI suffix (offset=0x%zx,size=0x%zx).\n",
+ ifwi_end, file_end - ifwi_end);
+ }
+
+ /*
+ * Convert BPDT to little-endian format and write it to output buffer.
+ * S-BPDT is written first and then BPDT.
+ */
+ bpdt_write(&ifwi, s->offset, &ifwi_image.subpart_buf[S_BPDT_TYPE]);
+ bpdt_write(&ifwi, 0, &ifwi_image.bpdt);
+
+ if (buffer_write_file(&b, image_name)) {
+ ERROR("File write error\n");
+ exit(-1);
+ }
+
+ buffer_delete(&b);
+ printf("Image written successfully to %s.\n", image_name);
+}
+
+/*
+ * Calculate size and offset of each sub-partition again since it might have
+ * changed because of add/delete operation. Also, re-create BPDT and S-BPDT
+ * entries and write back the new IFWI image to file.
+ */
+static void ifwi_repack(void)
+{
+ bpdt_reset();
+ bpdt_entries_init_header_order();
+ bpdt_entries_init_pack_order();
+
+ struct bpdt *b = buffer_get(&ifwi_image.bpdt);
+
+ bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
+
+ b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
+ bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
+
+ DEBUG("Repack done.. writing image.\n");
+ ifwi_write(param.image_name);
+}
+
+static void init_subpart_dir_header(struct subpart_dir_header *hdr,
+ size_t count, const char *name)
+{
+ memset(hdr, 0, sizeof(*hdr));
+
+ hdr->marker = SUBPART_DIR_MARKER;
+ hdr->num_entries = count;
+ hdr->header_version = SUBPART_DIR_HEADER_VERSION_SUPPORTED;
+ hdr->entry_version = SUBPART_DIR_ENTRY_VERSION_SUPPORTED;
+ hdr->header_length = SUBPART_DIR_HEADER_SIZE;
+ memcpy(hdr->name, name, sizeof(hdr->name));
+}
+
+static size_t init_subpart_dir_entry(struct subpart_dir_entry *e,
+ struct buffer *b, size_t offset)
+{
+ memset(e, 0, sizeof(*e));
+
+ assert(strlen(b->name) <= sizeof(e->name));
+ strncpy((char *)e->name, (char *)b->name, sizeof(e->name));
+ e->offset = offset;
+ e->length = buffer_size(b);
+
+ return (offset + buffer_size(b));
+}
+
+static void init_manifest_header(struct manifest_header *hdr, size_t size)
+{
+ memset(hdr, 0, sizeof(*hdr));
+
+ hdr->header_type = 0x4;
+ assert((MANIFEST_HDR_SIZE % DWORD_SIZE) == 0);
+ hdr->header_length = MANIFEST_HDR_SIZE / DWORD_SIZE;
+ hdr->header_version = 0x10000;
+ hdr->vendor = 0x8086;
+
+ struct tm *local_time;
+ time_t curr_time;
+ char buffer[11];
+
+ curr_time = time(NULL);
+ local_time = localtime(&curr_time);
+ strftime(buffer, sizeof(buffer), "0x%Y%m%d", local_time);
+ hdr->date = strtoul(buffer, NULL, 16);
+
+ assert((size % DWORD_SIZE) == 0);
+ hdr->size = size / DWORD_SIZE;
+ hdr->id = MANIFEST_ID_MAGIC;
+}
+
+static void init_signed_pkg_info_ext(struct signed_pkg_info_ext *ext,
+ size_t count, const char *name)
+{
+ memset(ext, 0, sizeof(*ext));
+
+ ext->ext_type = SIGNED_PKG_INFO_EXT_TYPE;
+ ext->ext_length = SIGNED_PKG_INFO_EXT_SIZE + count * MODULE_SIZE;
+ memcpy(ext->name, name, sizeof(ext->name));
+}
+
+static void subpart_dir_fixup_write_buffer(struct buffer *buf)
+{
+ struct subpart_dir *s = buffer_get(buf);
+ struct subpart_dir_header *h = &s->h;
+ struct subpart_dir_entry *e = &s->e[0];
+
+ size_t count = h->num_entries;
+ size_t offset = 0;
+
+ offset = fix_member(&h->marker, offset, sizeof(h->marker));
+ offset = fix_member(&h->num_entries, offset, sizeof(h->num_entries));
+ offset = fix_member(&h->header_version, offset,
+ sizeof(h->header_version));
+ offset = fix_member(&h->entry_version, offset,
+ sizeof(h->entry_version));
+ offset = fix_member(&h->header_length, offset,
+ sizeof(h->header_length));
+ offset = fix_member(&h->checksum, offset, sizeof(h->checksum));
+ offset += sizeof(h->name);
+
+ uint32_t i;
+
+ for (i = 0; i < count; i++) {
+ offset += sizeof(e[i].name);
+ offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
+ offset = fix_member(&e[i].length, offset, sizeof(e[i].length));
+ offset = fix_member(&e[i].rsvd, offset, sizeof(e[i].rsvd));
+ }
+}
+
+static void create_subpart(struct buffer *dst, struct buffer *info[],
+ size_t count, const char *name)
+{
+ struct buffer subpart_dir_buff;
+ size_t size = SUBPART_DIR_HEADER_SIZE + count * SUBPART_DIR_ENTRY_SIZE;
+
+ alloc_buffer(&subpart_dir_buff, size, "subpart-dir");
+
+ struct subpart_dir_header *h = buffer_get(&subpart_dir_buff);
+ struct subpart_dir_entry *e = (struct subpart_dir_entry *)(h + 1);
+
+ init_subpart_dir_header(h, count, name);
+
+ size_t curr_offset = size;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ curr_offset = init_subpart_dir_entry(&e[i], info[i],
+ curr_offset);
+ }
+
+ alloc_buffer(dst, curr_offset, name);
+ uint8_t *data = buffer_get(dst);
+
+ for (i = 0; i < count; i++) {
+ memcpy(data + e[i].offset, buffer_get(info[i]),
+ buffer_size(info[i]));
+ }
+
+ h->checksum = calc_checksum(buffer_get(&subpart_dir_buff));
+
+ struct subpart_dir *dir = buffer_get(&subpart_dir_buff);
+
+ print_subpart_dir(dir);
+
+ subpart_dir_fixup_write_buffer(&subpart_dir_buff);
+ memcpy(data, dir, buffer_size(&subpart_dir_buff));
+
+ buffer_delete(&subpart_dir_buff);
+}
+
+static enum ifwi_ret ibbp_dir_add(int type)
+{
+ struct buffer manifest;
+ struct signed_pkg_info_ext *ext;
+ struct buffer ibbl;
+ struct buffer ibb;
+
+#define DUMMY_IBB_SIZE (4 * KiB)
+
+ assert(type == IBB_TYPE);
+
+ /*
+ * Entry # 1 - IBBP.man
+ * Contains manifest header and signed pkg info extension.
+ */
+ size_t size = MANIFEST_HDR_SIZE + SIGNED_PKG_INFO_EXT_SIZE;
+
+ alloc_buffer(&manifest, size, "IBBP.man");
+
+ struct manifest_header *man_hdr = buffer_get(&manifest);
+
+ init_manifest_header(man_hdr, size);
+
+ ext = (struct signed_pkg_info_ext *)(man_hdr + 1);
+
+ init_signed_pkg_info_ext(ext, 0, subparts[type].name);
+
+ /* Entry # 2 - IBBL */
+ if (buffer_from_file(&ibbl, param.file_name))
+ return COMMAND_ERR;
+
+ /* Entry # 3 - IBB */
+ alloc_buffer(&ibb, DUMMY_IBB_SIZE, "IBB");
+ memset(buffer_get(&ibb), 0xFF, DUMMY_IBB_SIZE);
+
+ /* Create subpartition */
+ struct buffer *info[] = {
+ &manifest, &ibbl, &ibb,
+ };
+ create_subpart(&ifwi_image.subpart_buf[type], &info[0],
+ ARRAY_SIZE(info), subparts[type].name);
+
+ return REPACK_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_raw_add(int type)
+{
+ if (buffer_from_file(&ifwi_image.subpart_buf[type], param.file_name))
+ return COMMAND_ERR;
+
+ printf("Sub-partition %s(%d) added from file %s.\n", param.subpart_name,
+ type, param.file_name);
+ return REPACK_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_dir_add(int type)
+{
+ if (!(subparts[type].attr & CONTAINS_DIR) ||
+ !subparts[type].dir_ops.dir_add) {
+ ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
+ subparts[type].name, type);
+ return COMMAND_ERR;
+ }
+
+ if (!param.dentry_name) {
+ ERROR("%s: -e option required\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ enum ifwi_ret ret = subparts[type].dir_ops.dir_add(type);
+
+ if (ret != COMMAND_ERR)
+ printf("Sub-partition %s(%d) entry %s added from file %s.\n",
+ param.subpart_name, type, param.dentry_name,
+ param.file_name);
+ else
+ ERROR("Sub-partition dir operation failed.\n");
+
+ return ret;
+}
+
+static enum ifwi_ret ifwi_add(void)
+{
+ if (!param.file_name) {
+ ERROR("%s: -f option required\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ if (!param.subpart_name) {
+ ERROR("%s: -n option required\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ int type = find_type_by_name(param.subpart_name);
+
+ if (type == -1)
+ return COMMAND_ERR;
+
+ const struct subpart_info *curr_subpart = &subparts[type];
+
+ if (curr_subpart->attr & AUTO_GENERATED) {
+ ERROR("Cannot add auto-generated sub-partitions.\n");
+ return COMMAND_ERR;
+ }
+
+ if (buffer_size(&ifwi_image.subpart_buf[type])) {
+ ERROR("Image already contains sub-partition %s(%d).\n",
+ param.subpart_name, type);
+ return COMMAND_ERR;
+ }
+
+ if (param.dir_ops)
+ return ifwi_dir_add(type);
+
+ return ifwi_raw_add(type);
+}
+
+static enum ifwi_ret ifwi_delete(void)
+{
+ if (!param.subpart_name) {
+ ERROR("%s: -n option required\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ int type = find_type_by_name(param.subpart_name);
+
+ if (type == -1)
+ return COMMAND_ERR;
+
+ const struct subpart_info *curr_subpart = &subparts[type];
+
+ if (curr_subpart->attr & AUTO_GENERATED) {
+ ERROR("Cannot delete auto-generated sub-partitions.\n");
+ return COMMAND_ERR;
+ }
+
+ if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
+ printf("Image does not contain sub-partition %s(%d).\n",
+ param.subpart_name, type);
+ return NO_ACTION_REQUIRED;
+ }
+
+ buffer_delete(&ifwi_image.subpart_buf[type]);
+ printf("Sub-Partition %s(%d) deleted.\n", subparts[type].name, type);
+ return REPACK_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_dir_extract(int type)
+{
+ if (!(subparts[type].attr & CONTAINS_DIR)) {
+ ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
+ subparts[type].name, type);
+ return COMMAND_ERR;
+ }
+
+ if (!param.dentry_name) {
+ ERROR("%s: -e option required.\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ struct buffer subpart_dir_buff;
+
+ parse_subpart_dir(&subpart_dir_buff, &ifwi_image.subpart_buf[type],
+ subparts[type].name);
+
+ uint32_t i;
+ struct subpart_dir *s = buffer_get(&subpart_dir_buff);
+
+ for (i = 0; i < s->h.num_entries; i++) {
+ if (!strncmp((char *)s->e[i].name, param.dentry_name,
+ sizeof(s->e[i].name)))
+ break;
+ }
+
+ if (i == s->h.num_entries) {
+ ERROR("Entry %s not found in subpartition for %s.\n",
+ param.dentry_name, param.subpart_name);
+ exit(-1);
+ }
+
+ struct buffer dst;
+
+ DEBUG("Splicing buffer at 0x%x size 0x%x\n", s->e[i].offset,
+ s->e[i].length);
+ buffer_splice(&dst, &ifwi_image.subpart_buf[type], s->e[i].offset,
+ s->e[i].length);
+
+ if (buffer_write_file(&dst, param.file_name))
+ return COMMAND_ERR;
+
+ printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
+ param.subpart_name, type, param.dentry_name, param.file_name);
+
+ return NO_ACTION_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_raw_extract(int type)
+{
+ if (buffer_write_file(&ifwi_image.subpart_buf[type], param.file_name))
+ return COMMAND_ERR;
+
+ printf("Sub-Partition %s(%d) stored in %s.\n", param.subpart_name, type,
+ param.file_name);
+
+ return NO_ACTION_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_extract(void)
+{
+ if (!param.file_name) {
+ ERROR("%s: -f option required\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ if (!param.subpart_name) {
+ ERROR("%s: -n option required\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ int type = find_type_by_name(param.subpart_name);
+
+ if (type == -1)
+ return COMMAND_ERR;
+
+ if (type == S_BPDT_TYPE) {
+ INFO("Tool does not support raw extract for %s\n",
+ param.subpart_name);
+ return NO_ACTION_REQUIRED;
+ }
+
+ if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
+ ERROR("Image does not contain sub-partition %s(%d).\n",
+ param.subpart_name, type);
+ return COMMAND_ERR;
+ }
+
+ INFO("Extracting sub-partition %s(%d).\n", param.subpart_name, type);
+ if (param.dir_ops)
+ return ifwi_dir_extract(type);
+
+ return ifwi_raw_extract(type);
+}
+
+static enum ifwi_ret ifwi_print(void)
+{
+ verbose += 2;
+
+ struct bpdt *b = buffer_get(&ifwi_image.bpdt);
+
+ bpdt_print_header(&b->h, "BPDT");
+ bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
+
+ b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
+ bpdt_print_header(&b->h, "S-BPDT");
+ bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
+
+ if (param.dir_ops == 0) {
+ verbose -= 2;
+ return NO_ACTION_REQUIRED;
+ }
+
+ int i;
+ struct buffer subpart_dir_buf;
+
+ for (i = 0; i < MAX_SUBPARTS ; i++) {
+ if (!(subparts[i].attr & CONTAINS_DIR) ||
+ (buffer_size(&ifwi_image.subpart_buf[i]) == 0))
+ continue;
+
+ parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[i],
+ subparts[i].name);
+ buffer_delete(&subpart_dir_buf);
+ }
+
+ verbose -= 2;
+
+ return NO_ACTION_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_raw_replace(int type)
+{
+ buffer_delete(&ifwi_image.subpart_buf[type]);
+ return ifwi_raw_add(type);
+}
+
+static enum ifwi_ret ifwi_dir_replace(int type)
+{
+ if (!(subparts[type].attr & CONTAINS_DIR)) {
+ ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
+ subparts[type].name, type);
+ return COMMAND_ERR;
+ }
+
+ if (!param.dentry_name) {
+ ERROR("%s: -e option required.\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ struct buffer subpart_dir_buf;
+
+ parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[type],
+ subparts[type].name);
+
+ uint32_t i;
+ struct subpart_dir *s = buffer_get(&subpart_dir_buf);
+
+ for (i = 0; i < s->h.num_entries; i++) {
+ if (!strcmp((char *)s->e[i].name, param.dentry_name))
+ break;
+ }
+
+ if (i == s->h.num_entries) {
+ ERROR("Entry %s not found in subpartition for %s.\n",
+ param.dentry_name, param.subpart_name);
+ exit(-1);
+ }
+
+ struct buffer b;
+
+ if (buffer_from_file(&b, param.file_name)) {
+ ERROR("Failed to read %s\n", param.file_name);
+ exit(-1);
+ }
+
+ struct buffer dst;
+ size_t dst_size = buffer_size(&ifwi_image.subpart_buf[type]) +
+ buffer_size(&b) - s->e[i].length;
+ size_t subpart_start = s->e[i].offset;
+ size_t subpart_end = s->e[i].offset + s->e[i].length;
+
+ alloc_buffer(&dst, dst_size, ifwi_image.subpart_buf[type].name);
+
+ uint8_t *src_data = buffer_get(&ifwi_image.subpart_buf[type]);
+ uint8_t *dst_data = buffer_get(&dst);
+ size_t curr_offset = 0;
+
+ /* Copy data before the sub-partition entry */
+ memcpy(dst_data + curr_offset, src_data, subpart_start);
+ curr_offset += subpart_start;
+
+ /* Copy sub-partition entry */
+ memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
+ curr_offset += buffer_size(&b);
+
+ /* Copy remaining data */
+ memcpy(dst_data + curr_offset, src_data + subpart_end,
+ buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end);
+
+ /* Update sub-partition buffer */
+ int offset = s->e[i].offset;
+
+ buffer_delete(&ifwi_image.subpart_buf[type]);
+ ifwi_image.subpart_buf[type] = dst;
+
+ /* Update length of entry in the subpartition */
+ s->e[i].length = buffer_size(&b);
+ buffer_delete(&b);
+
+ /* Adjust offsets of affected entries in subpartition */
+ offset = s->e[i].offset - offset;
+ for (; i < s->h.num_entries; i++)
+ s->e[i].offset += offset;
+
+ /* Re-calculate checksum */
+ s->h.checksum = calc_checksum(s);
+
+ /* Convert members to litte-endian */
+ subpart_dir_fixup_write_buffer(&subpart_dir_buf);
+
+ memcpy(dst_data, buffer_get(&subpart_dir_buf),
+ buffer_size(&subpart_dir_buf));
+
+ buffer_delete(&subpart_dir_buf);
+
+ printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
+ param.subpart_name, type, param.dentry_name, param.file_name);
+
+ return REPACK_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_replace(void)
+{
+ if (!param.file_name) {
+ ERROR("%s: -f option required\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ if (!param.subpart_name) {
+ ERROR("%s: -n option required\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ int type = find_type_by_name(param.subpart_name);
+
+ if (type == -1)
+ return COMMAND_ERR;
+
+ const struct subpart_info *curr_subpart = &subparts[type];
+
+ if (curr_subpart->attr & AUTO_GENERATED) {
+ ERROR("Cannot replace auto-generated sub-partitions.\n");
+ return COMMAND_ERR;
+ }
+
+ if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
+ ERROR("Image does not contain sub-partition %s(%d).\n",
+ param.subpart_name, type);
+ return COMMAND_ERR;
+ }
+
+ if (param.dir_ops)
+ return ifwi_dir_replace(type);
+
+ return ifwi_raw_replace(type);
+}
+
+static enum ifwi_ret ifwi_create(void)
+{
+ /*
+ * Create peels off any non-IFWI content present in the input buffer and
+ * creates output file with only the IFWI present.
+ */
+
+ if (!param.file_name) {
+ ERROR("%s: -f option required\n", __func__);
+ return COMMAND_ERR;
+ }
+
+ /* Peel off any non-IFWI prefix */
+ buffer_seek(&ifwi_image.input_buff,
+ ifwi_image.input_ifwi_start_offset);
+ /* Peel off any non-IFWI suffix */
+ buffer_set_size(&ifwi_image.input_buff,
+ ifwi_image.input_ifwi_end_offset -
+ ifwi_image.input_ifwi_start_offset);
+
+ /*
+ * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
+ */
+ ifwi_image.input_ifwi_end_offset -= ifwi_image.input_ifwi_start_offset;
+ ifwi_image.input_ifwi_start_offset = 0;
+
+ param.image_name = param.file_name;
+
+ return REPACK_REQUIRED;
+}
+
+struct command {
+ const char *name;
+ const char *optstring;
+ enum ifwi_ret (*function)(void);
+};
+
+static const struct command commands[] = {
+ {"add", "f:n:e:dvh?", ifwi_add},
+ {"create", "f:vh?", ifwi_create},
+ {"delete", "f:n:vh?", ifwi_delete},
+ {"extract", "f:n:e:dvh?", ifwi_extract},
+ {"print", "dh?", ifwi_print},
+ {"replace", "f:n:e:dvh?", ifwi_replace},
+};
+
+static struct option long_options[] = {
+ {"subpart_dentry", required_argument, 0, 'e'},
+ {"file", required_argument, 0, 'f'},
+ {"help", required_argument, 0, 'h'},
+ {"name", required_argument, 0, 'n'},
+ {"dir_ops", no_argument, 0, 'd'},
+ {"verbose", no_argument, 0, 'v'},
+ {NULL, 0, 0, 0 }
+};
+
+static void usage(const char *name)
+{
+ printf("ifwitool: Utility for IFWI manipulation\n\n"
+ "USAGE:\n"
+ " %s [-h]\n"
+ " %s FILE COMMAND [PARAMETERS]\n\n"
+ "COMMANDs:\n"
+ " add -f FILE -n NAME [-d -e ENTRY]\n"
+ " create -f FILE\n"
+ " delete -n NAME\n"
+ " extract -f FILE -n NAME [-d -e ENTRY]\n"
+ " print [-d]\n"
+ " replace -f FILE -n NAME [-d -e ENTRY]\n"
+ "OPTIONs:\n"
+ " -f FILE : File to read/write/create/extract\n"
+ " -d : Perform directory operation\n"
+ " -e ENTRY: Name of directory entry to operate on\n"
+ " -v : Verbose level\n"
+ " -h : Help message\n"
+ " -n NAME : Name of sub-partition to operate on\n",
+ name, name
+ );
+
+ printf("\nNAME should be one of:\n");
+ int i;
+
+ for (i = 0; i < MAX_SUBPARTS; i++)
+ printf("%s(%s)\n", subparts[i].name, subparts[i].readable_name);
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 3) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ param.image_name = argv[1];
+ char *cmd = argv[2];
+
+ optind += 2;
+
+ uint32_t i;
+
+ for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ if (strcmp(cmd, commands[i].name) != 0)
+ continue;
+
+ int c;
+
+ while (1) {
+ int option_index;
+
+ c = getopt_long(argc, argv, commands[i].optstring,
+ long_options, &option_index);
+
+ if (c == -1)
+ break;
+
+ /* Filter out illegal long options */
+ if (!strchr(commands[i].optstring, c)) {
+ ERROR("%s: invalid option -- '%c'\n", argv[0],
+ c);
+ c = '?';
+ }
+
+ switch (c) {
+ case 'n':
+ param.subpart_name = optarg;
+ break;
+ case 'f':
+ param.file_name = optarg;
+ break;
+ case 'd':
+ param.dir_ops = 1;
+ break;
+ case 'e':
+ param.dentry_name = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ return 1;
+ default:
+ break;
+ }
+ }
+
+ if (ifwi_parse()) {
+ ERROR("%s: ifwi parsing failed\n", argv[0]);
+ return 1;
+ }
+
+ enum ifwi_ret ret = commands[i].function();
+
+ if (ret == COMMAND_ERR) {
+ ERROR("%s: failed execution\n", argv[0]);
+ return 1;
+ }
+
+ if (ret == REPACK_REQUIRED)
+ ifwi_repack();
+
+ return 0;
+ }
+
+ ERROR("%s: invalid command\n", argv[0]);
+ return 1;
+}
diff --git a/tools/mkenvimage.c b/tools/mkenvimage.c
index 75967d0..a8eebab 100644
--- a/tools/mkenvimage.c
+++ b/tools/mkenvimage.c
@@ -65,10 +65,12 @@
exit(EXIT_FAILURE);
}
+#define CHUNK_SIZE 4096
+
int main(int argc, char **argv)
{
uint32_t crc, targetendian_crc;
- const char *txt_filename = NULL, *bin_filename = NULL;
+ const char *bin_filename = NULL;
int txt_fd, bin_fd;
unsigned char *dataptr, *envptr;
unsigned char *filebuf = NULL;
@@ -76,12 +78,11 @@
int bigendian = 0;
int redundant = 0;
unsigned char padbyte = 0xff;
+ int readbytes = 0;
int option;
int ret = EXIT_SUCCESS;
- struct stat txt_file_stat;
-
int fp, ep;
const char *prg;
@@ -156,63 +157,33 @@
/* Open the input file ... */
if (optind >= argc || strcmp(argv[optind], "-") == 0) {
- int readbytes = 0;
- int readlen = sizeof(*envptr) * 4096;
txt_fd = STDIN_FILENO;
-
- do {
- filebuf = realloc(filebuf, filesize + readlen);
- if (!filebuf) {
- fprintf(stderr, "Can't realloc memory for the input file buffer\n");
- return EXIT_FAILURE;
- }
- readbytes = read(txt_fd, filebuf + filesize, readlen);
- if (readbytes < 0) {
- fprintf(stderr, "Error while reading stdin: %s\n",
- strerror(errno));
- return EXIT_FAILURE;
- }
- filesize += readbytes;
- } while (readbytes == readlen);
-
} else {
- txt_filename = argv[optind];
- txt_fd = open(txt_filename, O_RDONLY);
+ txt_fd = open(argv[optind], O_RDONLY);
if (txt_fd == -1) {
fprintf(stderr, "Can't open \"%s\": %s\n",
- txt_filename, strerror(errno));
+ argv[optind], strerror(errno));
return EXIT_FAILURE;
}
- /* ... and check it */
- ret = fstat(txt_fd, &txt_file_stat);
- if (ret == -1) {
- fprintf(stderr, "Can't stat() on \"%s\": %s\n",
- txt_filename, strerror(errno));
+ }
+
+ do {
+ filebuf = realloc(filebuf, filesize + CHUNK_SIZE);
+ if (!filebuf) {
+ fprintf(stderr, "Can't realloc memory for the input file buffer\n");
return EXIT_FAILURE;
}
-
- filesize = txt_file_stat.st_size;
-
- filebuf = mmap(NULL, sizeof(*envptr) * filesize, PROT_READ,
- MAP_PRIVATE, txt_fd, 0);
- if (filebuf == MAP_FAILED) {
- fprintf(stderr, "mmap (%zu bytes) failed: %s\n",
- sizeof(*envptr) * filesize,
- strerror(errno));
- fprintf(stderr, "Falling back to read()\n");
-
- filebuf = malloc(sizeof(*envptr) * filesize);
- ret = read(txt_fd, filebuf, sizeof(*envptr) * filesize);
- if (ret != sizeof(*envptr) * filesize) {
- fprintf(stderr, "Can't read the whole input file (%zu bytes): %s\n",
- sizeof(*envptr) * filesize,
- strerror(errno));
-
- return EXIT_FAILURE;
- }
+ readbytes = read(txt_fd, filebuf + filesize, CHUNK_SIZE);
+ if (readbytes < 0) {
+ fprintf(stderr, "Error while reading: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
}
+ filesize += readbytes;
+ } while (readbytes > 0);
+
+ if (txt_fd != STDIN_FILENO)
ret = close(txt_fd);
- }
/* Parse a byte at time until reaching the file OR until the environment fills
* up. Check ep against envsize - 1 to allow for extra trailing '\0'. */
diff --git a/tools/mkimage.c b/tools/mkimage.c
index d1e1a67..4217188 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -105,7 +105,7 @@
" -F => re-sign existing FIT image\n"
" -p => place external data at a static position\n"
" -r => mark keys used as 'required' in dtb\n"
- " -N => engine to use for signing (pkcs11)\n");
+ " -N => openssl engine to use for signing\n");
#else
fprintf(stderr,
"Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
diff --git a/tools/patman/command.py b/tools/patman/command.py
index 14edcda..16299f3 100644
--- a/tools/patman/command.py
+++ b/tools/patman/command.py
@@ -108,8 +108,8 @@
return result
def Output(*cmd, **kwargs):
- raise_on_error = kwargs.get('raise_on_error', True)
- return RunPipe([cmd], capture=True, raise_on_error=raise_on_error).stdout
+ kwargs['raise_on_error'] = kwargs.get('raise_on_error', True)
+ return RunPipe([cmd], capture=True, **kwargs).stdout
def OutputOneLine(*cmd, **kwargs):
raise_on_error = kwargs.pop('raise_on_error', True)
diff --git a/tools/patman/test_util.py b/tools/patman/test_util.py
index ea36cd1..09f258c 100644
--- a/tools/patman/test_util.py
+++ b/tools/patman/test_util.py
@@ -46,9 +46,10 @@
glob_list = []
glob_list += exclude_list
glob_list += ['*libfdt.py', '*site-packages*', '*dist-packages*']
+ test_cmd = 'test' if 'binman.py' in prog else '-t'
cmd = ('PYTHONPATH=$PYTHONPATH:%s/sandbox_spl/tools %s-coverage run '
- '--omit "%s" %s -P1 -t' % (build_dir, PYTHON, ','.join(glob_list),
- prog))
+ '--omit "%s" %s %s -P1' % (build_dir, PYTHON, ','.join(glob_list),
+ prog, test_cmd))
os.system(cmd)
stdout = command.Output('%s-coverage' % PYTHON, 'report')
lines = stdout.splitlines()
@@ -57,6 +58,7 @@
test_set = set([os.path.splitext(os.path.basename(line.split()[0]))[0]
for line in lines if '/etype/' in line])
missing_list = required
+ missing_list.discard('__init__')
missing_list.difference_update(test_set)
if missing_list:
print('Missing tests for %s' % (', '.join(missing_list)))
diff --git a/tools/patman/tools.py b/tools/patman/tools.py
index 8e9f22a..e945b54 100644
--- a/tools/patman/tools.py
+++ b/tools/patman/tools.py
@@ -3,6 +3,8 @@
# Copyright (c) 2016 Google, Inc
#
+from __future__ import print_function
+
import command
import glob
import os
@@ -24,6 +26,8 @@
# Search paths to use for Filename(), used to find files
search_paths = []
+tool_search_paths = []
+
# Tools and the packages that contain them, on debian
packages = {
'lz4': 'liblz4-tool',
@@ -154,26 +158,56 @@
def NotPowerOfTwo(num):
return num and (num & (num - 1))
+def SetToolPaths(toolpaths):
+ """Set the path to search for tools
+
+ Args:
+ toolpaths: List of paths to search for tools executed by Run()
+ """
+ global tool_search_paths
+
+ tool_search_paths = toolpaths
+
-def PathHasFile(fname):
+def PathHasFile(path_spec, fname):
"""Check if a given filename is in the PATH
Args:
+ path_spec: Value of PATH variable to check
fname: Filename to check
Returns:
True if found, False if not
"""
- for dir in os.environ['PATH'].split(':'):
+ for dir in path_spec.split(':'):
if os.path.exists(os.path.join(dir, fname)):
return True
return False
def Run(name, *args, **kwargs):
+ """Run a tool with some arguments
+
+ This runs a 'tool', which is a program used by binman to process files and
+ perhaps produce some output. Tools can be located on the PATH or in a
+ search path.
+
+ Args:
+ name: Command name to run
+ args: Arguments to the tool
+ kwargs: Options to pass to command.run()
+
+ Returns:
+ CommandResult object
+ """
try:
- return command.Run(name, *args, cwd=outdir, capture=True, **kwargs)
+ env = None
+ if tool_search_paths:
+ env = dict(os.environ)
+ env['PATH'] = ':'.join(tool_search_paths) + ':' + env['PATH']
+ return command.Run(name, *args, capture=True,
+ capture_stderr=True, env=env, **kwargs)
except:
- if not PathHasFile(name):
- msg = "Plesae install tool '%s'" % name
+ if env and not PathHasFile(env['PATH'], name):
+ msg = "Please install tool '%s'" % name
package = packages.get(name)
if package:
msg += " (e.g. from package '%s')" % package
@@ -342,3 +376,100 @@
if sys.version_info[0] >= 3:
return string.encode('utf-8')
return string
+
+def Compress(indata, algo):
+ """Compress some data using a given algorithm
+
+ Note that for lzma this uses an old version of the algorithm, not that
+ provided by xz.
+
+ This requires 'lz4' and 'lzma_alone' tools. It also requires an output
+ directory to be previously set up, by calling PrepareOutputDir().
+
+ Args:
+ indata: Input data to compress
+ algo: Algorithm to use ('none', 'gzip', 'lz4' or 'lzma')
+
+ Returns:
+ Compressed data
+ """
+ if algo == 'none':
+ return indata
+ fname = GetOutputFilename('%s.comp.tmp' % algo)
+ WriteFile(fname, indata)
+ if algo == 'lz4':
+ data = Run('lz4', '--no-frame-crc', '-c', fname, binary=True)
+ # cbfstool uses a very old version of lzma
+ elif algo == 'lzma':
+ outfname = GetOutputFilename('%s.comp.otmp' % algo)
+ Run('lzma_alone', 'e', fname, outfname, '-lc1', '-lp0', '-pb0', '-d8')
+ data = ReadFile(outfname)
+ elif algo == 'gzip':
+ data = Run('gzip', '-c', fname, binary=True)
+ else:
+ raise ValueError("Unknown algorithm '%s'" % algo)
+ return data
+
+def Decompress(indata, algo):
+ """Decompress some data using a given algorithm
+
+ Note that for lzma this uses an old version of the algorithm, not that
+ provided by xz.
+
+ This requires 'lz4' and 'lzma_alone' tools. It also requires an output
+ directory to be previously set up, by calling PrepareOutputDir().
+
+ Args:
+ indata: Input data to decompress
+ algo: Algorithm to use ('none', 'gzip', 'lz4' or 'lzma')
+
+ Returns:
+ Compressed data
+ """
+ if algo == 'none':
+ return indata
+ fname = GetOutputFilename('%s.decomp.tmp' % algo)
+ with open(fname, 'wb') as fd:
+ fd.write(indata)
+ if algo == 'lz4':
+ data = Run('lz4', '-dc', fname, binary=True)
+ elif algo == 'lzma':
+ outfname = GetOutputFilename('%s.decomp.otmp' % algo)
+ Run('lzma_alone', 'd', fname, outfname)
+ data = ReadFile(outfname)
+ elif algo == 'gzip':
+ data = Run('gzip', '-cd', fname, binary=True)
+ else:
+ raise ValueError("Unknown algorithm '%s'" % algo)
+ return data
+
+CMD_CREATE, CMD_DELETE, CMD_ADD, CMD_REPLACE, CMD_EXTRACT = range(5)
+
+IFWITOOL_CMDS = {
+ CMD_CREATE: 'create',
+ CMD_DELETE: 'delete',
+ CMD_ADD: 'add',
+ CMD_REPLACE: 'replace',
+ CMD_EXTRACT: 'extract',
+ }
+
+def RunIfwiTool(ifwi_file, cmd, fname=None, subpart=None, entry_name=None):
+ """Run ifwitool with the given arguments:
+
+ Args:
+ ifwi_file: IFWI file to operation on
+ cmd: Command to execute (CMD_...)
+ fname: Filename of file to add/replace/extract/create (None for
+ CMD_DELETE)
+ subpart: Name of sub-partition to operation on (None for CMD_CREATE)
+ entry_name: Name of directory entry to operate on, or None if none
+ """
+ args = ['ifwitool', ifwi_file]
+ args.append(IFWITOOL_CMDS[cmd])
+ if fname:
+ args += ['-f', fname]
+ if subpart:
+ args += ['-n', subpart]
+ if entry_name:
+ args += ['-d', '-e', entry_name]
+ Run(*args)
diff --git a/tools/patman/tout.py b/tools/patman/tout.py
index 4957c7a..15acce2 100644
--- a/tools/patman/tout.py
+++ b/tools/patman/tout.py
@@ -131,13 +131,21 @@
"""
_Output(3, msg)
+def Detail(msg):
+ """Display a detailed message
+
+ Args:
+ msg; Message to display.
+ """
+ _Output(4, msg)
+
def Debug(msg):
"""Display a debug message
Args:
msg; Message to display.
"""
- _Output(4, msg)
+ _Output(5, msg)
def UserOutput(msg):
"""Display a message regardless of the current output level.