summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml8
-rw-r--r--MAINTAINERS7
-rw-r--r--Makefile35
-rw-r--r--README19
-rw-r--r--arch/Kconfig5
-rw-r--r--arch/arm/Kconfig30
-rw-r--r--arch/arm/cpu/armv8/linux-kernel-image-header-vars.h86
-rw-r--r--arch/arm/cpu/armv8/start.S4
-rw-r--r--arch/arm/cpu/armv8/u-boot.lds4
-rw-r--r--arch/arm/dts/Makefile3
-rw-r--r--arch/arm/dts/dragonboard410c.dts22
-rw-r--r--arch/arm/dts/dragonboard820c-uboot.dtsi19
-rw-r--r--arch/arm/dts/dragonboard820c.dts108
-rw-r--r--arch/arm/dts/tegra-u-boot.dtsi15
-rw-r--r--arch/arm/include/asm/boot0-linux-kernel-header.h49
-rw-r--r--arch/arm/lib/bootm.c15
-rw-r--r--arch/arm/lib/crt0_64.S3
-rw-r--r--arch/arm/mach-snapdragon/Kconfig10
-rw-r--r--arch/arm/mach-snapdragon/Makefile7
-rw-r--r--arch/arm/mach-snapdragon/clock-apq8016.c181
-rw-r--r--arch/arm/mach-snapdragon/clock-apq8096.c62
-rw-r--r--arch/arm/mach-snapdragon/clock-snapdragon.c134
-rw-r--r--arch/arm/mach-snapdragon/clock-snapdragon.h40
-rw-r--r--arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h29
-rw-r--r--arch/arm/mach-snapdragon/include/mach/sysmap-apq8096.h29
-rw-r--r--arch/arm/mach-snapdragon/sysmap-apq8096.c32
-rw-r--r--arch/arm/mach-tegra/Kconfig6
-rw-r--r--arch/arm/mach-tegra/arm64-mmu.c3
-rw-r--r--arch/arm/mach-tegra/tegra186/Kconfig3
-rw-r--r--arch/arm/mach-tegra/tegra186/nvtboot_board.c265
-rw-r--r--arch/arm/mach-tegra/tegra186/nvtboot_mem.c144
-rw-r--r--arch/arm/mach-tegra/tegra210/Kconfig3
-rw-r--r--arch/riscv/Kconfig42
-rw-r--r--arch/riscv/Makefile11
-rw-r--r--arch/riscv/config.mk33
-rw-r--r--arch/riscv/cpu/nx25/Makefile10
-rw-r--r--arch/riscv/cpu/nx25/cpu.c33
-rw-r--r--arch/riscv/cpu/nx25/start.S291
-rw-r--r--arch/riscv/cpu/nx25/u-boot.lds69
-rw-r--r--arch/riscv/dts/Makefile14
-rw-r--r--arch/riscv/dts/ae250.dts96
-rw-r--r--arch/riscv/include/asm/bitops.h172
-rw-r--r--arch/riscv/include/asm/bootm.h65
-rw-r--r--arch/riscv/include/asm/byteorder.h35
-rw-r--r--arch/riscv/include/asm/cache.h22
-rw-r--r--arch/riscv/include/asm/config.h13
-rw-r--r--arch/riscv/include/asm/encoding.h188
-rw-r--r--arch/riscv/include/asm/global_data.h22
-rw-r--r--arch/riscv/include/asm/io.h494
-rw-r--r--arch/riscv/include/asm/linkage.h12
-rw-r--r--arch/riscv/include/asm/mach-types.h30
-rw-r--r--arch/riscv/include/asm/posix_types.h89
-rw-r--r--arch/riscv/include/asm/processor.h26
-rw-r--r--arch/riscv/include/asm/ptrace.h106
-rw-r--r--arch/riscv/include/asm/sections.h11
-rw-r--r--arch/riscv/include/asm/setup.h191
-rw-r--r--arch/riscv/include/asm/string.h43
-rw-r--r--arch/riscv/include/asm/system.h18
-rw-r--r--arch/riscv/include/asm/types.h64
-rw-r--r--arch/riscv/include/asm/u-boot-riscv.h21
-rw-r--r--arch/riscv/include/asm/u-boot.h46
-rw-r--r--arch/riscv/include/asm/unaligned.h1
-rw-r--r--arch/riscv/lib/Makefile14
-rw-r--r--arch/riscv/lib/boot.c19
-rw-r--r--arch/riscv/lib/bootm.c248
-rw-r--r--arch/riscv/lib/cache.c50
-rw-r--r--arch/riscv/lib/interrupts.c76
-rw-r--r--arch/sandbox/dts/test.dts7
-rw-r--r--board/AndesTech/nx25-ae250/Kconfig24
-rw-r--r--board/AndesTech/nx25-ae250/MAINTAINERS6
-rw-r--r--board/AndesTech/nx25-ae250/Makefile8
-rw-r--r--board/AndesTech/nx25-ae250/nx25-ae250.c77
-rw-r--r--board/qualcomm/dragonboard410c/Makefile1
-rw-r--r--board/qualcomm/dragonboard410c/dragonboard410c.c66
-rw-r--r--board/qualcomm/dragonboard410c/lowlevel_init.S28
-rw-r--r--board/qualcomm/dragonboard820c/Kconfig15
-rw-r--r--board/qualcomm/dragonboard820c/MAINTAINERS6
-rw-r--r--board/qualcomm/dragonboard820c/Makefile8
-rw-r--r--board/qualcomm/dragonboard820c/dragonboard820c.c163
-rw-r--r--board/qualcomm/dragonboard820c/head.S34
-rw-r--r--board/qualcomm/dragonboard820c/readme.txt459
-rw-r--r--board/qualcomm/dragonboard820c/u-boot.lds106
-rw-r--r--cmd/bdinfo.c15
-rw-r--r--cmd/mmc.c21
-rw-r--r--cmd/mvebu/bubt.c2
-rw-r--r--common/Makefile2
-rw-r--r--common/board_f.c2
-rw-r--r--common/board_r.c4
-rw-r--r--common/spl/Kconfig9
-rw-r--r--configs/am335x_hs_evm_defconfig4
-rw-r--r--configs/dragonboard410c_defconfig6
-rw-r--r--configs/dragonboard820c_defconfig43
-rw-r--r--configs/nx25-ae250_defconfig36
-rw-r--r--configs/omapl138_lcdk_defconfig1
-rw-r--r--configs/openrd_base_defconfig1
-rw-r--r--configs/openrd_client_defconfig1
-rw-r--r--configs/openrd_ultimate_defconfig1
-rw-r--r--doc/README.NX2546
-rw-r--r--doc/README.ae250137
-rw-r--r--doc/README.standalone1
-rw-r--r--drivers/core/root.c11
-rw-r--r--drivers/gpio/pm8916_gpio.c7
-rw-r--r--drivers/mmc/Kconfig76
-rw-r--r--drivers/mmc/Makefile4
-rw-r--r--drivers/mmc/exynos_dw_mmc.c3
-rw-r--r--drivers/mmc/fsl_esdhc.c11
-rw-r--r--drivers/mmc/gen_atmel_mci.c42
-rw-r--r--drivers/mmc/meson_gx_mmc.c2
-rw-r--r--drivers/mmc/mmc-uclass.c99
-rw-r--r--drivers/mmc/mmc.c1614
-rw-r--r--drivers/mmc/mmc_private.h4
-rw-r--r--drivers/mmc/omap_hsmmc.c4
-rw-r--r--drivers/mmc/sandbox_mmc.c5
-rw-r--r--drivers/mmc/sdhci.c7
-rw-r--r--drivers/power/power_core.c61
-rw-r--r--drivers/spmi/spmi-msm.c12
-rw-r--r--drivers/sysreset/Makefile2
-rw-r--r--drivers/sysreset/sysreset_snapdragon.c40
-rw-r--r--env/Kconfig39
-rw-r--r--env/env.c2
-rw-r--r--env/ext4.c30
-rw-r--r--examples/standalone/riscv.lds41
-rw-r--r--examples/standalone/stubs.c12
-rw-r--r--include/configs/dragonboard410c.h4
-rw-r--r--include/configs/dragonboard820c.h74
-rw-r--r--include/configs/nx25-ae250.h126
-rw-r--r--include/configs/p2771-0000.h23
-rw-r--r--include/configs/poplar.h2
-rw-r--r--include/configs/tegra-common.h4
-rw-r--r--include/configs/tegra186-common.h10
-rw-r--r--include/configs/tegra210-common.h10
-rw-r--r--include/elf.h5
-rw-r--r--include/fdtdec.h3
-rw-r--r--include/image.h1
-rw-r--r--include/mmc.h212
-rw-r--r--lib/fdtdec.c35
-rw-r--r--test/dm/bus.c2
-rw-r--r--test/dm/test-fdt.c2
-rw-r--r--tools/Makefile1
-rw-r--r--tools/prelink-riscv.c102
-rw-r--r--tools/prelink-riscv.inc112
141 files changed, 7469 insertions, 782 deletions
diff --git a/.travis.yml b/.travis.yml
index 8a220ccc42..a53e7c6f7b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -78,6 +78,11 @@ before_script:
tar -C /tmp -xf gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu.tar.xz &&
tar -C /tmp -xf gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz;
fi
+ - if [[ "${TOOLCHAIN}" == "riscv" ]]; then
+ wget https://github.com/PkmX/riscv-prebuilt-toolchains/releases/download/20180111/riscv32-unknown-elf-toolchain.tar.gz &&
+ tar -C /tmp -xf riscv32-unknown-elf-toolchain.tar.gz &&
+ echo -e "\n[toolchain-prefix]\nriscv = /tmp/riscv32-unknown-elf/bin/riscv32-unknown-elf-" >> ~/.buildman;
+ fi
- if [[ "${QEMU_TARGET}" != "" ]]; then
git clone git://git.qemu.org/qemu.git /tmp/qemu;
pushd /tmp/qemu;
@@ -251,6 +256,9 @@ matrix:
- env:
- BUILDMAN="xtensa"
TOOLCHAIN="xtensa"
+ - env:
+ - BUILDMAN="riscv"
+ TOOLCHAIN="riscv"
# QA jobs for code analytics
# static code analysis with cppcheck (we can add --enable=all later)
diff --git a/MAINTAINERS b/MAINTAINERS
index 9b4b63b063..754db5553d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -423,6 +423,13 @@ S: Orphaned (Since 2017-01)
T: git git://git.denx.de/u-boot-onenand.git
F: drivers/mtd/onenand/
+RISC-V
+M: Rick Chen <rick@andestech.com>
+S: Maintained
+T: git git://git.denx.de/u-boot-riscv.git
+F: arch/riscv/
+F: tools/prelink-riscv.c
+
SANDBOX
M: Simon Glass <sjg@chromium.org>
S: Maintained
diff --git a/Makefile b/Makefile
index d8f419bcd9..4981a2ed6f 100644
--- a/Makefile
+++ b/Makefile
@@ -811,6 +811,10 @@ ifneq ($(CONFIG_BUILD_TARGET),)
ALL-y += $(CONFIG_BUILD_TARGET:"%"=%)
endif
+ifneq ($(CONFIG_SYS_INIT_SP_BSS_OFFSET),)
+ALL-y += init_sp_bss_offset_check
+endif
+
LDFLAGS_u-boot += $(LDFLAGS_FINAL)
# Avoid 'Not enough room for program headers' error on binutils 2.28 onwards.
@@ -939,6 +943,33 @@ binary_size_check: u-boot-nodtb.bin FORCE
fi \
fi
+ifneq ($(CONFIG_SYS_INIT_SP_BSS_OFFSET),)
+ifneq ($(CONFIG_SYS_MALLOC_F_LEN),)
+subtract_sys_malloc_f_len = space=$$(($${space} - $(CONFIG_SYS_MALLOC_F_LEN)))
+else
+subtract_sys_malloc_f_len = true
+endif
+# The 1/4 margin below is somewhat arbitrary. The likely initial SP usage is
+# so low that the DTB could probably use 90%+ of the available space, for
+# current values of CONFIG_SYS_INIT_SP_BSS_OFFSET at least. However, let's be
+# safe for now and tweak this later if space becomes tight.
+# A rejected alternative would be to check that some absolute minimum stack
+# space was available. However, since CONFIG_SYS_INIT_SP_BSS_OFFSET is
+# deliberately build-specific, to take account of build-to-build stack usage
+# differences due to different feature sets, there is no common absolute value
+# to check against.
+init_sp_bss_offset_check: u-boot.dtb FORCE
+ @dtb_size=$(shell wc -c u-boot.dtb | awk '{print $$1}') ; \
+ space=$(CONFIG_SYS_INIT_SP_BSS_OFFSET) ; \
+ $(subtract_sys_malloc_f_len) ; \
+ quarter_space=$$(($${space} / 4)) ; \
+ if [ $${dtb_size} -gt $${quarter_space} ]; then \
+ echo "u-boot.dtb is larger than 1 quarter of " >&2 ; \
+ echo "(CONFIG_SYS_INIT_SP_BSS_OFFSET - CONFIG_SYS_MALLOC_F_LEN)" >&2 ; \
+ exit 1 ; \
+ fi
+endif
+
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
@@ -1264,6 +1295,10 @@ ifeq ($(CONFIG_KALLSYMS),y)
$(call cmd,u-boot__) common/system_map.o
endif
+ifeq ($(CONFIG_RISCV),y)
+ @tools/prelink-riscv $@ 0
+endif
+
quiet_cmd_sym ?= SYM $@
cmd_sym ?= $(OBJDUMP) -t $< > $@
u-boot.sym: u-boot FORCE
diff --git a/README b/README
index 06f3ed057d..b53ea7dfe3 100644
--- a/README
+++ b/README
@@ -143,6 +143,7 @@ Directory Hierarchy:
/nios2 Files generic to Altera NIOS2 architecture
/openrisc Files generic to OpenRISC architecture
/powerpc Files generic to PowerPC architecture
+ /riscv Files generic to RISC-V architecture
/sandbox Files generic to HW-independent "sandbox"
/sh Files generic to SH architecture
/x86 Files generic to x86 architecture
@@ -3510,7 +3511,7 @@ Low Level (hardware related) configuration options:
globally (CONFIG_CMD_MEMORY).
- CONFIG_SKIP_LOWLEVEL_INIT
- [ARM, NDS32, MIPS only] If this variable is defined, then certain
+ [ARM, NDS32, MIPS, RISC-V only] If this variable is defined, then certain
low level initializations (like setting up the memory
controller) are omitted and/or U-Boot does not
relocate itself into RAM.
@@ -4964,6 +4965,22 @@ On NDS32, the following registers are used:
NOTE: DECLARE_GLOBAL_DATA_PTR must be used with file-global scope,
or current versions of GCC may "optimize" the code too much.
+On RISC-V, the following registers are used:
+
+ x0: hard-wired zero (zero)
+ x1: return address (ra)
+ x2: stack pointer (sp)
+ x3: global pointer (gp)
+ x4: thread pointer (tp)
+ x5: link register (t0)
+ x8: frame pointer (fp)
+ x10-x11: arguments/return values (a0-1)
+ x12-x17: arguments (a2-7)
+ x28-31: temporaries (t3-6)
+ pc: program counter (pc)
+
+ ==> U-Boot will use gp to hold a pointer to the global data
+
Memory Management:
------------------
diff --git a/arch/Kconfig b/arch/Kconfig
index 0b12ed986c..762230cd56 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -54,6 +54,10 @@ config PPC
select HAVE_PRIVATE_LIBGCC
select SUPPORT_OF_CONTROL
+config RISCV
+ bool "riscv architecture"
+ select SUPPORT_OF_CONTROL
+
config SANDBOX
bool "Sandbox"
select BOARD_LATE_INIT
@@ -194,3 +198,4 @@ source "arch/sandbox/Kconfig"
source "arch/sh/Kconfig"
source "arch/x86/Kconfig"
source "arch/xtensa/Kconfig"
+source "arch/riscv/Kconfig"
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index de323bf4b9..001ece3cf1 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -19,6 +19,36 @@ config POSITION_INDEPENDENT
from almost any address. This logic relies on the relocation
information that is embedded into the binary to support U-Boot
relocating itself to the top-of-RAM later during execution.
+
+config SYS_INIT_SP_BSS_OFFSET
+ int
+ help
+ U-Boot typically uses a hard-coded value for the stack pointer
+ before relocation. Define this option to instead calculate the
+ initial SP at run-time. This is useful to avoid hard-coding addresses
+ into U-Boot, so that can be loaded and executed at arbitrary
+ addresses and thus avoid using arbitrary addresses at runtime. This
+ option's value is the offset added to &_bss_start in order to
+ calculate the stack pointer. This offset should be large enough so
+ that the early malloc region, global data (gd), and early stack usage
+ do not overlap any appended DTB.
+
+config LINUX_KERNEL_IMAGE_HEADER
+ bool
+ help
+ Place a Linux kernel image header at the start of the U-Boot binary.
+ The format of the header is described in the Linux kernel source at
+ Documentation/arm64/booting.txt. This feature is useful since the
+ image header reports the amount of memory (BSS and similar) that
+ U-Boot needs to use, but which isn't part of the binary.
+
+if LINUX_KERNEL_IMAGE_HEADER
+config LNX_KRNL_IMG_TEXT_OFFSET_BASE
+ hex
+ help
+ The value subtracted from CONFIG_SYS_TEXT_BASE to calculate the
+ TEXT_OFFSET value written in to the Linux kernel image header.
+endif
endif
config STATIC_RELA
diff --git a/arch/arm/cpu/armv8/linux-kernel-image-header-vars.h b/arch/arm/cpu/armv8/linux-kernel-image-header-vars.h
new file mode 100644
index 0000000000..3e720937f0
--- /dev/null
+++ b/arch/arm/cpu/armv8/linux-kernel-image-header-vars.h
@@ -0,0 +1,86 @@
+/*
+ * (C) Copyright 2017 NVIDIA Corporation <www.nvidia.com>
+ *
+ * Derived from Linux kernel v4.14 files:
+ *
+ * arch/arm64/include/asm/assembler.h:
+ * Based on arch/arm/include/asm/assembler.h, arch/arm/mm/proc-macros.S
+ * Copyright (C) 1996-2000 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * arch/arm64/kernel/head.S:
+ * Based on arch/arm/kernel/head.S
+ * Copyright (C) 1994-2002 Russell King
+ * Copyright (C) 2003-2012 ARM Ltd.
+ * Authors: Catalin Marinas <catalin.marinas@arm.com>
+ * Will Deacon <will.deacon@arm.com>
+ *
+ * arch/arm64/kernel/image.h:
+ * Copyright (C) 2014 ARM Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+/*
+ * There aren't any ELF relocations we can use to endian-swap values known only
+ * at link time (e.g. the subtraction of two symbol addresses), so we must get
+ * the linker to endian-swap certain values before emitting them.
+ *
+ * Note that, in order for this to work when building the ELF64 PIE executable
+ * (for KASLR), these values should not be referenced via R_AARCH64_ABS64
+ * relocations, since these are fixed up at runtime rather than at build time
+ * when PIE is in effect. So we need to split them up in 32-bit high and low
+ * words.
+ */
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define DATA_LE32(data) \
+ ((((data) & 0x000000ff) << 24) | \
+ (((data) & 0x0000ff00) << 8) | \
+ (((data) & 0x00ff0000) >> 8) | \
+ (((data) & 0xff000000) >> 24))
+#else
+#define DATA_LE32(data) ((data) & 0xffffffff)
+#endif
+
+#define DEFINE_IMAGE_LE64(sym, data) \
+ sym##_lo32 = DATA_LE32((data) & 0xffffffff); \
+ sym##_hi32 = DATA_LE32((data) >> 32)
+
+#define __MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define __CODE_DATA_SIZE (__bss_start - _start)
+#define __BSS_SIZE (__bss_end - __bss_start)
+#ifdef CONFIG_SYS_INIT_SP_BSS_OFFSET
+#define __MAX_EXTRA_RAM_USAGE __MAX(__BSS_SIZE, CONFIG_SYS_INIT_SP_BSS_OFFSET)
+#else
+#define __MAX_EXTRA_RAM_USAGE __BSS_SIZE
+#endif
+#define __MEM_USAGE (__CODE_DATA_SIZE + __MAX_EXTRA_RAM_USAGE)
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define __HEAD_FLAG_BE 1
+#else
+#define __HEAD_FLAG_BE 0
+#endif
+
+#define __HEAD_FLAG_PAGE_SIZE 1 /* 4K hard-coded */
+
+#define __HEAD_FLAG_PHYS_BASE 1
+
+#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \
+ (__HEAD_FLAG_PAGE_SIZE << 1) | \
+ (__HEAD_FLAG_PHYS_BASE << 3))
+
+#define TEXT_OFFSET (CONFIG_SYS_TEXT_BASE - \
+ CONFIG_LNX_KRNL_IMG_TEXT_OFFSET_BASE)
+
+/*
+ * These will output as part of the Image header, which should be little-endian
+ * regardless of the endianness of the kernel. While constant values could be
+ * endian swapped in head.S, all are done here for consistency.
+ */
+#define HEAD_SYMBOLS \
+ DEFINE_IMAGE_LE64(_kernel_size_le, __MEM_USAGE); \
+ DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET); \
+ DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);
+
+ HEAD_SYMBOLS
diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
index f385ed40e1..7a98a1c95d 100644
--- a/arch/arm/cpu/armv8/start.S
+++ b/arch/arm/cpu/armv8/start.S
@@ -19,7 +19,9 @@
.globl _start
_start:
-#ifdef CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK
+#if defined(LINUX_KERNEL_IMAGE_HEADER)
+#include <asm/boot0-linux-kernel-header.h>
+#elif defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK)
/*
* Various SoCs need something special and SoC-specific up front in
* order to boot, allow them to set that in their boot0.h file and then
diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds
index 22195b8834..7b76e0f9f0 100644
--- a/arch/arm/cpu/armv8/u-boot.lds
+++ b/arch/arm/cpu/armv8/u-boot.lds
@@ -159,4 +159,8 @@ SECTIONS
/DISCARD/ : { *(.plt*) }
/DISCARD/ : { *(.interp*) }
/DISCARD/ : { *(.gnu*) }
+
+#ifdef CONFIG_LINUX_KERNEL_IMAGE_HEADER
+#include "linux-kernel-image-header-vars.h"
+#endif
}
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 19100c95f4..e22b52cbb6 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -211,7 +211,8 @@ dtb-$(CONFIG_FSL_LSCH2) += fsl-ls1043a-qds-duart.dtb \
fsl-ls1012a-rdb.dtb \
fsl-ls1012a-frdm.dtb
-dtb-$(CONFIG_ARCH_SNAPDRAGON) += dragonboard410c.dtb
+dtb-$(CONFIG_TARGET_DRAGONBOARD410C) += dragonboard410c.dtb
+dtb-$(CONFIG_TARGET_DRAGONBOARD820C) += dragonboard820c.dtb
dtb-$(CONFIG_STM32F4) += stm32f429-disco.dtb \
stm32f469-disco.dtb
diff --git a/arch/arm/dts/dragonboard410c.dts b/arch/arm/dts/dragonboard410c.dts
index 7746622dda..5ccfe7f8c8 100644
--- a/arch/arm/dts/dragonboard410c.dts
+++ b/arch/arm/dts/dragonboard410c.dts
@@ -23,11 +23,16 @@
reg = <0 0x80000000 0 0x3da00000>;
};
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ };
+
chosen {
stdout-path = "/soc/serial@78b0000";
};
-
soc {
#address-cells = <0x1>;
#size-cells = <0x1>;
@@ -48,11 +53,6 @@
clock = <&clkc 4>;
};
- restart@4ab000 {
- compatible = "qcom,pshold";
- reg = <0x4ab000 0x4>;
- };
-
soc_gpios: pinctrl@1000000 {
compatible = "qcom,apq8016-pinctrl";
reg = <0x1000000 0x300000>;
@@ -86,6 +86,16 @@
clock-frequency = <200000000>;
};
+ wcnss {
+ bt {
+ compatible="qcom,wcnss-bt";
+ };
+
+ wifi {
+ compatible="qcom,wcnss-wlan";
+ };
+ };
+
spmi@200f000 {
compatible = "qcom,spmi-pmic-arb";
reg = <0x200f800 0x200 0x2400000 0x400000 0x2c00000 0x400000>;
diff --git a/arch/arm/dts/dragonboard820c-uboot.dtsi b/arch/arm/dts/dragonboard820c-uboot.dtsi
new file mode 100644
index 0000000000..167e72c0ae
--- /dev/null
+++ b/arch/arm/dts/dragonboard820c-uboot.dtsi
@@ -0,0 +1,19 @@
+/*
+ * U-Boot addition to handle Dragonboard 820c pins
+ *
+ * (C) Copyright 2017 Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+&pm8994_pon {
+ key_vol_down {
+ gpios = <&pm8994_pon 1 0>;
+ label = "key_vol_down";
+ };
+
+ key_power {
+ gpios = <&pm8994_pon 0 0>;
+ label = "key_power";
+ };
+};
diff --git a/arch/arm/dts/dragonboard820c.dts b/arch/arm/dts/dragonboard820c.dts
new file mode 100644
index 0000000000..64249449af
--- /dev/null
+++ b/arch/arm/dts/dragonboard820c.dts
@@ -0,0 +1,108 @@
+/*
+ * Qualcomm APQ8096 based Dragonboard 820C board device tree source
+ *
+ * (C) Copyright 2017 Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+
+#include "skeleton64.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. DB820c";
+ compatible = "arrow,apq8096-db820c", "qcom,apq8096-sbc";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ serial0 = &blsp2_uart1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x80000000 0 0xc0000000>;
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ soc: soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+ compatible = "simple-bus";
+
+ gcc: clock-controller@300000 {
+ compatible = "qcom,gcc-msm8996";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ reg = <0x300000 0x90000>;
+ };
+
+ blsp2_uart1: serial@75b0000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x75b0000 0x1000>;
+ };
+
+ sdhc2: sdhci@74a4900 {
+ compatible = "qcom,sdhci-msm-v4";
+ reg = <0x74a4900 0x314>, <0x74a4000 0x800>;
+ index = <0x0>;
+ bus-width = <4>;
+ clock = <&gcc 0>;
+ clock-frequency = <200000000>;
+ };
+
+ spmi@400f000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0x400f800 0x200>,
+ <0x4400000 0x400000>,
+ <0x4c00000 0x400000>;
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+
+ pmic0: pm8994@0 {
+ compatible = "qcom,spmi-pmic";
+ reg = <0x0 0x1>;
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+
+ pm8994_pon: pm8994_pon@800 {
+ compatible = "qcom,pm8994-pwrkey";
+ reg = <0x800 0x96>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-bank-name="pm8994_key.";
+ };
+
+ pm8994_gpios: pm8994_gpios@c000 {
+ compatible = "qcom,pm8994-gpio";
+ reg = <0xc000 0x400>;
+ gpio-controller;
+ gpio-count = <24>;
+ #gpio-cells = <2>;
+ gpio-bank-name="pm8994.";
+ };
+ };
+
+ pmic1: pm8994@1 {
+ compatible = "qcom,spmi-pmic";
+ reg = <0x1 0x1>;
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ };
+ };
+ };
+
+};
+
+#include "dragonboard820c-uboot.dtsi"
diff --git a/arch/arm/dts/tegra-u-boot.dtsi b/arch/arm/dts/tegra-u-boot.dtsi
index cde591c5fc..4f692ee975 100644
--- a/arch/arm/dts/tegra-u-boot.dtsi
+++ b/arch/arm/dts/tegra-u-boot.dtsi
@@ -1,5 +1,11 @@
#include <config.h>
+#ifdef CONFIG_SPL_TEXT_BASE
+#define U_BOOT_OFFSET (CONFIG_SYS_TEXT_BASE - CONFIG_SPL_TEXT_BASE)
+#else
+#define U_BOOT_OFFSET 0
+#endif
+
/ {
binman {
multiple-images;
@@ -9,8 +15,7 @@
u-boot-spl {
};
u-boot {
- pos = <(CONFIG_SYS_TEXT_BASE -
- CONFIG_SPL_TEXT_BASE)>;
+ pos = <(U_BOOT_OFFSET)>;
};
};
@@ -21,8 +26,7 @@
u-boot-spl {
};
u-boot {
- pos = <(CONFIG_SYS_TEXT_BASE -
- CONFIG_SPL_TEXT_BASE)>;
+ pos = <(U_BOOT_OFFSET)>;
};
};
@@ -32,8 +36,7 @@
u-boot-spl {
};
u-boot-nodtb {
- pos = <(CONFIG_SYS_TEXT_BASE -
- CONFIG_SPL_TEXT_BASE)>;
+ pos = <(U_BOOT_OFFSET)>;
};
};
};
diff --git a/arch/arm/include/asm/boot0-linux-kernel-header.h b/arch/arm/include/asm/boot0-linux-kernel-header.h
new file mode 100644
index 0000000000..ca28780daa
--- /dev/null
+++ b/arch/arm/include/asm/boot0-linux-kernel-header.h
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2017 NVIDIA Corporation <www.nvidia.com>
+ *
+ * Derived from Linux kernel v4.14 files:
+ *
+ * arch/arm64/include/asm/assembler.h:
+ * Based on arch/arm/include/asm/assembler.h, arch/arm/mm/proc-macros.S
+ * Copyright (C) 1996-2000 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * arch/arm64/kernel/head.S:
+ * Based on arch/arm/kernel/head.S
+ * Copyright (C) 1994-2002 Russell King
+ * Copyright (C) 2003-2012 ARM Ltd.
+ * Authors: Catalin Marinas <catalin.marinas@arm.com>
+ * Will Deacon <will.deacon@arm.com>
+ *
+ * arch/arm64/kernel/image.h:
+ * Copyright (C) 2014 ARM Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+ /*
+ * Emit a 64-bit absolute little endian symbol reference in a way that
+ * ensures that it will be resolved at build time, even when building a
+ * PIE binary. This requires cooperation from the linker script, which
+ * must emit the lo32/hi32 halves individually.
+ */
+ .macro le64sym, sym
+ .long \sym\()_lo32
+ .long \sym\()_hi32
+ .endm
+
+.globl _start
+_start:
+ /*
+ * DO NOT MODIFY. Image header expected by Linux boot-loaders.
+ */
+ b reset /* branch to kernel start, magic */
+ .long 0 /* reserved */
+ le64sym _kernel_offset_le /* Image load offset from start of RAM, little-endian */
+ le64sym _kernel_size_le /* Effective size of kernel image, little-endian */
+ le64sym _kernel_flags_le /* Informative flags, little-endian */
+ .quad 0 /* reserved */
+ .quad 0 /* reserved */
+ .quad 0 /* reserved */
+ .ascii "ARM\x64" /* Magic number */
+ .long 0 /* reserved */
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 5c62d9c144..89740657e0 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -47,7 +47,8 @@ static ulong get_sp(void)
void arch_lmb_reserve(struct lmb *lmb)
{
- ulong sp;
+ ulong sp, bank_end;
+ int bank;
/*
* Booting a (Linux) kernel image
@@ -63,8 +64,16 @@ void arch_lmb_reserve(struct lmb *lmb)
/* adjust sp by 4K to be safe */
sp -= 4096;
- lmb_reserve(lmb, sp,
- gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp);
+ for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+ if (sp < gd->bd->bi_dram[bank].start)
+ continue;
+ bank_end = gd->bd->bi_dram[bank].start +
+ gd->bd->bi_dram[bank].size;
+ if (sp >= bank_end)
+ continue;
+ lmb_reserve(lmb, sp, bank_end - sp);
+ break;
+ }
}
__weak void board_quiesce_devices(void)
diff --git a/arch/arm/lib/crt0_64.S b/arch/arm/lib/crt0_64.S
index 9cb70552fe..a181283e0f 100644
--- a/arch/arm/lib/crt0_64.S
+++ b/arch/arm/lib/crt0_64.S
@@ -73,6 +73,9 @@ ENTRY(_main)
ldr x0, =(CONFIG_TPL_STACK)
#elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr x0, =(CONFIG_SPL_STACK)
+#elif defined(CONFIG_SYS_INIT_SP_BSS_OFFSET)
+ adr x0, __bss_start
+ add x0, x0, #CONFIG_SYS_INIT_SP_BSS_OFFSET
#else
ldr x0, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig
index dc7ba21c18..d55dc1aaa1 100644
--- a/arch/arm/mach-snapdragon/Kconfig
+++ b/arch/arm/mach-snapdragon/Kconfig
@@ -19,8 +19,18 @@ config TARGET_DRAGONBOARD410C
- HDMI
- 20-pin low speed and 40-pin high speed expanders, 4 LED, 3 buttons
+config TARGET_DRAGONBOARD820C
+ bool "96Boards Dragonboard 820C"
+ help
+ Support for 96Boards Dragonboard 820C. This board complies with
+ 96Board Open Platform Specifications. Features:
+ - Qualcomm Snapdragon 820C SoC - APQ8096 (4xKyro CPU)
+ - 3GiB RAM
+ - 32GiB UFS drive
+
endchoice
source "board/qualcomm/dragonboard410c/Kconfig"
+source "board/qualcomm/dragonboard820c/Kconfig"
endif
diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile
index d82a04dda6..090c355b6b 100644
--- a/arch/arm/mach-snapdragon/Makefile
+++ b/arch/arm/mach-snapdragon/Makefile
@@ -4,5 +4,8 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-y += clock-apq8016.o
-obj-y += sysmap-apq8016.o
+obj-$(CONFIG_TARGET_DRAGONBOARD820C) += clock-apq8096.o
+obj-$(CONFIG_TARGET_DRAGONBOARD820C) += sysmap-apq8096.o
+obj-$(CONFIG_TARGET_DRAGONBOARD410C) += clock-apq8016.o
+obj-$(CONFIG_TARGET_DRAGONBOARD410C) += sysmap-apq8016.o
+obj-y += clock-snapdragon.o
diff --git a/arch/arm/mach-snapdragon/clock-apq8016.c b/arch/arm/mach-snapdragon/clock-apq8016.c
index da05015c32..a2424178c6 100644
--- a/arch/arm/mach-snapdragon/clock-apq8016.c
+++ b/arch/arm/mach-snapdragon/clock-apq8016.c
@@ -14,146 +14,12 @@
#include <errno.h>
#include <asm/io.h>
#include <linux/bitops.h>
+#include "clock-snapdragon.h"
/* GPLL0 clock control registers */
-#define GPLL0_STATUS 0x2101C
#define GPLL0_STATUS_ACTIVE BIT(17)
-
-#define APCS_GPLL_ENA_VOTE 0x45000
#define APCS_GPLL_ENA_VOTE_GPLL0 BIT(0)
-/* vote reg for blsp1 clock */
-#define APCS_CLOCK_BRANCH_ENA_VOTE 0x45004
-#define APCS_CLOCK_BRANCH_ENA_VOTE_BLSP1 BIT(10)
-
-/* SDC(n) clock control registers; n=1,2 */
-
-/* block control register */
-#define SDCC_BCR(n) ((n * 0x1000) + 0x41000)
-/* cmd */
-#define SDCC_CMD_RCGR(n) ((n * 0x1000) + 0x41004)
-/* cfg */
-#define SDCC_CFG_RCGR(n) ((n * 0x1000) + 0x41008)
-/* m */
-#define SDCC_M(n) ((n * 0x1000) + 0x4100C)
-/* n */
-#define SDCC_N(n) ((n * 0x1000) + 0x41010)
-/* d */
-#define SDCC_D(n) ((n * 0x1000) + 0x41014)
-/* branch control */
-#define SDCC_APPS_CBCR(n) ((n * 0x1000) + 0x41018)
-#define SDCC_AHB_CBCR(n) ((n * 0x1000) + 0x4101C)
-
-/* BLSP1 AHB clock (root clock for BLSP) */
-#define BLSP1_AHB_CBCR 0x1008
-
-/* Uart clock control registers */
-#define BLSP1_UART2_BCR 0x3028
-#define BLSP1_UART2_APPS_CBCR 0x302C
-#define BLSP1_UART2_APPS_CMD_RCGR 0x3034
-#define BLSP1_UART2_APPS_CFG_RCGR 0x3038
-#define BLSP1_UART2_APPS_M 0x303C
-#define BLSP1_UART2_APPS_N 0x3040
-#define BLSP1_UART2_APPS_D 0x3044
-
-/* CBCR register fields */
-#define CBCR_BRANCH_ENABLE_BIT BIT(0)
-#define CBCR_BRANCH_OFF_BIT BIT(31)
-
-struct msm_clk_priv {
- phys_addr_t base;
-};
-
-/* Enable clock controlled by CBC soft macro */
-static void clk_enable_cbc(phys_addr_t cbcr)
-{
- setbits_le32(cbcr, CBCR_BRANCH_ENABLE_BIT);
-
- while (readl(cbcr) & CBCR_BRANCH_OFF_BIT)
- ;
-}
-
-/* clock has 800MHz */
-static void clk_enable_gpll0(phys_addr_t base)
-{
- if (readl(base + GPLL0_STATUS) & GPLL0_STATUS_ACTIVE)
- return; /* clock already enabled */
-
- setbits_le32(base + APCS_GPLL_ENA_VOTE, APCS_GPLL_ENA_VOTE_GPLL0);
-
- while ((readl(base + GPLL0_STATUS) & GPLL0_STATUS_ACTIVE) == 0)
- ;
-}
-
-#define APPS_CMD_RGCR_UPDATE BIT(0)
-
-/* Update clock command via CMD_RGCR */
-static void clk_bcr_update(phys_addr_t apps_cmd_rgcr)
-{
- setbits_le32(apps_cmd_rgcr, APPS_CMD_RGCR_UPDATE);
-
- /* Wait for frequency to be updated. */
- while (readl(apps_cmd_rgcr) & APPS_CMD_RGCR_UPDATE)
- ;
-}
-
-struct bcr_regs {
- uintptr_t cfg_rcgr;
- uintptr_t cmd_rcgr;
- uintptr_t M;
- uintptr_t N;
- uintptr_t D;
-};
-
-/* RCGR_CFG register fields */
-#define CFG_MODE_DUAL_EDGE (0x2 << 12) /* Counter mode */
-
-/* sources */
-#define CFG_CLK_SRC_CXO (0 << 8)
-#define CFG_CLK_SRC_GPLL0 (1 << 8)
-#define CFG_CLK_SRC_MASK (7 << 8)
-
-/* Mask for supported fields */
-#define CFG_MASK 0x3FFF
-
-#define CFG_DIVIDER_MASK 0x1F
-
-/* root set rate for clocks with half integer and MND divider */
-static void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs,
- int div, int m, int n, int source)
-{
- uint32_t cfg;
- /* M value for MND divider. */
- uint32_t m_val = m;
- /* NOT(N-M) value for MND divider. */
- uint32_t n_val = ~((n)-(m)) * !!(n);
- /* NOT 2D value for MND divider. */
- uint32_t d_val = ~(n);
-
- /* Program MND values */
- writel(m_val, base + regs->M);
- writel(n_val, base + regs->N);
- writel(d_val, base + regs->D);
-
- /* setup src select and divider */
- cfg = readl(base + regs->cfg_rcgr);
- cfg &= ~CFG_MASK;
- cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */
-
- /* Set the divider; HW permits fraction dividers (+0.5), but
- for simplicity, we will support integers only */
- if (div)
- cfg |= (2 * div - 1) & CFG_DIVIDER_MASK;
-
- if (n_val)
- cfg |= CFG_MODE_DUAL_EDGE;
-
- writel(cfg, base + regs->cfg_rcgr); /* Write new clock configuration */
-
- /* Inform h/w to start using the new config. */
- clk_bcr_update(base + regs->cmd_rcgr);
-}
-
static const struct bcr_regs sdc_regs[] = {
{
.cfg_rcgr = SDCC_CFG_RCGR(1),
@@ -171,7 +37,14 @@ static const struct bcr_regs sdc_regs[] = {
}
};
-/* Init clock for SDHCI controller */
+static struct gpll0_ctrl gpll0_ctrl = {
+ .status = GPLL0_STATUS,
+ .status_bit = GPLL0_STATUS_ACTIVE,
+ .ena_vote = APCS_GPLL_ENA_VOTE,
+ .vote_bit = APCS_GPLL_ENA_VOTE_GPLL0,
+};
+
+/* SDHCI */
static int clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate)
{
int div = 8; /* 100MHz default */
@@ -183,7 +56,7 @@ static int clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate)
/* 800Mhz/div, gpll0 */
clk_rcg_set_rate_mnd(priv->base, &sdc_regs[slot], div, 0, 0,
CFG_CLK_SRC_GPLL0);
- clk_enable_gpll0(priv->base);
+ clk_enable_gpll0(priv->base, &gpll0_ctrl);
clk_enable_cbc(priv->base + SDCC_APPS_CBCR(slot));
return rate;
@@ -197,7 +70,7 @@ static const struct bcr_regs uart2_regs = {
.D = BLSP1_UART2_APPS_D,
};
-/* Init UART clock, 115200 */
+/* UART: 115200 */
static int clk_init_uart(struct msm_clk_priv *priv)
{
/* Enable iface clk */
@@ -205,7 +78,7 @@ static int clk_init_uart(struct msm_clk_priv *priv)
/* 7372800 uart block clock @ GPLL0 */
clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 144, 15625,
CFG_CLK_SRC_GPLL0);
- clk_enable_gpll0(priv->base);
+ clk_enable_gpll0(priv->base, &gpll0_ctrl);
/* Enable core clk */
clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR);
@@ -230,33 +103,3 @@ ulong msm_set_rate(struct clk *clk, ulong rate)
return 0;
}
}
-
-static int msm_clk_probe(struct udevice *dev)
-{
- struct msm_clk_priv *priv = dev_get_priv(dev);
-
- priv->base = devfdt_get_addr(dev);
- if (priv->base == FDT_ADDR_T_NONE)
- return -EINVAL;
-
- return 0;
-}
-
-static struct clk_ops msm_clk_ops = {
- .set_rate = msm_set_rate,
-};
-
-static const struct udevice_id msm_clk_ids[] = {
- { .compatible = "qcom,gcc-msm8916" },
- { .compatible = "qcom,gcc-apq8016" },
- { }
-};
-
-U_BOOT_DRIVER(clk_msm) = {
- .name = "clk_msm",
- .id = UCLASS_CLK,
- .of_match = msm_clk_ids,
- .ops = &msm_clk_ops,
- .priv_auto_alloc_size = sizeof(struct msm_clk_priv),
- .probe = msm_clk_probe,
-};
diff --git a/arch/arm/mach-snapdragon/clock-apq8096.c b/arch/arm/mach-snapdragon/clock-apq8096.c
new file mode 100644
index 0000000000..3d363d4d66
--- /dev/null
+++ b/arch/arm/mach-snapdragon/clock-apq8096.c
@@ -0,0 +1,62 @@
+/*
+ * Clock drivers for Qualcomm APQ8096
+ *
+ * (C) Copyright 2017 Jorge Ramirez Ortiz <jorge.ramirez-ortiz@linaro.org>
+ *
+ * Based on Little Kernel driver, simplified
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include "clock-snapdragon.h"
+
+/* GPLL0 clock control registers */
+#define GPLL0_STATUS_ACTIVE BIT(30)
+#define APCS_GPLL_ENA_VOTE_GPLL0 BIT(0)
+
+static const struct bcr_regs sdc_regs = {
+ .cfg_rcgr = SDCC2_CFG_RCGR,
+ .cmd_rcgr = SDCC2_CMD_RCGR,
+ .M = SDCC2_M,
+ .N = SDCC2_N,
+ .D = SDCC2_D,
+};
+
+static const struct gpll0_ctrl gpll0_ctrl = {
+ .status = GPLL0_STATUS,
+ .status_bit = GPLL0_STATUS_ACTIVE,
+ .ena_vote = APCS_GPLL_ENA_VOTE,
+ .vote_bit = APCS_GPLL_ENA_VOTE_GPLL0,
+};
+
+static int clk_init_sdc(struct msm_clk_priv *priv, uint rate)
+{
+ int div = 3;
+
+ clk_enable_cbc(priv->base + SDCC2_AHB_CBCR);
+ clk_rcg_set_rate_mnd(priv->base, &sdc_regs, div, 0, 0,
+ CFG_CLK_SRC_GPLL0);
+ clk_enable_gpll0(priv->base, &gpll0_ctrl);
+ clk_enable_cbc(priv->base + SDCC2_APPS_CBCR);
+
+ return rate;
+}
+
+ulong msm_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ switch (clk->id) {
+ case 0: /* SDC1 */
+ return clk_init_sdc(priv, rate);
+ break;
+ default:
+ return 0;
+ }
+}
diff --git a/arch/arm/mach-snapdragon/clock-snapdragon.c b/arch/arm/mach-snapdragon/clock-snapdragon.c
new file mode 100644
index 0000000000..899b5ba6ce
--- /dev/null
+++ b/arch/arm/mach-snapdragon/clock-snapdragon.c
@@ -0,0 +1,134 @@
+/*
+ * Clock drivers for Qualcomm APQ8016, APQ8096
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * Based on Little Kernel driver, simplified
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include "clock-snapdragon.h"
+
+/* CBCR register fields */
+#define CBCR_BRANCH_ENABLE_BIT BIT(0)
+#define CBCR_BRANCH_OFF_BIT BIT(31)
+
+extern ulong msm_set_rate(struct clk *clk, ulong rate);
+
+/* Enable clock controlled by CBC soft macro */
+void clk_enable_cbc(phys_addr_t cbcr)
+{
+ setbits_le32(cbcr, CBCR_BRANCH_ENABLE_BIT);
+
+ while (readl(cbcr) & CBCR_BRANCH_OFF_BIT)
+ ;
+}
+
+void clk_enable_gpll0(phys_addr_t base, const struct gpll0_ctrl *gpll0)
+{
+ if (readl(base + gpll0->status) & gpll0->status_bit)
+ return; /* clock already enabled */
+
+ setbits_le32(base + gpll0->ena_vote, gpll0->vote_bit);
+
+ while ((readl(base + gpll0->status) & gpll0->status_bit) == 0)
+ ;
+}
+
+#define APPS_CMD_RGCR_UPDATE BIT(0)
+
+/* Update clock command via CMD_RGCR */
+void clk_bcr_update(phys_addr_t apps_cmd_rgcr)
+{
+ setbits_le32(apps_cmd_rgcr, APPS_CMD_RGCR_UPDATE);
+
+ /* Wait for frequency to be updated. */
+ while (readl(apps_cmd_rgcr) & APPS_CMD_RGCR_UPDATE)
+ ;
+}
+
+#define CFG_MODE_DUAL_EDGE (0x2 << 12) /* Counter mode */
+
+#define CFG_MASK 0x3FFF
+
+#define CFG_DIVIDER_MASK 0x1F
+
+/* root set rate for clocks with half integer and MND divider */
+void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs,
+ int div, int m, int n, int source)
+{
+ u32 cfg;
+ /* M value for MND divider. */
+ u32 m_val = m;
+ /* NOT(N-M) value for MND divider. */
+ u32 n_val = ~((n) - (m)) * !!(n);
+ /* NOT 2D value for MND divider. */
+ u32 d_val = ~(n);
+
+ /* Program MND values */
+ writel(m_val, base + regs->M);
+ writel(n_val, base + regs->N);
+ writel(d_val, base + regs->D);
+
+ /* setup src select and divider */
+ cfg = readl(base + regs->cfg_rcgr);
+ cfg &= ~CFG_MASK;
+ cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */
+
+ /* Set the divider; HW permits fraction dividers (+0.5), but
+ for simplicity, we will support integers only */
+ if (div)
+ cfg |= (2 * div - 1) & CFG_DIVIDER_MASK;
+
+ if (n_val)
+ cfg |= CFG_MODE_DUAL_EDGE;
+
+ writel(cfg, base + regs->cfg_rcgr); /* Write new clock configuration */
+
+ /* Inform h/w to start using the new config. */
+ clk_bcr_update(base + regs->cmd_rcgr);
+}
+
+static int msm_clk_probe(struct udevice *dev)
+{
+ struct msm_clk_priv *priv = dev_get_priv(dev);
+
+ priv->base = devfdt_get_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static ulong msm_clk_set_rate(struct clk *clk, ulong rate)
+{
+ return msm_set_rate(clk, rate);
+}
+
+static struct clk_ops msm_clk_ops = {
+ .set_rate = msm_clk_set_rate,
+};
+
+static const struct udevice_id msm_clk_ids[] = {
+ { .compatible = "qcom,gcc-msm8916" },
+ { .compatible = "qcom,gcc-apq8016" },
+ { .compatible = "qcom,gcc-msm8996" },
+ { .compatible = "qcom,gcc-apq8096" },
+ { }
+};
+
+U_BOOT_DRIVER(clk_msm) = {
+ .name = "clk_msm",
+ .id = UCLASS_CLK,
+ .of_match = msm_clk_ids,
+ .ops = &msm_clk_ops,
+ .priv_auto_alloc_size = sizeof(struct msm_clk_priv),
+ .probe = msm_clk_probe,
+};
diff --git a/arch/arm/mach-snapdragon/clock-snapdragon.h b/arch/arm/mach-snapdragon/clock-snapdragon.h
new file mode 100644
index 0000000000..d7026aa867
--- /dev/null
+++ b/arch/arm/mach-snapdragon/clock-snapdragon.h
@@ -0,0 +1,40 @@
+/*
+ * Qualcomm APQ8016, APQ8096
+ *
+ * (C) Copyright 2017 Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#ifndef _CLOCK_SNAPDRAGON_H
+#define _CLOCK_SNAPDRAGON_H
+
+#define CFG_CLK_SRC_CXO (0 << 8)
+#define CFG_CLK_SRC_GPLL0 (1 << 8)
+#define CFG_CLK_SRC_MASK (7 << 8)
+
+struct gpll0_ctrl {
+ uintptr_t status;
+ int status_bit;
+ uintptr_t ena_vote;
+ int vote_bit;
+};
+
+struct bcr_regs {
+ uintptr_t cfg_rcgr;
+ uintptr_t cmd_rcgr;
+ uintptr_t M;
+ uintptr_t N;
+ uintptr_t D;
+};
+
+struct msm_clk_priv {
+ phys_addr_t base;
+};
+
+void clk_enable_gpll0(phys_addr_t base, const struct gpll0_ctrl *pll0);
+void clk_bcr_update(phys_addr_t apps_cmd_rgcr);
+void clk_enable_cbc(phys_addr_t cbcr);
+void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs,
+ int div, int m, int n, int source);
+
+#endif
diff --git a/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h
index cdbfad0def..1094b14a80 100644
--- a/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h
+++ b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h
@@ -8,7 +8,32 @@
#ifndef _MACH_SYSMAP_APQ8016_H
#define _MACH_SYSMAP_APQ8016_H
-#define GICD_BASE 0x0b000000
-#define GICC_BASE 0x0a20c000
+#define GICD_BASE (0x0b000000)
+#define GICC_BASE (0x0a20c000)
+
+/* Clocks: (from CLK_CTL_BASE) */
+#define GPLL0_STATUS (0x2101C)
+#define APCS_GPLL_ENA_VOTE (0x45000)
+
+#define SDCC_BCR(n) ((n * 0x1000) + 0x41000)
+#define SDCC_CMD_RCGR(n) ((n * 0x1000) + 0x41004)
+#define SDCC_CFG_RCGR(n) ((n * 0x1000) + 0x41008)
+#define SDCC_M(n) ((n * 0x1000) + 0x4100C)
+#define SDCC_N(n) ((n * 0x1000) + 0x41010)
+#define SDCC_D(n) ((n * 0x1000) + 0x41014)
+#define SDCC_APPS_CBCR(n) ((n * 0x1000) + 0x41018)
+#define SDCC_AHB_CBCR(n) ((n * 0x1000) + 0x4101C)
+
+/* BLSP1 AHB clock (root clock for BLSP) */
+#define BLSP1_AHB_CBCR 0x1008
+
+/* Uart clock control registers */
+#define BLSP1_UART2_BCR (0x3028)
+#define BLSP1_UART2_APPS_CBCR (0x302C)
+#define BLSP1_UART2_APPS_CMD_RCGR (0x3034)
+#define BLSP1_UART2_APPS_CFG_RCGR (0x3038)
+#define BLSP1_UART2_APPS_M (0x303C)
+#define BLSP1_UART2_APPS_N (0x3040)
+#define BLSP1_UART2_APPS_D (0x3044)
#endif
diff --git a/arch/arm/mach-snapdragon/include/mach/sysmap-apq8096.h b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8096.h
new file mode 100644
index 0000000000..fb89de258d
--- /dev/null
+++ b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8096.h
@@ -0,0 +1,29 @@
+/*
+ * Qualcomm APQ8096 sysmap
+ *
+ * (C) Copyright 2017 Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#ifndef _MACH_SYSMAP_APQ8096_H
+#define _MACH_SYSMAP_APQ8096_H
+
+#define TLMM_BASE_ADDR (0x1010000)
+
+/* Strength (sdc1) */
+#define SDC1_HDRV_PULL_CTL_REG (TLMM_BASE_ADDR + 0x0012D000)
+
+/* Clocks: (from CLK_CTL_BASE) */
+#define GPLL0_STATUS (0x0000)
+#define APCS_GPLL_ENA_VOTE (0x52000)
+
+#define SDCC2_BCR (0x14000) /* block reset */
+#define SDCC2_APPS_CBCR (0x14004) /* branch control */
+#define SDCC2_AHB_CBCR (0x14008)
+#define SDCC2_CMD_RCGR (0x14010)
+#define SDCC2_CFG_RCGR (0x14014)
+#define SDCC2_M (0x14018)
+#define SDCC2_N (0x1401C)
+#define SDCC2_D (0x14020)
+
+#endif
diff --git a/arch/arm/mach-snapdragon/sysmap-apq8096.c b/arch/arm/mach-snapdragon/sysmap-apq8096.c
new file mode 100644
index 0000000000..cb6d1e475b
--- /dev/null
+++ b/arch/arm/mach-snapdragon/sysmap-apq8096.c
@@ -0,0 +1,32 @@
+/*
+ * Qualcomm APQ8096 memory map
+ *
+ * (C) Copyright 2017 Jorge Ramirez Ortiz <jorge.ramirez-ortiz@linaro.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/armv8/mmu.h>
+
+static struct mm_region apq8096_mem_map[] = {
+ {
+ .virt = 0x0UL, /* Peripheral block */
+ .phys = 0x0UL, /* Peripheral block */
+ .size = 0x10000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ .virt = 0x80000000UL, /* DDR */
+ .phys = 0x80000000UL, /* DDR */
+ .size = 0xC0000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ /* List terminator */
+ 0,
+ }
+};
+
+struct mm_region *mem_map = apq8096_mem_map;
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 51d143687b..fd0082d22a 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -60,8 +60,14 @@ config TEGRA_ARMV7_COMMON
config TEGRA_ARMV8_COMMON
bool "Tegra 64-bit common options"
select ARM64
+ select LINUX_KERNEL_IMAGE_HEADER
select TEGRA_COMMON
+if TEGRA_ARMV8_COMMON
+config LNX_KRNL_IMG_TEXT_OFFSET_BASE
+ default 0x80000000
+endif
+
choice
prompt "Tegra SoC select"
optional
diff --git a/arch/arm/mach-tegra/arm64-mmu.c b/arch/arm/mach-tegra/arm64-mmu.c
index a79a5192e0..3a126bdec4 100644
--- a/arch/arm/mach-tegra/arm64-mmu.c
+++ b/arch/arm/mach-tegra/arm64-mmu.c
@@ -12,7 +12,8 @@
#include <asm/system.h>
#include <asm/armv8/mmu.h>
-static struct mm_region tegra_mem_map[] = {
+/* size: IO + NR_DRAM_BANKS + terminator */
+struct mm_region tegra_mem_map[1 + CONFIG_NR_DRAM_BANKS + 1] = {
{
.virt = 0x0UL,
.phys = 0x0UL,
diff --git a/arch/arm/mach-tegra/tegra186/Kconfig b/arch/arm/mach-tegra/tegra186/Kconfig
index b2e53b58ca..479c0955ee 100644
--- a/arch/arm/mach-tegra/tegra186/Kconfig
+++ b/arch/arm/mach-tegra/tegra186/Kconfig
@@ -21,6 +21,9 @@ endchoice
config SYS_SOC
default "tegra186"
+config SYS_INIT_SP_BSS_OFFSET
+ default 524288
+
source "board/nvidia/p2771-0000/Kconfig"
endif
diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_board.c b/arch/arm/mach-tegra/tegra186/nvtboot_board.c
index b94eb424aa..8ecb454443 100644
--- a/arch/arm/mach-tegra/tegra186/nvtboot_board.c
+++ b/arch/arm/mach-tegra/tegra186/nvtboot_board.c
@@ -1,16 +1,278 @@
/*
- * Copyright (c) 2016, NVIDIA CORPORATION.
+ * Copyright (c) 2016-2018, NVIDIA CORPORATION.
*
* SPDX-License-Identifier: GPL-2.0+
*/
+#include <stdlib.h>
#include <common.h>
#include <fdt_support.h>
#include <fdtdec.h>
#include <asm/arch/tegra.h>
+#include <asm/armv8/mmu.h>
+
+DECLARE_GLOBAL_DATA_PTR;
extern unsigned long nvtboot_boot_x0;
+/*
+ * The following few functions run late during the boot process and dynamically
+ * calculate the load address of various binaries. To keep track of multiple
+ * allocations, some writable list of RAM banks must be used. tegra_mem_map[]
+ * is used for this purpose to avoid making yet another copy of the list of RAM
+ * banks. This is safe because tegra_mem_map[] is only used once during very
+ * early boot to create U-Boot's page tables, long before this code runs. If
+ * this assumption becomes invalid later, we can just fix the code to copy the
+ * list of RAM banks into some private data structure before running.
+ */
+
+extern struct mm_region tegra_mem_map[];
+
+static char *gen_varname(const char *var, const char *ext)
+{
+ size_t len_var = strlen(var);
+ size_t len_ext = strlen(ext);
+ size_t len = len_var + len_ext + 1;
+ char *varext = malloc(len);
+
+ if (!varext)
+ return 0;
+ strcpy(varext, var);
+ strcpy(varext + len_var, ext);
+ return varext;
+}
+
+static void mark_ram_allocated(int bank, u64 allocated_start, u64 allocated_end)
+{
+ u64 bank_start = tegra_mem_map[bank].virt;
+ u64 bank_size = tegra_mem_map[bank].size;
+ u64 bank_end = bank_start + bank_size;
+ bool keep_front = allocated_start != bank_start;
+ bool keep_tail = allocated_end != bank_end;
+
+ if (keep_front && keep_tail) {
+ /*
+ * There are CONFIG_NR_DRAM_BANKS DRAM entries in the array,
+ * starting at index 1 (index 0 is MMIO). So, we are at DRAM
+ * entry "bank" not "bank - 1" as for a typical 0-base array.
+ * The number of remaining DRAM entries is therefore
+ * "CONFIG_NR_DRAM_BANKS - bank". We want to duplicate the
+ * current entry and shift up the remaining entries, dropping
+ * the last one. Thus, we must copy one fewer entry than the
+ * number remaining.
+ */
+ memmove(&tegra_mem_map[bank + 1], &tegra_mem_map[bank],
+ CONFIG_NR_DRAM_BANKS - bank - 1);
+ tegra_mem_map[bank].size = allocated_start - bank_start;
+ bank++;
+ tegra_mem_map[bank].virt = allocated_end;
+ tegra_mem_map[bank].phys = allocated_end;
+ tegra_mem_map[bank].size = bank_end - allocated_end;
+ } else if (keep_front) {
+ tegra_mem_map[bank].size = allocated_start - bank_start;
+ } else if (keep_tail) {
+ tegra_mem_map[bank].virt = allocated_end;
+ tegra_mem_map[bank].phys = allocated_end;
+ tegra_mem_map[bank].size = bank_end - allocated_end;
+ } else {
+ /*
+ * We could move all subsequent banks down in the array but
+ * that's not necessary for subsequent allocations to work, so
+ * we skip doing so.
+ */
+ tegra_mem_map[bank].size = 0;
+ }
+}
+
+static void reserve_ram(u64 start, u64 size)
+{
+ int bank;
+ u64 end = start + size;
+
+ for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
+ u64 bank_start = tegra_mem_map[bank].virt;
+ u64 bank_size = tegra_mem_map[bank].size;
+ u64 bank_end = bank_start + bank_size;
+
+ if (end <= bank_start || start > bank_end)
+ continue;
+ mark_ram_allocated(bank, start, end);
+ break;
+ }
+}
+
+static u64 alloc_ram(u64 size, u64 align, u64 offset)
+{
+ int bank;
+
+ for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
+ u64 bank_start = tegra_mem_map[bank].virt;
+ u64 bank_size = tegra_mem_map[bank].size;
+ u64 bank_end = bank_start + bank_size;
+ u64 allocated = ROUND(bank_start, align) + offset;
+ u64 allocated_end = allocated + size;
+
+ if (allocated_end > bank_end)
+ continue;
+ mark_ram_allocated(bank, allocated, allocated_end);
+ return allocated;
+ }
+ return 0;
+}
+
+static void set_calculated_aliases(char *aliases, u64 address)
+{
+ char *tmp, *alias;
+ int err;
+
+ aliases = strdup(aliases);
+ if (!aliases) {
+ pr_err("strdup(aliases) failed");
+ return;
+ }
+
+ tmp = aliases;
+ while (true) {
+ alias = strsep(&tmp, " ");
+ if (!alias)
+ break;
+ debug("%s: alias: %s\n", __func__, alias);
+ err = env_set_hex(alias, address);
+ if (err)
+ pr_err("Could not set %s\n", alias);
+ }
+
+ free(aliases);
+}
+
+static void set_calculated_env_var(const char *var)
+{
+ char *var_size;
+ char *var_align;
+ char *var_offset;
+ char *var_aliases;
+ u64 size;
+ u64 align;
+ u64 offset;
+ char *aliases;
+ u64 address;
+ int err;
+
+ var_size = gen_varname(var, "_size");
+ if (!var_size)
+ return;
+ var_align = gen_varname(var, "_align");
+ if (!var_align)
+ goto out_free_var_size;
+ var_offset = gen_varname(var, "_offset");
+ if (!var_offset)
+ goto out_free_var_align;
+ var_aliases = gen_varname(var, "_aliases");
+ if (!var_aliases)
+ goto out_free_var_offset;
+
+ size = env_get_hex(var_size, 0);
+ if (!size) {
+ pr_err("%s not set or zero\n", var_size);
+ goto out_free_var_aliases;
+ }
+ align = env_get_hex(var_align, 1);
+ /* Handle extant variables, but with a value of 0 */
+ if (!align)
+ align = 1;
+ offset = env_get_hex(var_offset, 0);
+ aliases = env_get(var_aliases);
+
+ debug("%s: Calc var %s; size=%llx, align=%llx, offset=%llx\n",
+ __func__, var, size, align, offset);
+ if (aliases)
+ debug("%s: Aliases: %s\n", __func__, aliases);
+
+ address = alloc_ram(size, align, offset);
+ if (!address) {
+ pr_err("Could not allocate %s\n", var);
+ goto out_free_var_aliases;
+ }
+ debug("%s: Address %llx\n", __func__, address);
+
+ err = env_set_hex(var, address);
+ if (err)
+ pr_err("Could not set %s\n", var);
+ if (aliases)
+ set_calculated_aliases(aliases, address);
+
+out_free_var_aliases:
+ free(var_aliases);
+out_free_var_offset:
+ free(var_offset);
+out_free_var_align:
+ free(var_align);
+out_free_var_size:
+ free(var_size);
+}
+
+#ifdef DEBUG
+static void dump_ram_banks(void)
+{
+ int bank;
+
+ for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
+ u64 bank_start = tegra_mem_map[bank].virt;
+ u64 bank_size = tegra_mem_map[bank].size;
+ u64 bank_end = bank_start + bank_size;
+
+ if (!bank_size)
+ continue;
+ printf("%d: %010llx..%010llx (+%010llx)\n", bank - 1,
+ bank_start, bank_end, bank_size);
+ }
+}
+#endif
+
+static void set_calculated_env_vars(void)
+{
+ char *vars, *tmp, *var;
+
+#ifdef DEBUG
+ printf("RAM banks before any calculated env. var.s:\n");
+ dump_ram_banks();
+#endif
+
+ reserve_ram(nvtboot_boot_x0, fdt_totalsize(nvtboot_boot_x0));
+
+#ifdef DEBUG
+ printf("RAM after reserving cboot DTB:\n");
+ dump_ram_banks();
+#endif
+
+ vars = env_get("calculated_vars");
+ if (!vars) {
+ debug("%s: No env var calculated_vars\n", __func__);
+ return;
+ }
+
+ vars = strdup(vars);
+ if (!vars) {
+ pr_err("strdup(calculated_vars) failed");
+ return;
+ }
+
+ tmp = vars;
+ while (true) {
+ var = strsep(&tmp, " ");
+ if (!var)
+ break;
+ debug("%s: var: %s\n", __func__, var);
+ set_calculated_env_var(var);
+#ifdef DEBUG
+ printf("RAM banks affter allocating %s:\n", var);
+ dump_ram_banks();
+#endif
+ }
+
+ free(vars);
+}
+
static int set_fdt_addr(void)
{
int ret;
@@ -60,6 +322,7 @@ static int set_ethaddr_from_nvtboot(void)
int tegra_soc_board_init_late(void)
{
+ set_calculated_env_vars();
/*
* Ignore errors here; the value may not be used depending on
* extlinux.conf or boot script content.
diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c
index 5224ef641c..2ca59747d4 100644
--- a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c
+++ b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, NVIDIA CORPORATION.
+ * Copyright (c) 2016-2018, NVIDIA CORPORATION.
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -8,28 +8,48 @@
#include <fdt_support.h>
#include <fdtdec.h>
#include <asm/arch/tegra.h>
+#include <asm/armv8/mmu.h>
+
+#define SZ_4G 0x100000000ULL
+
+/*
+ * Size of a region that's large enough to hold the relocated U-Boot and all
+ * other allocations made around it (stack, heap, page tables, etc.)
+ * In practice, running "bdinfo" at the shell prompt, the stack reaches about
+ * 5MB from the address selected for ram_top as of the time of writing,
+ * so a 16MB region should be plenty.
+ */
+#define MIN_USABLE_RAM_SIZE SZ_16M
+/*
+ * The amount of space we expect to require for stack usage. Used to validate
+ * that all reservations fit into the region selected for the relocation target
+ */
+#define MIN_USABLE_STACK_SIZE SZ_1M
DECLARE_GLOBAL_DATA_PTR;
extern unsigned long nvtboot_boot_x0;
+extern struct mm_region tegra_mem_map[];
/*
- * A parsed version of /memory/reg from the DTB that is passed to U-Boot in x0.
- *
- * We only support up to two banks since that's all the binary bootloader
- * ever sets. We assume bank 0 is RAM below 4G and bank 1 is RAM above 4G.
- * This is all a fairly safe assumption, since the L4T kernel makes the same
- * assumptions, so the bootloader is unlikely to change.
- *
- * This is written to before relocation, and hence cannot be in .bss, since
- * .bss overlaps the DTB that's appended to the U-Boot binary. The initializer
- * forces this into .data and avoids this issue. This also has the nice side-
- * effect of the content being valid after relocation.
+ * These variables are written to before relocation, and hence cannot be
+ * in.bss, since .bss overlaps the DTB that's appended to the U-Boot binary.
+ * The section attribute forces this into .data and avoids this issue. This
+ * also has the nice side-effect of the content being valid after relocation.
+ */
+
+/* The number of valid entries in ram_banks[] */
+static int ram_bank_count __attribute__((section(".data")));
+
+/*
+ * The usable top-of-RAM for U-Boot. This is both:
+ * a) Below 4GB to avoid issues with peripherals that use 32-bit addressing.
+ * b) At the end of a region that has enough space to hold the relocated U-Boot
+ * and all other allocations made around it (stack, heap, page tables, etc.)
*/
-static struct {
- u64 start;
- u64 size;
-} ram_banks[2] = {{1}};
+static u64 ram_top __attribute__((section(".data")));
+/* The base address of the region of RAM that ends at ram_top */
+static u64 region_base __attribute__((section(".data")));
int dram_init(void)
{
@@ -38,8 +58,6 @@ int dram_init(void)
int node, len, i;
const u32 *prop;
- memset(ram_banks, 0, sizeof(ram_banks));
-
na = fdtdec_get_uint(nvtboot_blob, 0, "#address-cells", 2);
ns = fdtdec_get_uint(nvtboot_blob, 0, "#size-cells", 2);
@@ -54,37 +72,103 @@ int dram_init(void)
hang();
}
- len /= (na + ns);
- if (len > ARRAY_SIZE(ram_banks))
- len = ARRAY_SIZE(ram_banks);
+ /* Calculate the true # of base/size pairs to read */
+ len /= 4; /* Convert bytes to number of cells */
+ len /= (na + ns); /* Convert cells to number of banks */
+ if (len > CONFIG_NR_DRAM_BANKS)
+ len = CONFIG_NR_DRAM_BANKS;
+ /* Parse the /memory node, and save useful entries */
gd->ram_size = 0;
+ ram_bank_count = 0;
for (i = 0; i < len; i++) {
- ram_banks[i].start = fdt_read_number(prop, na);
+ u64 bank_start, bank_end, bank_size, usable_bank_size;
+
+ /* Extract raw memory region data from DTB */
+ bank_start = fdt_read_number(prop, na);
prop += na;
- ram_banks[i].size = fdt_read_number(prop, ns);
+ bank_size = fdt_read_number(prop, ns);
prop += ns;
- gd->ram_size += ram_banks[i].size;
+ gd->ram_size += bank_size;
+ bank_end = bank_start + bank_size;
+ debug("Bank %d: %llx..%llx (+%llx)\n", i,
+ bank_start, bank_end, bank_size);
+
+ /*
+ * Align the bank to MMU section size. This is not strictly
+ * necessary, since the translation table construction code
+ * handles page granularity without issue. However, aligning
+ * the MMU entries reduces the size and number of levels in the
+ * page table, so is worth it.
+ */
+ bank_start = ROUND(bank_start, SZ_2M);
+ bank_end = bank_end & ~(SZ_2M - 1);
+ bank_size = bank_end - bank_start;
+ debug(" aligned: %llx..%llx (+%llx)\n",
+ bank_start, bank_end, bank_size);
+ if (bank_end <= bank_start)
+ continue;
+
+ /* Record data used to create MMU translation tables */
+ ram_bank_count++;
+ /* Index below is deliberately 1-based to skip MMIO entry */
+ tegra_mem_map[ram_bank_count].virt = bank_start;
+ tegra_mem_map[ram_bank_count].phys = bank_start;
+ tegra_mem_map[ram_bank_count].size = bank_size;
+ tegra_mem_map[ram_bank_count].attrs =
+ PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE;
+
+ /* Determine best bank to relocate U-Boot into */
+ if (bank_end > SZ_4G)
+ bank_end = SZ_4G;
+ debug(" end %llx (usable)\n", bank_end);
+ usable_bank_size = bank_end - bank_start;
+ debug(" size %llx (usable)\n", usable_bank_size);
+ if ((usable_bank_size >= MIN_USABLE_RAM_SIZE) &&
+ (bank_end > ram_top)) {
+ ram_top = bank_end;
+ region_base = bank_start;
+ debug("ram top now %llx\n", ram_top);
+ }
+ }
+
+ /* Ensure memory map contains the desired sentinel entry */
+ tegra_mem_map[ram_bank_count + 1].virt = 0;
+ tegra_mem_map[ram_bank_count + 1].phys = 0;
+ tegra_mem_map[ram_bank_count + 1].size = 0;
+ tegra_mem_map[ram_bank_count + 1].attrs = 0;
+
+ /* Error out if a relocation target couldn't be found */
+ if (!ram_top) {
+ pr_err("Can't find a usable RAM top");
+ hang();
}
return 0;
}
-extern unsigned long nvtboot_boot_x0;
-
int dram_init_banksize(void)
{
int i;
- for (i = 0; i < 2; i++) {
- gd->bd->bi_dram[i].start = ram_banks[i].start;
- gd->bd->bi_dram[i].size = ram_banks[i].size;
+ if ((gd->start_addr_sp - region_base) < MIN_USABLE_STACK_SIZE) {
+ pr_err("Reservations exceed chosen region size");
+ hang();
+ }
+
+ for (i = 0; i < ram_bank_count; i++) {
+ gd->bd->bi_dram[i].start = tegra_mem_map[1 + i].virt;
+ gd->bd->bi_dram[i].size = tegra_mem_map[1 + i].size;
}
+#ifdef CONFIG_PCI
+ gd->pci_ram_top = ram_top;
+#endif
+
return 0;
}
ulong board_get_usable_ram_top(ulong total_size)
{
- return ram_banks[0].start + ram_banks[0].size;
+ return ram_top;
}
diff --git a/arch/arm/mach-tegra/tegra210/Kconfig b/arch/arm/mach-tegra/tegra210/Kconfig
index 3637473051..250738aed3 100644
--- a/arch/arm/mach-tegra/tegra210/Kconfig
+++ b/arch/arm/mach-tegra/tegra210/Kconfig
@@ -40,6 +40,9 @@ endchoice
config SYS_SOC
default "tegra210"
+config SYS_INIT_SP_BSS_OFFSET
+ default 524288
+
source "board/nvidia/e2220-1170/Kconfig"
source "board/nvidia/p2371-0000/Kconfig"
source "board/nvidia/p2371-2180/Kconfig"
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
new file mode 100644
index 0000000000..c50be37c97
--- /dev/null
+++ b/arch/riscv/Kconfig
@@ -0,0 +1,42 @@
+menu "RISCV architecture"
+ depends on RISCV
+
+config SYS_ARCH
+ default "riscv"
+
+choice
+ prompt "Target select"
+ optional
+
+config TARGET_NX25_AE250
+ bool "Support nx25-ae250"
+
+endchoice
+
+source "board/AndesTech/nx25-ae250/Kconfig"
+
+choice
+ prompt "CPU selection"
+ default CPU_RISCV_32
+
+config CPU_RISCV_32
+ bool "RISCV 32 bit"
+ select 32BIT
+ help
+ Choose this option to build an U-Boot for RISCV32 architecture.
+
+config CPU_RISCV_64
+ bool "RISCV 64 bit"
+ select 64BIT
+ help
+ Choose this option to build an U-Boot for RISCV64 architecture.
+
+endchoice
+
+config 32BIT
+ bool
+
+config 64BIT
+ bool
+
+endmenu
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
new file mode 100644
index 0000000000..09d24db7a9
--- /dev/null
+++ b/arch/riscv/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright (C) 2017 Andes Technology Corporation.
+# Rick Chen, Andes Technology Corporation <rick@andestech.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+head-y := arch/riscv/cpu/$(CPU)/start.o
+
+libs-y += arch/riscv/cpu/$(CPU)/
+libs-y += arch/riscv/lib/
diff --git a/arch/riscv/config.mk b/arch/riscv/config.mk
new file mode 100644
index 0000000000..6b681c4286
--- /dev/null
+++ b/arch/riscv/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2000-2002
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# Copyright (c) 2017 Microsemi Corporation.
+# Padmarao Begari, Microsemi Corporation <padmarao.begari@microsemi.com>
+#
+# Copyright (C) 2017 Andes Technology Corporation
+# Rick Chen, Andes Technology Corporation <rick@andestech.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+
+ifeq ($(CROSS_COMPILE),)
+CROSS_COMPILE := riscv32-unknown-linux-gnu-
+endif
+
+32bit-emul := elf32lriscv
+64bit-emul := elf64lriscv
+
+ifdef CONFIG_32BIT
+PLATFORM_LDFLAGS += -m $(32bit-emul)
+endif
+
+ifdef CONFIG_64BIT
+PLATFORM_LDFLAGS += -m $(64bit-emul)
+endif
+
+CONFIG_STANDALONE_LOAD_ADDR = 0x00000000 \
+ -T $(srctree)/examples/standalone/riscv.lds
+
+PLATFORM_CPPFLAGS += -ffixed-gp -fpic
+PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -gdwarf-2
+LDFLAGS_u-boot += --gc-sections -static -pie
diff --git a/arch/riscv/cpu/nx25/Makefile b/arch/riscv/cpu/nx25/Makefile
new file mode 100644
index 0000000000..5fcf1007c2
--- /dev/null
+++ b/arch/riscv/cpu/nx25/Makefile
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2017 Andes Technology Corporation
+# Rick Chen, Andes Technology Corporation <rick@andestech.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+extra-y = start.o
+
+obj-y := cpu.o
diff --git a/arch/riscv/cpu/nx25/cpu.c b/arch/riscv/cpu/nx25/cpu.c
new file mode 100644
index 0000000000..5478f4f2de
--- /dev/null
+++ b/arch/riscv/cpu/nx25/cpu.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* CPU specific code */
+#include <common.h>
+#include <command.h>
+#include <watchdog.h>
+#include <asm/cache.h>
+
+/*
+ * cleanup_before_linux() is called just before we call linux
+ * it prepares the processor for linux
+ *
+ * we disable interrupt and caches.
+ */
+int cleanup_before_linux(void)
+{
+ disable_interrupts();
+
+ /* turn off I/D-cache */
+
+ return 0;
+}
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ disable_interrupts();
+ panic("nx25-ae250 wdt not support yet.\n");
+}
diff --git a/arch/riscv/cpu/nx25/start.S b/arch/riscv/cpu/nx25/start.S
new file mode 100644
index 0000000000..6a076639d3
--- /dev/null
+++ b/arch/riscv/cpu/nx25/start.S
@@ -0,0 +1,291 @@
+/*
+ * Startup Code for RISC-V Core
+ *
+ * Copyright (c) 2017 Microsemi Corporation.
+ * Copyright (c) 2017 Padmarao Begari <Padmarao.Begari@microsemi.com>
+ *
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <elf.h>
+#include <asm/encoding.h>
+
+#ifdef CONFIG_32BIT
+#define LREG lw
+#define SREG sw
+#define REGBYTES 4
+#define RELOC_TYPE R_RISCV_32
+#define SYM_INDEX 0x8
+#define SYM_SIZE 0x10
+#else
+#define LREG ld
+#define SREG sd
+#define REGBYTES 8
+#define RELOC_TYPE R_RISCV_64
+#define SYM_INDEX 0x20
+#define SYM_SIZE 0x18
+#endif
+
+.section .text
+.globl _start
+_start:
+ j handle_reset
+
+nmi_vector:
+ j nmi_vector
+
+trap_vector:
+ j trap_entry
+
+.global trap_entry
+handle_reset:
+ la t0, trap_entry
+ csrw mtvec, t0
+ csrwi mstatus, 0
+ csrwi mie, 0
+
+/*
+ * Do CPU critical regs init only at reboot,
+ * not when booting from ram
+ */
+#ifdef CONFIG_INIT_CRITICAL
+ jal cpu_init_crit /* Do CPU critical regs init */
+#endif
+
+/*
+ * Set stackpointer in internal/ex RAM to call board_init_f
+ */
+call_board_init_f:
+ li t0, -16
+ li t1, CONFIG_SYS_INIT_SP_ADDR
+ and sp, t1, t0 /* force 16 byte alignment */
+
+#ifdef CONFIG_DEBUG_UART
+ jal debug_uart_init
+#endif
+
+call_board_init_f_0:
+ mv a0, sp
+ jal board_init_f_alloc_reserve
+ mv sp, a0
+ jal board_init_f_init_reserve
+
+ mv a0, zero /* a0 <-- boot_flags = 0 */
+ la t5, board_init_f
+ jr t5 /* jump to board_init_f() */
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ */
+.globl relocate_code
+relocate_code:
+ mv s2, a0 /* save addr_sp */
+ mv s3, a1 /* save addr of gd */
+ mv s4, a2 /* save addr of destination */
+
+/*
+ *Set up the stack
+ */
+stack_setup:
+ mv sp, s2
+ la t0, _start
+ sub t6, s4, t0 /* t6 <- relocation offset */
+ beq t0, s4, clear_bss /* skip relocation */
+
+ mv t1, s4 /* t1 <- scratch for copy_loop */
+ la t3, __bss_start
+ sub t3, t3, t0 /* t3 <- __bss_start_ofs */
+ add t2, t0, t3 /* t2 <- source end address */
+
+copy_loop:
+ LREG t5, 0(t0)
+ addi t0, t0, REGBYTES
+ SREG t5, 0(t1)
+ addi t1, t1, REGBYTES
+ blt t0, t2, copy_loop
+
+/*
+ * Update dynamic relocations after board_init_f
+ */
+fix_rela_dyn:
+ la t1, __rel_dyn_start
+ la t2, __rel_dyn_end
+ beq t1, t2, clear_bss
+ add t1, t1, t6 /* t1 <- rela_dyn_start in RAM */
+ add t2, t2, t6 /* t2 <- rela_dyn_end in RAM */
+
+/*
+ * skip first reserved entry: address, type, addend
+ */
+ bne t1, t2, 7f
+
+6:
+ LREG t5, -(REGBYTES*2)(t1) /* t5 <-- relocation info:type */
+ li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
+ bne t5, t3, 8f /* skip non-RISCV_RELOC entries */
+ LREG t3, -(REGBYTES*3)(t1)
+ LREG t5, -(REGBYTES)(t1) /* t5 <-- addend */
+ add t5, t5, t6 /* t5 <-- location to fix up in RAM */
+ add t3, t3, t6 /* t3 <-- location to fix up in RAM */
+ SREG t5, 0(t3)
+7:
+ addi t1, t1, (REGBYTES*3)
+ ble t1, t2, 6b
+
+8:
+ la t4, __dyn_sym_start
+ add t4, t4, t6
+
+9:
+ LREG t5, -(REGBYTES*2)(t1) /* t5 <-- relocation info:type */
+ srli t0, t5, SYM_INDEX /* t0 <--- sym table index */
+ andi t5, t5, 0xFF /* t5 <--- relocation type */
+ li t3, RELOC_TYPE
+ bne t5, t3, 10f /* skip non-addned entries */
+
+ LREG t3, -(REGBYTES*3)(t1)
+ li t5, SYM_SIZE
+ mul t0, t0, t5
+ add s1, t4, t0
+ LREG t5, REGBYTES(s1)
+ add t5, t5, t6 /* t5 <-- location to fix up in RAM */
+ add t3, t3, t6 /* t3 <-- location to fix up in RAM */
+ SREG t5, 0(t3)
+10:
+ addi t1, t1, (REGBYTES*3)
+ ble t1, t2, 9b
+
+/*
+ * trap update
+*/
+ la t0, trap_entry
+ add t0, t0, t6
+ csrw mtvec, t0
+
+clear_bss:
+ la t0, __bss_start /* t0 <- rel __bss_start in FLASH */
+ add t0, t0, t6 /* t0 <- rel __bss_start in RAM */
+ la t1, __bss_end /* t1 <- rel __bss_end in FLASH */
+ add t1, t1, t6 /* t1 <- rel __bss_end in RAM */
+ li t2, 0x00000000 /* clear */
+ beq t0, t1, call_board_init_r
+
+clbss_l:
+ SREG t2, 0(t0) /* clear loop... */
+ addi t0, t0, REGBYTES
+ bne t0, t1, clbss_l
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+call_board_init_r:
+ la t0, board_init_r
+ mv t4, t0 /* offset of board_init_r() */
+ add t4, t4, t6 /* real address of board_init_r() */
+/*
+ * setup parameters for board_init_r
+ */
+ mv a0, s3 /* gd_t */
+ mv a1, s4 /* dest_addr */
+
+/*
+ * jump to it ...
+ */
+ jr t4 /* jump to board_init_r() */
+
+/*
+ * trap entry
+ */
+trap_entry:
+ addi sp, sp, -32*REGBYTES
+ SREG x1, 1*REGBYTES(sp)
+ SREG x2, 2*REGBYTES(sp)
+ SREG x3, 3*REGBYTES(sp)
+ SREG x4, 4*REGBYTES(sp)
+ SREG x5, 5*REGBYTES(sp)
+ SREG x6, 6*REGBYTES(sp)
+ SREG x7, 7*REGBYTES(sp)
+ SREG x8, 8*REGBYTES(sp)
+ SREG x9, 9*REGBYTES(sp)
+ SREG x10, 10*REGBYTES(sp)
+ SREG x11, 11*REGBYTES(sp)
+ SREG x12, 12*REGBYTES(sp)
+ SREG x13, 13*REGBYTES(sp)
+ SREG x14, 14*REGBYTES(sp)
+ SREG x15, 15*REGBYTES(sp)
+ SREG x16, 16*REGBYTES(sp)
+ SREG x17, 17*REGBYTES(sp)
+ SREG x18, 18*REGBYTES(sp)
+ SREG x19, 19*REGBYTES(sp)
+ SREG x20, 20*REGBYTES(sp)
+ SREG x21, 21*REGBYTES(sp)
+ SREG x22, 22*REGBYTES(sp)
+ SREG x23, 23*REGBYTES(sp)
+ SREG x24, 24*REGBYTES(sp)
+ SREG x25, 25*REGBYTES(sp)
+ SREG x26, 26*REGBYTES(sp)
+ SREG x27, 27*REGBYTES(sp)
+ SREG x28, 28*REGBYTES(sp)
+ SREG x29, 29*REGBYTES(sp)
+ SREG x30, 30*REGBYTES(sp)
+ SREG x31, 31*REGBYTES(sp)
+ csrr a0, mcause
+ csrr a1, mepc
+ mv a2, sp
+ jal handle_trap
+ csrw mepc, a0
+
+/*
+ * Remain in M-mode after mret
+ */
+ li t0, MSTATUS_MPP
+ csrs mstatus, t0
+ LREG x1, 1*REGBYTES(sp)
+ LREG x2, 2*REGBYTES(sp)
+ LREG x3, 3*REGBYTES(sp)
+ LREG x4, 4*REGBYTES(sp)
+ LREG x5, 5*REGBYTES(sp)
+ LREG x6, 6*REGBYTES(sp)
+ LREG x7, 7*REGBYTES(sp)
+ LREG x8, 8*REGBYTES(sp)
+ LREG x9, 9*REGBYTES(sp)
+ LREG x10, 10*REGBYTES(sp)
+ LREG x11, 11*REGBYTES(sp)
+ LREG x12, 12*REGBYTES(sp)
+ LREG x13, 13*REGBYTES(sp)
+ LREG x14, 14*REGBYTES(sp)
+ LREG x15, 15*REGBYTES(sp)
+ LREG x16, 16*REGBYTES(sp)
+ LREG x17, 17*REGBYTES(sp)
+ LREG x18, 18*REGBYTES(sp)
+ LREG x19, 19*REGBYTES(sp)
+ LREG x20, 20*REGBYTES(sp)
+ LREG x21, 21*REGBYTES(sp)
+ LREG x22, 22*REGBYTES(sp)
+ LREG x23, 23*REGBYTES(sp)
+ LREG x24, 24*REGBYTES(sp)
+ LREG x25, 25*REGBYTES(sp)
+ LREG x26, 26*REGBYTES(sp)
+ LREG x27, 27*REGBYTES(sp)
+ LREG x28, 28*REGBYTES(sp)
+ LREG x29, 29*REGBYTES(sp)
+ LREG x30, 30*REGBYTES(sp)
+ LREG x31, 31*REGBYTES(sp)
+ addi sp, sp, 32*REGBYTES
+ mret
+
+#ifdef CONFIG_INIT_CRITICAL
+cpu_init_crit:
+ ret
+#endif
diff --git a/arch/riscv/cpu/nx25/u-boot.lds b/arch/riscv/cpu/nx25/u-boot.lds
new file mode 100644
index 0000000000..936fd779aa
--- /dev/null
+++ b/arch/riscv/cpu/nx25/u-boot.lds
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+OUTPUT_ARCH("riscv")
+ENTRY(_start)
+
+SECTIONS
+{
+ . = ALIGN(4);
+ .text :
+ {
+ arch/riscv/cpu/nx25/start.o (.text)
+ *(.text)
+ }
+
+ . = ALIGN(4);
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+
+ . = ALIGN(4);
+ .data : {
+ __global_pointer$ = . + 0x800;
+ *(.data*)
+ }
+ . = ALIGN(4);
+
+ .got : {
+ __got_start = .;
+ *(.got.plt) *(.got)
+ __got_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ . = ALIGN(4);
+
+ /DISCARD/ : { *(.rela.plt*) }
+ .rela.dyn : {
+ __rel_dyn_start = .;
+ *(.rela*)
+ __rel_dyn_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .dynsym : {
+ __dyn_sym_start = .;
+ *(.dynsym)
+ __dyn_sym_end = .;
+ }
+
+ . = ALIGN(4);
+
+ _end = .;
+
+ .bss : {
+ __bss_start = .;
+ *(.bss)
+ . = ALIGN(4);
+ __bss_end = .;
+ }
+
+}
diff --git a/arch/riscv/dts/Makefile b/arch/riscv/dts/Makefile
new file mode 100644
index 0000000000..718b99f694
--- /dev/null
+++ b/arch/riscv/dts/Makefile
@@ -0,0 +1,14 @@
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+dtb-$(CONFIG_TARGET_NX25_AE250) += ae250.dtb
+targets += $(dtb-y)
+
+DTC_FLAGS += -R 4 -p 0x1000
+
+PHONY += dtbs
+dtbs: $(addprefix $(obj)/, $(dtb-y))
+ @:
+
+clean-files := *.dtb
diff --git a/arch/riscv/dts/ae250.dts b/arch/riscv/dts/ae250.dts
new file mode 100644
index 0000000000..5dc4fb04be
--- /dev/null
+++ b/arch/riscv/dts/ae250.dts
@@ -0,0 +1,96 @@
+/dts-v1/;
+/ {
+ compatible = "riscv32 nx25";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+
+ aliases {
+ uart0 = &serial0;
+ ethernet0 = &mac0;
+ spi0 = &spi;
+ } ;
+
+ chosen {
+ bootargs = "console=ttyS0,38400n8 earlyprintk=uart8250-32bit,0xf0300000 debug loglevel=7";
+ stdout-path = "uart0:38400n8";
+ tick-timer = &timer0;
+ };
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x40000000>;
+ };
+
+ spiclk: virt_100mhz {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <100000000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ compatible = "andestech,n13";
+ reg = <0>;
+ /* FIXME: to fill correct frqeuency */
+ clock-frequency = <60000000>;
+ };
+ };
+
+ intc: interrupt-controller {
+ compatible = "andestech,atnointc010";
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ };
+
+ serial0: serial@f0300000 {
+ compatible = "andestech,uart16550", "ns16550a";
+ reg = <0xf0300000 0x1000>;
+ interrupts = <7 4>;
+ clock-frequency = <19660800>;
+ reg-shift = <2>;
+ reg-offset = <32>;
+ no-loopback-test = <1>;
+ };
+
+ timer0: timer@f0400000 {
+ compatible = "andestech,atcpit100";
+ reg = <0xf0400000 0x1000>;
+ interrupts = <2 4>;
+ clock-frequency = <40000000>;
+ };
+
+ mac0: mac@e0100000 {
+ compatible = "andestech,atmac100";
+ reg = <0xe0100000 0x1000>;
+ interrupts = <25 4>;
+ };
+
+ mmc0: mmc@f0e00000 {
+ compatible = "andestech,atsdc010";
+ max-frequency = <100000000>;
+ fifo-depth = <0x10>;
+ reg = <0xf0e00000 0x1000>;
+ interrupts = <17 4>;
+ };
+
+ spi: spi@f0b00000 {
+ compatible = "andestech,atcspi200";
+ reg = <0xf0b00000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ num-cs = <1>;
+ clocks = <&spiclk>;
+ interrupts = <3 4>;
+ flash@0 {
+ compatible = "spi-flash";
+ spi-max-frequency = <50000000>;
+ reg = <0>;
+ spi-cpol;
+ spi-cpha;
+ };
+ };
+
+};
diff --git a/arch/riscv/include/asm/bitops.h b/arch/riscv/include/asm/bitops.h
new file mode 100644
index 0000000000..55d420fdfb
--- /dev/null
+++ b/arch/riscv/include/asm/bitops.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright 1995, Russell King.
+ * Various bits and pieces copyrights include:
+ * Linus Torvalds (test_bit).
+ *
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
+ *
+ * Please note that the code in this file should never be included
+ * from user space. Many of these are not implemented in assembler
+ * since they would be too costly. Also, they require priviledged
+ * instructions (which are not available from user mode) to ensure
+ * that they are atomic.
+ */
+
+#ifndef __ASM_RISCV_BITOPS_H
+#define __ASM_RISCV_BITOPS_H
+
+#ifdef __KERNEL__
+
+#include <asm/system.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
+
+#define smp_mb__before_clear_bit() do { } while (0)
+#define smp_mb__after_clear_bit() do { } while (0)
+
+/*
+ * Function prototypes to keep gcc -Wall happy.
+ */
+static inline void __set_bit(int nr, void *addr)
+{
+ int *a = (int *)addr;
+ int mask;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ *a |= mask;
+}
+
+static inline void __clear_bit(int nr, void *addr)
+{
+ int *a = (int *)addr;
+ int mask;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ *a &= ~mask;
+}
+
+static inline void __change_bit(int nr, void *addr)
+{
+ int mask;
+ unsigned long *ADDR = (unsigned long *)addr;
+
+ ADDR += nr >> 5;
+ mask = 1 << (nr & 31);
+ *ADDR ^= mask;
+}
+
+static inline int __test_and_set_bit(int nr, void *addr)
+{
+ int mask, retval;
+ unsigned int *a = (unsigned int *)addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ retval = (mask & *a) != 0;
+ *a |= mask;
+ return retval;
+}
+
+static inline int __test_and_clear_bit(int nr, void *addr)
+{
+ int mask, retval;
+ unsigned int *a = (unsigned int *)addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ retval = (mask & *a) != 0;
+ *a &= ~mask;
+ return retval;
+}
+
+static inline int __test_and_change_bit(int nr, void *addr)
+{
+ int mask, retval;
+ unsigned int *a = (unsigned int *)addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ retval = (mask & *a) != 0;
+ *a ^= mask;
+ return retval;
+}
+
+/*
+ * This routine doesn't need to be atomic.
+ */
+static inline int test_bit(int nr, const void *addr)
+{
+ return ((unsigned char *)addr)[nr >> 3] & (1U << (nr & 7));
+}
+
+/*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+ */
+static inline unsigned long ffz(unsigned long word)
+{
+ int k;
+
+ word = ~word;
+ k = 31;
+ if (word & 0x0000ffff) {
+ k -= 16; word <<= 16;
+ }
+ if (word & 0x00ff0000) {
+ k -= 8; word <<= 8;
+ }
+ if (word & 0x0f000000) {
+ k -= 4; word <<= 4;
+ }
+ if (word & 0x30000000) {
+ k -= 2; word <<= 2;
+ }
+ if (word & 0x40000000)
+ k -= 1;
+
+ return k;
+}
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+/*
+ * redefined in include/linux/bitops.h
+ * #define ffs(x) generic_ffs(x)
+ */
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+#define ext2_set_bit test_and_set_bit
+#define ext2_clear_bit test_and_clear_bit
+#define ext2_test_bit test_bit
+#define ext2_find_first_zero_bit find_first_zero_bit
+#define ext2_find_next_zero_bit find_next_zero_bit
+
+/* Bitmap functions for the minix filesystem. */
+#define minix_test_and_set_bit(nr, addr) test_and_set_bit(nr, addr)
+#define minix_set_bit(nr, addr) set_bit(nr, addr)
+#define minix_test_and_clear_bit(nr, addr) test_and_clear_bit(nr, addr)
+#define minix_test_bit(nr, addr) test_bit(nr, addr)
+#define minix_find_first_zero_bit(addr, size) find_first_zero_bit(addr, size)
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_RISCV_BITOPS_H */
diff --git a/arch/riscv/include/asm/bootm.h b/arch/riscv/include/asm/bootm.h
new file mode 100644
index 0000000000..0a644bb58b
--- /dev/null
+++ b/arch/riscv/include/asm/bootm.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * Copyright (C) 2011
+ * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#ifndef NDS32_BOOTM_H
+#define NDS32_BOOTM_H
+
+#include <asm/setup.h>
+
+#if defined(CONFIG_SETUP_MEMORY_TAGS) || \
+ defined(CONFIG_CMDLINE_TAG) || \
+ defined(CONFIG_INITRD_TAG) || \
+ defined(CONFIG_SERIAL_TAG) || \
+ defined(CONFIG_REVISION_TAG)
+# define BOOTM_ENABLE_TAGS 1
+#else
+# define BOOTM_ENABLE_TAGS 0
+#endif
+
+#ifdef CONFIG_SETUP_MEMORY_TAGS
+# define BOOTM_ENABLE_MEMORY_TAGS 1
+#else
+# define BOOTM_ENABLE_MEMORY_TAGS 0
+#endif
+
+#ifdef CONFIG_CMDLINE_TAG
+ #define BOOTM_ENABLE_CMDLINE_TAG 1
+#else
+ #define BOOTM_ENABLE_CMDLINE_TAG 0
+#endif
+
+#ifdef CONFIG_INITRD_TAG
+ #define BOOTM_ENABLE_INITRD_TAG 1
+#else
+ #define BOOTM_ENABLE_INITRD_TAG 0
+#endif
+
+#ifdef CONFIG_SERIAL_TAG
+ #define BOOTM_ENABLE_SERIAL_TAG 1
+void get_board_serial(struct tag_serialnr *serialnr);
+#else
+ #define BOOTM_ENABLE_SERIAL_TAG 0
+static inline void get_board_serial(struct tag_serialnr *serialnr)
+{
+}
+#endif
+
+#ifdef CONFIG_REVISION_TAG
+ #define BOOTM_ENABLE_REVISION_TAG 1
+u32 get_board_rev(void);
+#else
+ #define BOOTM_ENABLE_REVISION_TAG 0
+static inline u32 get_board_rev(void)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/arch/riscv/include/asm/byteorder.h b/arch/riscv/include/asm/byteorder.h
new file mode 100644
index 0000000000..d26ac5688f
--- /dev/null
+++ b/arch/riscv/include/asm/byteorder.h
@@ -0,0 +1,35 @@
+/*
+ * linux/include/asm-arm/byteorder.h
+ *
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * ARM Endian-ness. In little endian mode, the data bus is connected such
+ * that byte accesses appear as:
+ * 0 = d0...d7, 1 = d8...d15, 2 = d16...d23, 3 = d24...d31
+ * and word accesses (data or instruction) appear as:
+ * d0...d31
+ *
+ * When in big endian mode, byte accesses appear as:
+ * 0 = d24...d31, 1 = d16...d23, 2 = d8...d15, 3 = d0...d7
+ * and word accesses (data or instruction) appear as:
+ * d0...d31
+ */
+
+#ifndef __ASM_RISCV_BYTEORDER_H
+#define __ASM_RISCV_BYTEORDER_H
+
+#include <asm/types.h>
+
+#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+# define __BYTEORDER_HAS_U64__
+# define __SWAB_64_THRU_32__
+#endif
+
+#ifdef __RISCVEB__
+#include <linux/byteorder/big_endian.h>
+#else
+#include <linux/byteorder/little_endian.h>
+#endif
+
+#endif
diff --git a/arch/riscv/include/asm/cache.h b/arch/riscv/include/asm/cache.h
new file mode 100644
index 0000000000..facf0720aa
--- /dev/null
+++ b/arch/riscv/include/asm/cache.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _ASM_RISCV_CACHE_H
+#define _ASM_RISCV_CACHE_H
+
+/*
+ * The current upper bound for RISCV L1 data cache line sizes is 32 bytes.
+ * We use that value for aligning DMA buffers unless the board config has
+ * specified an alternate cache line size.
+ */
+#ifdef CONFIG_SYS_CACHELINE_SIZE
+#define ARCH_DMA_MINALIGN CONFIG_SYS_CACHELINE_SIZE
+#else
+#define ARCH_DMA_MINALIGN 32
+#endif
+
+#endif /* _ASM_RISCV_CACHE_H */
diff --git a/arch/riscv/include/asm/config.h b/arch/riscv/include/asm/config.h
new file mode 100644
index 0000000000..5f94eb02e2
--- /dev/null
+++ b/arch/riscv/include/asm/config.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _ASM_CONFIG_H_
+#define _ASM_CONFIG_H_
+
+#define CONFIG_LMB
+
+#endif
diff --git a/arch/riscv/include/asm/encoding.h b/arch/riscv/include/asm/encoding.h
new file mode 100644
index 0000000000..5ff6d59149
--- /dev/null
+++ b/arch/riscv/include/asm/encoding.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2017 Microsemi Corporation.
+ * Padmarao Begari, Microsemi Corporation <padmarao.begari@microsemi.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef RISCV_CSR_ENCODING_H
+#define RISCV_CSR_ENCODING_H
+
+#define MSTATUS_UIE 0x00000001
+#define MSTATUS_SIE 0x00000002
+#define MSTATUS_HIE 0x00000004
+#define MSTATUS_MIE 0x00000008
+#define MSTATUS_UPIE 0x00000010
+#define MSTATUS_SPIE 0x00000020
+#define MSTATUS_HPIE 0x00000040
+#define MSTATUS_MPIE 0x00000080
+#define MSTATUS_SPP 0x00000100
+#define MSTATUS_HPP 0x00000600
+#define MSTATUS_MPP 0x00001800
+#define MSTATUS_FS 0x00006000
+#define MSTATUS_XS 0x00018000
+#define MSTATUS_MPRV 0x00020000
+#define MSTATUS_PUM 0x00040000
+#define MSTATUS_VM 0x1F000000
+#define MSTATUS32_SD 0x80000000
+#define MSTATUS64_SD 0x8000000000000000
+
+#define MCAUSE32_CAUSE 0x7FFFFFFF
+#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFF
+#define MCAUSE32_INT 0x80000000
+#define MCAUSE64_INT 0x8000000000000000
+
+#define SSTATUS_UIE 0x00000001
+#define SSTATUS_SIE 0x00000002
+#define SSTATUS_UPIE 0x00000010
+#define SSTATUS_SPIE 0x00000020
+#define SSTATUS_SPP 0x00000100
+#define SSTATUS_FS 0x00006000
+#define SSTATUS_XS 0x00018000
+#define SSTATUS_PUM 0x00040000
+#define SSTATUS32_SD 0x80000000
+#define SSTATUS64_SD 0x8000000000000000
+
+#define MIP_SSIP BIT(IRQ_S_SOFT)
+#define MIP_HSIP BIT(IRQ_H_SOFT)
+#define MIP_MSIP BIT(IRQ_M_SOFT)
+#define MIP_STIP BIT(IRQ_S_TIMER)
+#define MIP_HTIP BIT(IRQ_H_TIMER)
+#define MIP_MTIP BIT(IRQ_M_TIMER)
+#define MIP_SEIP BIT(IRQ_S_EXT)
+#define MIP_HEIP BIT(IRQ_H_EXT)
+#define MIP_MEIP BIT(IRQ_M_EXT)
+
+#define SIP_SSIP MIP_SSIP
+#define SIP_STIP MIP_STIP
+
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2
+#define PRV_M 3
+
+#define VM_MBARE 0
+#define VM_MBB 1
+#define VM_MBBID 2
+#define VM_SV32 8
+#define VM_SV39 9
+#define VM_SV48 10
+
+#define IRQ_S_SOFT 1
+#define IRQ_H_SOFT 2
+#define IRQ_M_SOFT 3
+#define IRQ_S_TIMER 5
+#define IRQ_H_TIMER 6
+#define IRQ_M_TIMER 7
+#define IRQ_S_EXT 9
+#define IRQ_H_EXT 10
+#define IRQ_M_EXT 11
+#define IRQ_COP 12
+#define IRQ_HOST 13
+
+#define DEFAULT_RSTVEC 0x00001000
+#define DEFAULT_NMIVEC 0x00001004
+#define DEFAULT_MTVEC 0x00001010
+#define CONFIG_STRING_ADDR 0x0000100C
+#define EXT_IO_BASE 0x40000000
+#define DRAM_BASE 0x80000000
+
+// page table entry (PTE) fields
+#define PTE_V 0x001 // Valid
+#define PTE_TYPE 0x01E // Type
+#define PTE_R 0x020 // Referenced
+#define PTE_D 0x040 // Dirty
+#define PTE_SOFT 0x380 // Reserved for Software
+
+#define PTE_TYPE_TABLE 0x00
+#define PTE_TYPE_TABLE_GLOBAL 0x02
+#define PTE_TYPE_URX_SR 0x04
+#define PTE_TYPE_URWX_SRW 0x06
+#define PTE_TYPE_UR_SR 0x08
+#define PTE_TYPE_URW_SRW 0x0A
+#define PTE_TYPE_URX_SRX 0x0C
+#define PTE_TYPE_URWX_SRWX0x0E
+#define PTE_TYPE_SR 0x10
+#define PTE_TYPE_SRW 0x12
+#define PTE_TYPE_SRX 0x14
+#define PTE_TYPE_SRWX 0x16
+#define PTE_TYPE_SR_GLOBAL 0x18
+#define PTE_TYPE_SRW_GLOBAL 0x1A
+#define PTE_TYPE_SRX_GLOBAL 0x1C
+#define PTE_TYPE_SRWX_GLOBAL 0x1E
+
+#define PTE_PPN_SHIFT 10
+
+#define PTE_TABLE(PTE) ((0x0000000AU >> ((PTE) & 0x1F)) & 1)
+#define PTE_UR(PTE) ((0x0000AAA0U >> ((PTE) & 0x1F)) & 1)
+#define PTE_UW(PTE) ((0x00008880U >> ((PTE) & 0x1F)) & 1)
+#define PTE_UX(PTE) ((0x0000A0A0U >> ((PTE) & 0x1F)) & 1)
+#define PTE_SR(PTE) ((0xAAAAAAA0U >> ((PTE) & 0x1F)) & 1)
+#define PTE_SW(PTE) ((0x88888880U >> ((PTE) & 0x1F)) & 1)
+#define PTE_SX(PTE) ((0xA0A0A000U >> ((PTE) & 0x1F)) & 1)
+
+#define PTE_CHECK_PERM(PTE, SUPERVISOR, STORE, FETCH) \
+ ((STORE) ? ((SUPERVISOR) ? PTE_SW(PTE) : PTE_UW(PTE)) : \
+ (FETCH) ? ((SUPERVISOR) ? PTE_SX(PTE) : PTE_UX(PTE)) : \
+ ((SUPERVISOR) ? PTE_SR(PTE) : PTE_UR(PTE)))
+
+#ifdef __riscv
+#ifdef CONFIG_64BIT
+# define MSTATUS_SD MSTATUS64_SD
+# define SSTATUS_SD SSTATUS64_SD
+# define MCAUSE_INT MCAUSE64_INT
+# define MCAUSE_CAUSE MCAUSE64_CAUSE
+# define RISCV_PGLEVEL_BITS 9
+#else
+# define MSTATUS_SD MSTATUS32_SD
+# define SSTATUS_SD SSTATUS32_SD
+# define RISCV_PGLEVEL_BITS 10
+# define MCAUSE_INT MCAUSE32_INT
+# define MCAUSE_CAUSE MCAUSE32_CAUSE
+#endif
+#define RISCV_PGSHIFT 12
+#define RISCV_PGSIZE BIT(RISCV_PGSHIFT)
+
+#ifndef __ASSEMBLER__
+
+#ifdef __GNUC__
+
+#define read_csr(reg) ({ unsigned long __tmp; \
+ asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
+ __tmp; })
+
+#define write_csr(reg, val) ({ \
+if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
+ asm volatile ("csrw " #reg ", %0" :: "i"(val)); \
+else \
+ asm volatile ("csrw " #reg ", %0" :: "r"(val)); })
+
+#define swap_csr(reg, val) ({ unsigned long __tmp; \
+if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
+ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \
+else \
+ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \
+ __tmp; })
+
+#define set_csr(reg, bit) ({ unsigned long __tmp; \
+if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
+ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
+else \
+ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
+ __tmp; })
+
+#define clear_csr(reg, bit) ({ unsigned long __tmp; \
+if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
+ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
+else \
+ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
+ __tmp; })
+
+#define rdtime() read_csr(time)
+#define rdcycle() read_csr(cycle)
+#define rdinstret() read_csr(instret)
+
+#endif
+#endif
+#endif
+#endif
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h
new file mode 100644
index 0000000000..0cce98ab53
--- /dev/null
+++ b/arch/riscv/include/asm/global_data.h
@@ -0,0 +1,22 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (c) 2017 Microsemi Corporation.
+ * Padmarao Begari, Microsemi Corporation <padmarao.begari@microsemi.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ASM_GBL_DATA_H
+#define __ASM_GBL_DATA_H
+
+/* Architecture-specific global data */
+struct arch_global_data {
+};
+
+#include <asm-generic/global_data.h>
+
+#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("gp")
+
+#endif /* __ASM_GBL_DATA_H */
diff --git a/arch/riscv/include/asm/io.h b/arch/riscv/include/asm/io.h
new file mode 100644
index 0000000000..e7f63ed8a9
--- /dev/null
+++ b/arch/riscv/include/asm/io.h
@@ -0,0 +1,494 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ */
+#ifndef __ASM_RISCV_IO_H
+#define __ASM_RISCV_IO_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+static inline void sync(void)
+{
+}
+
+/*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+#define MAP_NOCACHE (0)
+#define MAP_WRCOMBINE (0)
+#define MAP_WRBACK (0)
+#define MAP_WRTHROUGH (0)
+
+#ifdef CONFIG_ARCH_MAP_SYSMEM
+static inline void *map_sysmem(phys_addr_t paddr, unsigned long len)
+{
+ if (paddr < PHYS_SDRAM_0_SIZE + PHYS_SDRAM_1_SIZE)
+ paddr = paddr | 0x40000000;
+ return (void *)(uintptr_t)paddr;
+}
+
+static inline void *unmap_sysmem(const void *vaddr)
+{
+ phys_addr_t paddr = (phys_addr_t)vaddr;
+
+ paddr = paddr & ~0x40000000;
+ return (void *)(uintptr_t)paddr;
+}
+
+static inline phys_addr_t map_to_sysmem(const void *ptr)
+{
+ return (phys_addr_t)(uintptr_t)ptr;
+}
+#endif
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+ return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+}
+
+static inline phys_addr_t virt_to_phys(void *vaddr)
+{
+ return (phys_addr_t)(vaddr);
+}
+
+/*
+ * Generic virtual read/write. Note that we don't support half-word
+ * read/writes. We define __arch_*[bl] here, and leave __arch_*w
+ * to the architecture specific code.
+ */
+#define __arch_getb(a) (*(unsigned char *)(a))
+#define __arch_getw(a) (*(unsigned short *)(a))
+#define __arch_getl(a) (*(unsigned int *)(a))
+#define __arch_getq(a) (*(unsigned long *)(a))
+
+#define __arch_putb(v, a) (*(unsigned char *)(a) = (v))
+#define __arch_putw(v, a) (*(unsigned short *)(a) = (v))
+#define __arch_putl(v, a) (*(unsigned int *)(a) = (v))
+#define __arch_putq(v, a) (*(unsigned long *)(a) = (v))
+
+#define __raw_writeb(v, a) __arch_putb(v, a)
+#define __raw_writew(v, a) __arch_putw(v, a)
+#define __raw_writel(v, a) __arch_putl(v, a)
+#define __raw_writeq(v, a) __arch_putq(v, a)
+
+#define __raw_readb(a) __arch_getb(a)
+#define __raw_readw(a) __arch_getw(a)
+#define __raw_readl(a) __arch_getl(a)
+#define __raw_readq(a) __arch_getq(a)
+
+/*
+ * TODO: The kernel offers some more advanced versions of barriers, it might
+ * have some advantages to use them instead of the simple one here.
+ */
+#define dmb() __asm__ __volatile__ ("" : : : "memory")
+#define __iormb() dmb()
+#define __iowmb() dmb()
+
+static inline void writeb(u8 val, volatile void __iomem *addr)
+{
+ __iowmb();
+ __arch_putb(val, addr);
+}
+
+static inline void writew(u16 val, volatile void __iomem *addr)
+{
+ __iowmb();
+ __arch_putw(val, addr);
+}
+
+static inline void writel(u32 val, volatile void __iomem *addr)
+{
+ __iowmb();
+ __arch_putl(val, addr);
+}
+
+static inline void writeq(u64 val, volatile void __iomem *addr)
+{
+ __iowmb();
+ __arch_putq(val, addr);
+}
+
+static inline u8 readb(const volatile void __iomem *addr)
+{
+ u8 val;
+
+ val = __arch_getb(addr);
+ __iormb();
+ return val;
+}
+
+static inline u16 readw(const volatile void __iomem *addr)
+{
+ u16 val;
+
+ val = __arch_getw(addr);
+ __iormb();
+ return val;
+}
+
+static inline u32 readl(const volatile void __iomem *addr)
+{
+ u32 val;
+
+ val = __arch_getl(addr);
+ __iormb();
+ return val;
+}
+
+static inline u64 readq(const volatile void __iomem *addr)
+{
+ u32 val;
+
+ val = __arch_getq(addr);
+ __iormb();
+ return val;
+}
+
+/*
+ * The compiler seems to be incapable of optimising constants
+ * properly. Spell it out to the compiler in some cases.
+ * These are only valid for small values of "off" (< 1<<12)
+ */
+#define __raw_base_writeb(val, base, off) __arch_base_putb(val, base, off)
+#define __raw_base_writew(val, base, off) __arch_base_putw(val, base, off)
+#define __raw_base_writel(val, base, off) __arch_base_putl(val, base, off)
+
+#define __raw_base_readb(base, off) __arch_base_getb(base, off)
+#define __raw_base_readw(base, off) __arch_base_getw(base, off)
+#define __raw_base_readl(base, off) __arch_base_getl(base, off)
+
+#define out_arch(type, endian, a, v) __raw_write##type(cpu_to_##endian(v), a)
+#define in_arch(type, endian, a) endian##_to_cpu(__raw_read##type(a))
+
+#define out_le32(a, v) out_arch(l, le32, a, v)
+#define out_le16(a, v) out_arch(w, le16, a, v)
+
+#define in_le32(a) in_arch(l, le32, a)
+#define in_le16(a) in_arch(w, le16, a)
+
+#define out_be32(a, v) out_arch(l, be32, a, v)
+#define out_be16(a, v) out_arch(w, be16, a, v)
+
+#define in_be32(a) in_arch(l, be32, a)
+#define in_be16(a) in_arch(w, be16, a)
+
+#define out_8(a, v) __raw_writeb(v, a)
+#define in_8(a) __raw_readb(a)
+
+/*
+ * Clear and set bits in one shot. These macros can be used to clear and
+ * set multiple bits in a register using a single call. These macros can
+ * also be used to set a multiple-bit bit pattern using a mask, by
+ * specifying the mask in the 'clear' parameter and the new bit pattern
+ * in the 'set' parameter.
+ */
+
+#define clrbits(type, addr, clear) \
+ out_##type((addr), in_##type(addr) & ~(clear))
+
+#define setbits(type, addr, set) \
+ out_##type((addr), in_##type(addr) | (set))
+
+#define clrsetbits(type, addr, clear, set) \
+ out_##type((addr), (in_##type(addr) & ~(clear)) | (set))
+
+#define clrbits_be32(addr, clear) clrbits(be32, addr, clear)
+#define setbits_be32(addr, set) setbits(be32, addr, set)
+#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set)
+
+#define clrbits_le32(addr, clear) clrbits(le32, addr, clear)
+#define setbits_le32(addr, set) setbits(le32, addr, set)
+#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set)
+
+#define clrbits_be16(addr, clear) clrbits(be16, addr, clear)
+#define setbits_be16(addr, set) setbits(be16, addr, set)
+#define clrsetbits_be16(addr, clear, set) clrsetbits(be16, addr, clear, set)
+
+#define clrbits_le16(addr, clear) clrbits(le16, addr, clear)
+#define setbits_le16(addr, set) setbits(le16, addr, set)
+#define clrsetbits_le16(addr, clear, set) clrsetbits(le16, addr, clear, set)
+
+#define clrbits_8(addr, clear) clrbits(8, addr, clear)
+#define setbits_8(addr, set) setbits(8, addr, set)
+#define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set)
+
+/*
+ * Now, pick up the machine-defined IO definitions
+ * #include <asm/arch/io.h>
+ */
+
+/*
+ * IO port access primitives
+ * -------------------------
+ *
+ * The NDS32 doesn't have special IO access instructions just like ARM;
+ * all IO is memory mapped.
+ * Note that these are defined to perform little endian accesses
+ * only. Their primary purpose is to access PCI and ISA peripherals.
+ *
+ * Note that for a big endian machine, this implies that the following
+ * big endian mode connectivity is in place, as described by numerious
+ * ARM documents:
+ *
+ * PCI: D0-D7 D8-D15 D16-D23 D24-D31
+ * ARM: D24-D31 D16-D23 D8-D15 D0-D7
+ *
+ * The machine specific io.h include defines __io to translate an "IO"
+ * address to a memory address.
+ *
+ * Note that we prevent GCC re-ordering or caching values in expressions
+ * by introducing sequence points into the in*() definitions. Note that
+ * __raw_* do not guarantee this behaviour.
+ *
+ * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space.
+ */
+#ifdef __io
+#define outb(v, p) __raw_writeb(v, __io(p))
+#define outw(v, p) __raw_writew(cpu_to_le16(v), __io(p))
+#define outl(v, p) __raw_writel(cpu_to_le32(v), __io(p))
+
+#define inb(p) ({ unsigned int __v = __raw_readb(__io(p)); __v; })
+#define inw(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; })
+#define inl(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; })
+
+#define outsb(p, d, l) writesb(__io(p), d, l)
+#define outsw(p, d, l) writesw(__io(p), d, l)
+#define outsl(p, d, l) writesl(__io(p), d, l)
+
+#define insb(p, d, l) readsb(__io(p), d, l)
+#define insw(p, d, l) readsw(__io(p), d, l)
+#define insl(p, d, l) readsl(__io(p), d, l)
+
+static inline void readsb(unsigned int *addr, void *data, int bytelen)
+{
+ unsigned char *ptr;
+ unsigned char *ptr2;
+
+ ptr = (unsigned char *)addr;
+ ptr2 = (unsigned char *)data;
+
+ while (bytelen) {
+ *ptr2 = *ptr;
+ ptr2++;
+ bytelen--;
+ }
+}
+
+static inline void readsw(unsigned int *addr, void *data, int wordlen)
+{
+ unsigned short *ptr;
+ unsigned short *ptr2;
+
+ ptr = (unsigned short *)addr;
+ ptr2 = (unsigned short *)data;
+
+ while (wordlen) {
+ *ptr2 = *ptr;
+ ptr2++;
+ wordlen--;
+ }
+}
+
+static inline void readsl(unsigned int *addr, void *data, int longlen)
+{
+ unsigned int *ptr;
+ unsigned int *ptr2;
+
+ ptr = (unsigned int *)addr;
+ ptr2 = (unsigned int *)data;
+
+ while (longlen) {
+ *ptr2 = *ptr;
+ ptr2++;
+ longlen--;
+ }
+}
+
+static inline void writesb(unsigned int *addr, const void *data, int bytelen)
+{
+ unsigned char *ptr;
+ unsigned char *ptr2;
+
+ ptr = (unsigned char *)addr;
+ ptr2 = (unsigned char *)data;
+
+ while (bytelen) {
+ *ptr = *ptr2;
+ ptr2++;
+ bytelen--;
+ }
+}
+
+static inline void writesw(unsigned int *addr, const void *data, int wordlen)
+{
+ unsigned short *ptr;
+ unsigned short *ptr2;
+
+ ptr = (unsigned short *)addr;
+ ptr2 = (unsigned short *)data;
+
+ while (wordlen) {
+ *ptr = *ptr2;
+ ptr2++;
+ wordlen--;
+ }
+}
+
+static inline void writesl(unsigned int *addr, const void *data, int longlen)
+{
+ unsigned int *ptr;
+ unsigned int *ptr2;
+
+ ptr = (unsigned int *)addr;
+ ptr2 = (unsigned int *)data;
+
+ while (longlen) {
+ *ptr = *ptr2;
+ ptr2++;
+ longlen--;
+ }
+}
+#endif
+
+#define outb_p(val, port) outb((val), (port))
+#define outw_p(val, port) outw((val), (port))
+#define outl_p(val, port) outl((val), (port))
+#define inb_p(port) inb((port))
+#define inw_p(port) inw((port))
+#define inl_p(port) inl((port))
+
+#define outsb_p(port, from, len) outsb(port, from, len)
+#define outsw_p(port, from, len) outsw(port, from, len)
+#define outsl_p(port, from, len) outsl(port, from, len)
+#define insb_p(port, to, len) insb(port, to, len)
+#define insw_p(port, to, len) insw(port, to, len)
+#define insl_p(port, to, len) insl(port, to, len)
+
+/*
+ * DMA-consistent mapping functions. These allocate/free a region of
+ * uncached, unwrite-buffered mapped memory space for use with DMA
+ * devices. This is the "generic" version. The PCI specific version
+ * is in pci.h
+ */
+
+/*
+ * String version of IO memory access ops:
+ */
+
+/*
+ * If this architecture has PCI memory IO, then define the read/write
+ * macros. These should only be used with the cookie passed from
+ * ioremap.
+ */
+#ifdef __mem_pci
+
+#define readb(c) ({ unsigned int __v = \
+ __raw_readb(__mem_pci(c)); __v; })
+#define readw(c) ({ unsigned int __v = \
+ le16_to_cpu(__raw_readw(__mem_pci(c))); __v; })
+#define readl(c) ({ unsigned int __v = \
+ le32_to_cpu(__raw_readl(__mem_pci(c))); __v; })
+
+#define writeb(v, c) __raw_writeb(v, __mem_pci(c))
+#define writew(v, c) __raw_writew(cpu_to_le16(v), __mem_pci(c))
+#define writel(v, c) __raw_writel(cpu_to_le32(v), __mem_pci(c))
+
+#define memset_io(c, v, l) _memset_io(__mem_pci(c), (v), (l))
+#define memcpy_fromio(a, c, l) _memcpy_fromio((a), __mem_pci(c), (l))
+#define memcpy_toio(c, a, l) _memcpy_toio(__mem_pci(c), (a), (l))
+
+#define eth_io_copy_and_sum(s, c, l, b) \
+ eth_copy_and_sum((s), __mem_pci(c), (l), (b))
+
+static inline int
+check_signature(unsigned long io_addr, const unsigned char *signature,
+ int length)
+{
+ int retval = 0;
+
+ do {
+ if (readb(io_addr) != *signature)
+ goto out;
+ io_addr++;
+ signature++;
+ length--;
+ } while (length);
+ retval = 1;
+out:
+ return retval;
+}
+#endif /* __mem_pci */
+
+/*
+ * If this architecture has ISA IO, then define the isa_read/isa_write
+ * macros.
+ */
+#ifdef __mem_isa
+
+#define isa_readb(addr) __raw_readb(__mem_isa(addr))
+#define isa_readw(addr) __raw_readw(__mem_isa(addr))
+#define isa_readl(addr) __raw_readl(__mem_isa(addr))
+#define isa_writeb(val, addr) __raw_writeb(val, __mem_isa(addr))
+#define isa_writew(val, addr) __raw_writew(val, __mem_isa(addr))
+#define isa_writel(val, addr) __raw_writel(val, __mem_isa(addr))
+#define isa_memset_io(a, b, c) _memset_io(__mem_isa(a), (b), (c))
+#define isa_memcpy_fromio(a, b, c) _memcpy_fromio((a), __mem_isa(b), (c))
+#define isa_memcpy_toio(a, b, c) _memcpy_toio(__mem_isa((a)), (b), (c))
+
+#define isa_eth_io_copy_and_sum(a, b, c, d) \
+ eth_copy_and_sum((a), __mem_isa(b), (c), (d))
+
+static inline int
+isa_check_signature(unsigned long io_addr, const unsigned char *signature,
+ int length)
+{
+ int retval = 0;
+
+ do {
+ if (isa_readb(io_addr) != *signature)
+ goto out;
+ io_addr++;
+ signature++;
+ length--;
+ } while (length);
+ retval = 1;
+out:
+ return retval;
+}
+
+#else /* __mem_isa */
+
+#define isa_readb(addr) (__readwrite_bug("isa_readb"), 0)
+#define isa_readw(addr) (__readwrite_bug("isa_readw"), 0)
+#define isa_readl(addr) (__readwrite_bug("isa_readl"), 0)
+#define isa_writeb(val, addr) __readwrite_bug("isa_writeb")
+#define isa_writew(val, addr) __readwrite_bug("isa_writew")
+#define isa_writel(val, addr) __readwrite_bug("isa_writel")
+#define isa_memset_io(a, b, c) __readwrite_bug("isa_memset_io")
+#define isa_memcpy_fromio(a, b, c) __readwrite_bug("isa_memcpy_fromio")
+#define isa_memcpy_toio(a, b, c) __readwrite_bug("isa_memcpy_toio")
+
+#define isa_eth_io_copy_and_sum(a, b, c, d) \
+ __readwrite_bug("isa_eth_io_copy_and_sum")
+
+#define isa_check_signature(io, sig, len) (0)
+
+#endif /* __mem_isa */
+#endif /* __KERNEL__ */
+#endif /* __ASM_RISCV_IO_H */
diff --git a/arch/riscv/include/asm/linkage.h b/arch/riscv/include/asm/linkage.h
new file mode 100644
index 0000000000..60d5317797
--- /dev/null
+++ b/arch/riscv/include/asm/linkage.h
@@ -0,0 +1,12 @@
+/*
+ * U-Boot - linkage.h
+ *
+ * Copyright (c) 2005-2007 Analog Devices Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ASM_LINKAGE_H
+#define __ASM_LINKAGE_H
+
+#endif
diff --git a/arch/riscv/include/asm/mach-types.h b/arch/riscv/include/asm/mach-types.h
new file mode 100644
index 0000000000..f70b407998
--- /dev/null
+++ b/arch/riscv/include/asm/mach-types.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ASM_RISCV_MACH_TYPE_H
+#define __ASM_RISCV_MACH_TYPE_H
+
+#ifndef __ASSEMBLY__
+/* The type of machine we're running on */
+extern unsigned int __machine_arch_type;
+#endif
+
+#define MACH_TYPE_AE250 1
+
+#ifdef CONFIG_ARCH_AE250
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_AE250
+# endif
+# define machine_is_ae250() (machine_arch_type == MACH_TYPE_AE250)
+#else
+# define machine_is_ae250() (1)
+#endif
+
+#endif /* __ASM_RISCV_MACH_TYPE_H */
diff --git a/arch/riscv/include/asm/posix_types.h b/arch/riscv/include/asm/posix_types.h
new file mode 100644
index 0000000000..6892b66814
--- /dev/null
+++ b/arch/riscv/include/asm/posix_types.h
@@ -0,0 +1,89 @@
+/*
+ * linux/include/asm-arm/posix_types.h
+ *
+ * Copyright (C) 1996-1998 Russell King.
+ *
+ * Copyright (C) 2011 Andes Technology Corporation
+ * Copyright (C) 2010 Shawn Lin (nobuhiro@andestech.com)
+ * Copyright (C) 2011 Macpaul Lin (macpaul@andestech.com)
+ * Copyright (C) 2017 Rick Chen (rick@andestech.com)
+ *
+ * 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.
+ *
+ * Changelog:
+ * 27-06-1996 RMK Created
+ * 25-10-2017 Modified for arch RISCV
+ */
+#ifndef __ARCH_RISCV_POSIX_TYPES_H
+#define __ARCH_RISCV_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc. Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned short __kernel_dev_t;
+typedef unsigned long __kernel_ino_t;
+typedef unsigned short __kernel_mode_t;
+typedef unsigned short __kernel_nlink_t;
+typedef long __kernel_off_t;
+typedef int __kernel_pid_t;
+typedef unsigned short __kernel_ipc_pid_t;
+typedef unsigned short __kernel_uid_t;
+typedef unsigned short __kernel_gid_t;
+#ifdef __GNUC__
+typedef __SIZE_TYPE__ __kernel_size_t;
+#else
+typedef unsigned int __kernel_size_t;
+#endif
+typedef int __kernel_ssize_t;
+typedef int __kernel_ptrdiff_t;
+typedef long __kernel_time_t;
+typedef long __kernel_suseconds_t;
+typedef long __kernel_clock_t;
+typedef int __kernel_daddr_t;
+typedef char *__kernel_caddr_t;
+typedef unsigned short __kernel_uid16_t;
+typedef unsigned short __kernel_gid16_t;
+typedef unsigned int __kernel_uid32_t;
+typedef unsigned int __kernel_gid32_t;
+
+typedef unsigned short __kernel_old_uid_t;
+typedef unsigned short __kernel_old_gid_t;
+
+#ifdef __GNUC__
+typedef long long __kernel_loff_t;
+#endif
+
+typedef struct {
+#if defined(__KERNEL__) || defined(__USE_ALL)
+ int val[2];
+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+ int __val[2];
+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+} __kernel_fsid_t;
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#undef __FD_SET
+#define __FD_SET(fd, fdsetp) \
+ (((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1 << (fd & 31)))
+
+#undef __FD_CLR
+#define __FD_CLR(fd, fdsetp) \
+ (((fd_set *)fdsetp)->fds_bits[fd >> 5] &= ~(1 << (fd & 31)))
+
+#undef __FD_ISSET
+#define __FD_ISSET(fd, fdsetp) \
+ ((((fd_set *)fdsetp)->fds_bits[fd >> 5] & (1 << (fd & 31))) != 0)
+
+#undef __FD_ZERO
+#define __FD_ZERO(fdsetp) \
+ (memset(fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
+
+#endif
+
+#endif /* __ARCH_RISCV_POSIX_TYPES_H */
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
new file mode 100644
index 0000000000..fe3575298e
--- /dev/null
+++ b/arch/riscv/include/asm/processor.h
@@ -0,0 +1,26 @@
+/*
+ * linux/include/asm-arm/processor.h
+ *
+ * Copyright (C) 1995-2002 Russell King
+ *
+ * Copyright (C) 2011 Andes Technology Corporation
+ * Copyright (C) 2010 Shawn Lin (nobuhiro@andestech.com)
+ * Copyright (C) 2011 Macpaul Lin (macpaul@andestech.com)
+ * Copyright (C) 2017 Rick Chen (rick@andestech.com)
+ *
+ * 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.
+ */
+
+#ifndef __ASM_RISCV_PROCESSOR_H
+#define __ASM_RISCV_PROCESSOR_H
+
+/**************************************************************
+ * CAUTION:
+ * - do not implement for RISCV Arch yet.
+ * - so far some files include /asm/processor.h, but
+ * no one uses the macros defined in this head file.
+ **************************************************************/
+
+#endif /* __ASM_RISCV_PROCESSOR_H */
diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h
new file mode 100644
index 0000000000..76d68698bb
--- /dev/null
+++ b/arch/riscv/include/asm/ptrace.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017 Microsemi Corporation.
+ * Copyright (c) 2017 Padmarao Begari <Padmarao.Begari@microsemi.com>
+ *
+ * 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.
+ */
+#ifndef __ASM_RISCV_PTRACE_H
+#define __ASM_RISCV_PTRACE_H
+
+struct pt_regs {
+ unsigned long sepc;
+ unsigned long ra;
+ unsigned long sp;
+ unsigned long gp;
+ unsigned long tp;
+ unsigned long t0;
+ unsigned long t1;
+ unsigned long t2;
+ unsigned long s0;
+ unsigned long s1;
+ unsigned long a0;
+ unsigned long a1;
+ unsigned long a2;
+ unsigned long a3;
+ unsigned long a4;
+ unsigned long a5;
+ unsigned long a6;
+ unsigned long a7;
+ unsigned long s2;
+ unsigned long s3;
+ unsigned long s4;
+ unsigned long s5;
+ unsigned long s6;
+ unsigned long s7;
+ unsigned long s8;
+ unsigned long s9;
+ unsigned long s10;
+ unsigned long s11;
+ unsigned long t3;
+ unsigned long t4;
+ unsigned long t5;
+ unsigned long t6;
+ /* Supervisor CSRs */
+ unsigned long sstatus;
+ unsigned long sbadaddr;
+ unsigned long scause;
+};
+
+#ifdef CONFIG_64BIT
+#define REG_FMT "%016lx"
+#else
+#define REG_FMT "%08lx"
+#endif
+
+#define user_mode(regs) (((regs)->sstatus & SR_PS) == 0)
+
+/* Helpers for working with the instruction pointer */
+#define GET_IP(regs) ((regs)->sepc)
+#define SET_IP(regs, val) (GET_IP(regs) = (val))
+
+static inline unsigned long instruction_pointer(struct pt_regs *regs)
+{
+ return GET_IP(regs);
+}
+
+static inline void instruction_pointer_set(struct pt_regs *regs,
+ unsigned long val)
+{
+ SET_IP(regs, val);
+}
+
+#define profile_pc(regs) instruction_pointer(regs)
+
+/* Helpers for working with the user stack pointer */
+#define GET_USP(regs) ((regs)->sp)
+#define SET_USP(regs, val) (GET_USP(regs) = (val))
+
+static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+{
+ return GET_USP(regs);
+}
+
+static inline void user_stack_pointer_set(struct pt_regs *regs,
+ unsigned long val)
+{
+ SET_USP(regs, val);
+}
+
+/* Helpers for working with the frame pointer */
+#define GET_FP(regs) ((regs)->s0)
+#define SET_FP(regs, val) (GET_FP(regs) = (val))
+
+static inline unsigned long frame_pointer(struct pt_regs *regs)
+{
+ return GET_FP(regs);
+}
+
+static inline void frame_pointer_set(struct pt_regs *regs,
+ unsigned long val)
+{
+ SET_FP(regs, val);
+}
+
+#endif /* __ASM_RISCV_PTRACE_H */
diff --git a/arch/riscv/include/asm/sections.h b/arch/riscv/include/asm/sections.h
new file mode 100644
index 0000000000..9faa099fb9
--- /dev/null
+++ b/arch/riscv/include/asm/sections.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ASM_RISCV_SECTIONS_H
+#define __ASM_RISCV_SECTIONS_H
+
+#include <asm-generic/sections.h>
+
+#endif
diff --git a/arch/riscv/include/asm/setup.h b/arch/riscv/include/asm/setup.h
new file mode 100644
index 0000000000..731b0d96aa
--- /dev/null
+++ b/arch/riscv/include/asm/setup.h
@@ -0,0 +1,191 @@
+/*
+ * linux/arch/nds32/include/asm/setup.h
+ *
+ * Copyright (C) 1997-1999 Russell King
+ * Copyright (C) 2008 Andes Technology Corporation
+ * Copyright (C) 2013 Ken Kuo (ken_kuo@andestech.com)
+ * Copyright (C) 2017 Rick Chen (rick@andestech.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * Structure passed to kernel to tell it about the
+ * hardware it's running on. See Documentation/arm/Setup
+ * for more info.
+ */
+#ifndef __RISCV_SETUP_H
+#define __RISCV_SETUP_H
+
+#define COMMAND_LINE_SIZE 256
+
+/* The list ends with an ATAG_NONE node. */
+#define ATAG_NONE 0x00000000
+
+struct tag_header {
+ u32 size;
+ u32 tag;
+};
+
+/* The list must start with an ATAG_CORE node */
+#define ATAG_CORE 0x54410001
+
+struct tag_core {
+ u32 flags; /* bit 0 = read-only */
+ u32 pagesize;
+ u32 rootdev;
+};
+
+/* it is allowed to have multiple ATAG_MEM nodes */
+#define ATAG_MEM 0x54410002
+
+struct tag_mem32 {
+ u32 size;
+ u32 start; /* physical start address */
+};
+
+/* VGA text type displays */
+#define ATAG_VIDEOTEXT 0x54410003
+
+struct tag_videotext {
+ u8 x;
+ u8 y;
+ u16 video_page;
+ u8 video_mode;
+ u8 video_cols;
+ u16 video_ega_bx;
+ u8 video_lines;
+ u8 video_isvga;
+ u16 video_points;
+};
+
+/* describes how the ramdisk will be used in kernel */
+#define ATAG_RAMDISK 0x54410004
+
+struct tag_ramdisk {
+ u32 flags; /* bit 0 = load, bit 1 = prompt */
+ u32 size; /* decompressed ramdisk size in _kilo_ bytes */
+ u32 start; /* starting block of floppy-based RAM disk image */
+};
+
+/*
+ * this one accidentally used virtual addresses - as such,
+ * it's deprecated.
+ * describes where the compressed ramdisk image lives (virtual address)
+ */
+#define ATAG_INITRD 0x54410005
+
+/* describes where the compressed ramdisk image lives (physical address) */
+#define ATAG_INITRD2 0x54420005
+
+struct tag_initrd {
+ u32 start; /* physical start address */
+ u32 size; /* size of compressed ramdisk image in bytes */
+};
+
+/* board serial number. "64 bits should be enough for everybody" */
+#define ATAG_SERIAL 0x54410006
+
+struct tag_serialnr {
+ u32 low;
+ u32 high;
+};
+
+/* board revision */
+#define ATAG_REVISION 0x54410007
+
+struct tag_revision {
+ u32 rev;
+};
+
+/* initial values for vesafb-type framebuffers. see struct screen_info
+ * in include/linux/tty.h
+ */
+#define ATAG_VIDEOLFB 0x54410008
+
+struct tag_videolfb {
+ u16 lfb_width;
+ u16 lfb_height;
+ u16 lfb_depth;
+ u16 lfb_linelength;
+ u32 lfb_base;
+ u32 lfb_size;
+ u8 red_size;
+ u8 red_pos;
+ u8 green_size;
+ u8 green_pos;
+ u8 blue_size;
+ u8 blue_pos;
+ u8 rsvd_size;
+ u8 rsvd_pos;
+};
+
+/* command line: \0 terminated string */
+#define ATAG_CMDLINE 0x54410009
+
+struct tag_cmdline {
+ char cmdline[COMMAND_LINE_SIZE];
+};
+
+struct tag {
+ struct tag_header hdr;
+ union {
+ struct tag_core core;
+ struct tag_mem32 mem;
+ struct tag_videotext videotext;
+ struct tag_ramdisk ramdisk;
+ struct tag_initrd initrd;
+ struct tag_serialnr serialnr;
+ struct tag_revision revision;
+ struct tag_videolfb videolfb;
+ struct tag_cmdline cmdline;
+ } u;
+};
+
+struct tagtable {
+ u32 tag;
+ int (*parse)(const struct tag *);
+};
+
+#define tag_member_present(tag, member) \
+ ((unsigned long)(&((struct tag *)0L)->member + 1) \
+ <= (tag)->hdr.size * 4)
+
+#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))
+#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
+
+#define for_each_tag(t, base) \
+ for (t = base; t->hdr.size; t = tag_next(t))
+
+#ifdef __KERNEL__
+
+#define __tag __used __attribute__((__section__(".taglist")))
+#define __tagtable(tag, fn) \
+static struct tagtable __tagtable_##fn __tag = { tag, fn }
+
+/*
+ * Memory map description
+ */
+#define NR_BANKS 8
+
+struct meminfo {
+ int nr_banks;
+ struct {
+ unsigned long start;
+ unsigned long size;
+ int node;
+ } bank[NR_BANKS];
+};
+
+/*
+ * Early command line parameters.
+ */
+struct early_params {
+ const char *arg;
+ void (*fn)(char **p);
+};
+
+#define __early_param(name, fn) \
+static struct early_params __early_##fn __used \
+__attribute__((__section__("__early_param"))) = { name, fn }
+
+#endif
+#endif
diff --git a/arch/riscv/include/asm/string.h b/arch/riscv/include/asm/string.h
new file mode 100644
index 0000000000..038cdaea72
--- /dev/null
+++ b/arch/riscv/include/asm/string.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Andes Technology Corporation
+ * Copyright (C) 2010 Shawn Lin (nobuhiro@andestech.com)
+ * Copyright (C) 2011 Macpaul Lin (macpaul@andestech.com)
+ * Copyright (C) 2017 Rick Chen (rick@andestech.com)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __ASM_RISCV_STRING_H
+#define __ASM_RISCV_STRING_H
+
+/*
+ * We don't do inline string functions, since the
+ * optimised inline asm versions are not small.
+ */
+
+#undef __HAVE_ARCH_STRRCHR
+#undef __HAVE_ARCH_STRCHR
+#undef __HAVE_ARCH_MEMCPY
+#undef __HAVE_ARCH_MEMMOVE
+#undef __HAVE_ARCH_MEMCHR
+#undef __HAVE_ARCH_MEMZERO
+#undef __HAVE_ARCH_MEMSET
+
+#ifdef CONFIG_MARCO_MEMSET
+#define memset(p, v, n) \
+ ({ \
+ if ((n) != 0) { \
+ if (__builtin_constant_p((v)) && (v) == 0) \
+ __memzero((p), (n)); \
+ else \
+ memset((p), (v), (n)); \
+ } \
+ (p); \
+ })
+
+#define memzero(p, n) ({ if ((n) != 0) __memzero((p), (n)); (p); })
+#endif
+
+#endif /* __ASM_RISCV_STRING_H */
diff --git a/arch/riscv/include/asm/system.h b/arch/riscv/include/asm/system.h
new file mode 100644
index 0000000000..443a3005d8
--- /dev/null
+++ b/arch/riscv/include/asm/system.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ASM_RISCV_SYSTEM_H
+#define __ASM_RISCV_SYSTEM_H
+
+/*
+ * Interrupt configuring macros.
+ *
+ * TODO
+ *
+ */
+
+#endif /* __ASM_RISCV_SYSTEM_H */
diff --git a/arch/riscv/include/asm/types.h b/arch/riscv/include/asm/types.h
new file mode 100644
index 0000000000..9797206e5e
--- /dev/null
+++ b/arch/riscv/include/asm/types.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 Andes Technology Corporation
+ * Copyright (C) 2010 Shawn Lin (nobuhiro@andestech.com)
+ * Copyright (C) 2011 Macpaul Lin (macpaul@andestech.com)
+ * Copyright (C) 2017 Rick Chen (rick@andestech.com)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __ASM_RISCV_TYPES_H
+#define __ASM_RISCV_TYPES_H
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+#endif
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+#define BITS_PER_LONG 32
+
+#include <stddef.h>
+
+typedef u32 dma_addr_t;
+
+typedef unsigned long phys_addr_t;
+typedef unsigned long phys_size_t;
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/arch/riscv/include/asm/u-boot-riscv.h b/arch/riscv/include/asm/u-boot-riscv.h
new file mode 100644
index 0000000000..18099cd260
--- /dev/null
+++ b/arch/riscv/include/asm/u-boot-riscv.h
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _U_BOOT_RISCV_H_
+#define _U_BOOT_RISCV_H_ 1
+
+/* cpu/.../cpu.c */
+int cleanup_before_linux(void);
+
+/* board/.../... */
+int board_init(void);
+
+#endif /* _U_BOOT_RISCV_H_ */
diff --git a/arch/riscv/include/asm/u-boot.h b/arch/riscv/include/asm/u-boot.h
new file mode 100644
index 0000000000..ddf7a6310f
--- /dev/null
+++ b/arch/riscv/include/asm/u-boot.h
@@ -0,0 +1,46 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ ********************************************************************
+ * NOTE: This header file defines an interface to U-Boot. Including
+ * this (unmodified) header file in another file is considered normal
+ * use of U-Boot, and does *not* fall under the heading of "derived
+ * work".
+ ********************************************************************
+ */
+
+#ifndef _U_BOOT_H_
+#define _U_BOOT_H_ 1
+
+#include <asm/u-boot-riscv.h>
+
+#include <environment.h>
+
+typedef struct bd_info {
+ unsigned long bi_arch_number; /* unique id for this board */
+ unsigned long bi_boot_params; /* where this board expects params */
+ unsigned long bi_memstart; /* start of DRAM memory */
+ unsigned long bi_memsize; /* size of DRAM memory in bytes */
+ unsigned long bi_flashstart; /* start of FLASH memory */
+ unsigned long bi_flashsize; /* size of FLASH memory */
+ unsigned long bi_flashoffset; /* reserved area for startup monitor */
+ unsigned char bi_enetaddr[6];
+
+ struct /* RAM configuration */
+ {
+ unsigned long start;
+ unsigned long size;
+ } bi_dram[CONFIG_NR_DRAM_BANKS];
+} bd_t;
+
+/* For image.h:image_check_target_arch() */
+#define IH_ARCH_DEFAULT IH_ARCH_RISCV
+
+#endif /* _U_BOOT_H_ */
diff --git a/arch/riscv/include/asm/unaligned.h b/arch/riscv/include/asm/unaligned.h
new file mode 100644
index 0000000000..6cecbbb211
--- /dev/null
+++ b/arch/riscv/include/asm/unaligned.h
@@ -0,0 +1 @@
+#include <asm-generic/unaligned.h>
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
new file mode 100644
index 0000000000..323cf3e835
--- /dev/null
+++ b/arch/riscv/lib/Makefile
@@ -0,0 +1,14 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# Copyright (C) 2017 Andes Technology Corporation
+# Rick Chen, Andes Technology Corporation <rick@andestech.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_CMD_GO) += boot.o
+obj-y += cache.o
+obj-y += interrupts.o
diff --git a/arch/riscv/lib/boot.c b/arch/riscv/lib/boot.c
new file mode 100644
index 0000000000..39ba9b49ff
--- /dev/null
+++ b/arch/riscv/lib/boot.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+unsigned long do_go_exec(ulong (*entry)(int, char * const []),
+ int argc, char * const argv[])
+{
+ cleanup_before_linux();
+
+ return entry(argc, argv);
+}
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c
new file mode 100644
index 0000000000..44ce38b614
--- /dev/null
+++ b/arch/riscv/lib/bootm.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2011 Andes Technology Corporation
+ * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com>
+ * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <image.h>
+#include <u-boot/zlib.h>
+#include <asm/byteorder.h>
+#include <asm/bootm.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int arch_fixup_fdt(void *blob)
+{
+ return 0;
+}
+
+#if defined(CONFIG_SETUP_MEMORY_TAGS) || \
+ defined(CONFIG_CMDLINE_TAG) || \
+ defined(CONFIG_INITRD_TAG) || \
+ defined(CONFIG_SERIAL_TAG) || \
+ defined(CONFIG_REVISION_TAG)
+static void setup_start_tag(bd_t *bd);
+
+# ifdef CONFIG_SETUP_MEMORY_TAGS
+static void setup_memory_tags(bd_t *bd);
+# endif
+static void setup_commandline_tag(bd_t *bd, char *commandline);
+
+# ifdef CONFIG_INITRD_TAG
+static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end);
+# endif
+static void setup_end_tag(bd_t *bd);
+
+static struct tag *params;
+#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
+
+int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
+{
+ bd_t *bd = gd->bd;
+ char *s;
+ int machid = bd->bi_arch_number;
+ void (*theKernel)(int zero, int arch, uint params);
+
+#ifdef CONFIG_CMDLINE_TAG
+ char *commandline = env_get("bootargs");
+#endif
+
+ /*
+ * allow the PREP bootm subcommand, it is required for bootm to work
+ */
+ if (flag & BOOTM_STATE_OS_PREP)
+ return 0;
+
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
+ theKernel = (void (*)(int, int, uint))images->ep;
+
+ s = env_get("machid");
+ if (s) {
+ machid = simple_strtoul(s, NULL, 16);
+ printf("Using machid 0x%x from environment\n", machid);
+ }
+
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+ debug("## Transferring control to Linux (at address %08lx) ...\n",
+ (ulong)theKernel);
+
+ if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
+#ifdef CONFIG_OF_LIBFDT
+ debug("using: FDT\n");
+ if (image_setup_linux(images)) {
+ printf("FDT creation failed! hanging...");
+ hang();
+ }
+#endif
+ } else if (BOOTM_ENABLE_TAGS) {
+#if defined(CONFIG_SETUP_MEMORY_TAGS) || \
+ defined(CONFIG_CMDLINE_TAG) || \
+ defined(CONFIG_INITRD_TAG) || \
+ defined(CONFIG_SERIAL_TAG) || \
+ defined(CONFIG_REVISION_TAG)
+ setup_start_tag(bd);
+#ifdef CONFIG_SERIAL_TAG
+ setup_serial_tag(&params);
+#endif
+#ifdef CONFIG_REVISION_TAG
+ setup_revision_tag(&params);
+#endif
+#ifdef CONFIG_SETUP_MEMORY_TAGS
+ setup_memory_tags(bd);
+#endif
+#ifdef CONFIG_CMDLINE_TAG
+ setup_commandline_tag(bd, commandline);
+#endif
+#ifdef CONFIG_INITRD_TAG
+ if (images->rd_start && images->rd_end)
+ setup_initrd_tag(bd, images->rd_start, images->rd_end);
+#endif
+ setup_end_tag(bd);
+#endif
+
+ /* we assume that the kernel is in place */
+ printf("\nStarting kernel ...\n\n");
+
+#ifdef CONFIG_USB_DEVICE
+ {
+ extern void udc_disconnect(void);
+ udc_disconnect();
+ }
+#endif
+ }
+ cleanup_before_linux();
+ if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
+ theKernel(0, machid, (unsigned long)images->ft_addr);
+ else
+ theKernel(0, machid, bd->bi_boot_params);
+ /* does not return */
+
+ return 1;
+}
+
+#if defined(CONFIG_SETUP_MEMORY_TAGS) || \
+ defined(CONFIG_CMDLINE_TAG) || \
+ defined(CONFIG_INITRD_TAG) || \
+ defined(CONFIG_SERIAL_TAG) || \
+ defined(CONFIG_REVISION_TAG)
+static void setup_start_tag(bd_t *bd)
+{
+ params = (struct tag *)bd->bi_boot_params;
+
+ params->hdr.tag = ATAG_CORE;
+ params->hdr.size = tag_size(tag_core);
+
+ params->u.core.flags = 0;
+ params->u.core.pagesize = 0;
+ params->u.core.rootdev = 0;
+
+ params = tag_next(params);
+}
+
+#ifdef CONFIG_SETUP_MEMORY_TAGS
+static void setup_memory_tags(bd_t *bd)
+{
+ int i;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ params->hdr.tag = ATAG_MEM;
+ params->hdr.size = tag_size(tag_mem32);
+
+ params->u.mem.start = bd->bi_dram[i].start;
+ params->u.mem.size = bd->bi_dram[i].size;
+
+ params = tag_next(params);
+ }
+}
+#endif /* CONFIG_SETUP_MEMORY_TAGS */
+
+static void setup_commandline_tag(bd_t *bd, char *commandline)
+{
+ char *p;
+
+ if (!commandline)
+ return;
+
+ /* eat leading white space */
+ for (p = commandline; *p == ' '; p++)
+ ;
+
+ /* skip non-existent command lines so the kernel will still
+ * use its default command line.
+ */
+ if (*p == '\0')
+ return;
+
+ params->hdr.tag = ATAG_CMDLINE;
+ params->hdr.size =
+ (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2;
+
+ strcpy(params->u.cmdline.cmdline, p)
+ ;
+
+ params = tag_next(params);
+}
+
+#ifdef CONFIG_INITRD_TAG
+static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end)
+{
+ /* an ATAG_INITRD node tells the kernel where the compressed
+ * ramdisk can be found. ATAG_RDIMG is a better name, actually.
+ */
+ params->hdr.tag = ATAG_INITRD2;
+ params->hdr.size = tag_size(tag_initrd);
+
+ params->u.initrd.start = initrd_start;
+ params->u.initrd.size = initrd_end - initrd_start;
+
+ params = tag_next(params);
+}
+#endif /* CONFIG_INITRD_TAG */
+
+#ifdef CONFIG_SERIAL_TAG
+void setup_serial_tag(struct tag **tmp)
+{
+ struct tag *params;
+ struct tag_serialnr serialnr;
+ void get_board_serial(struct tag_serialnr *serialnr);
+
+ params = *tmp;
+ get_board_serial(&serialnr);
+ params->hdr.tag = ATAG_SERIAL;
+ params->hdr.size = tag_size(tag_serialnr);
+ params->u.serialnr.low = serialnr.low;
+ params->u.serialnr.high = serialnr.high;
+ params = tag_next(params);
+ *tmp = params;
+}
+#endif
+
+#ifdef CONFIG_REVISION_TAG
+void setup_revision_tag(struct tag **in_params)
+{
+ u32 rev;
+ u32 get_board_rev(void);
+
+ rev = get_board_rev();
+ params->hdr.tag = ATAG_REVISION;
+ params->hdr.size = tag_size(tag_revision);
+ params->u.revision.rev = rev;
+ params = tag_next(params);
+}
+#endif /* CONFIG_REVISION_TAG */
+
+static void setup_end_tag(bd_t *bd)
+{
+ params->hdr.tag = ATAG_NONE;
+ params->hdr.size = 0;
+}
+
+#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
diff --git a/arch/riscv/lib/cache.c b/arch/riscv/lib/cache.c
new file mode 100644
index 0000000000..948656fdf2
--- /dev/null
+++ b/arch/riscv/lib/cache.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+void flush_dcache_range(unsigned long start, unsigned long end)
+{
+}
+
+void invalidate_icache_range(unsigned long start, unsigned long end)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long end)
+{
+}
+
+void flush_cache(unsigned long addr, unsigned long size)
+{
+}
+
+void icache_enable(void)
+{
+}
+
+void icache_disable(void)
+{
+}
+
+int icache_status(void)
+{
+ return 0;
+}
+
+void dcache_enable(void)
+{
+}
+
+void dcache_disable(void)
+{
+}
+
+int dcache_status(void)
+{
+ return 0;
+}
diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c
new file mode 100644
index 0000000000..075db8ba46
--- /dev/null
+++ b/arch/riscv/lib/interrupts.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016-17 Microsemi Corporation.
+ * Padmarao Begari, Microsemi Corporation <padmarao.begari@microsemi.com>
+ *
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/encoding.h>
+
+static void _exit_trap(int code, uint epc, struct pt_regs *regs);
+
+int interrupt_init(void)
+{
+ return 0;
+}
+
+/*
+ * enable interrupts
+ */
+void enable_interrupts(void)
+{
+}
+
+/*
+ * disable interrupts
+ */
+int disable_interrupts(void)
+{
+ return 0;
+}
+
+uint handle_trap(uint mcause, uint epc, struct pt_regs *regs)
+{
+ uint is_int;
+
+ is_int = (mcause & MCAUSE_INT);
+ if ((is_int) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT))
+ external_interrupt(0); /* handle_m_ext_interrupt */
+ else if ((is_int) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER))
+ timer_interrupt(0); /* handle_m_timer_interrupt */
+ else
+ _exit_trap(mcause, epc, regs);
+
+ return epc;
+}
+
+/*
+ *Entry Point for PLIC Interrupt Handler
+ */
+__attribute__((weak)) void external_interrupt(struct pt_regs *regs)
+{
+}
+
+__attribute__((weak)) void timer_interrupt(struct pt_regs *regs)
+{
+}
+
+static void _exit_trap(int code, uint epc, struct pt_regs *regs)
+{
+ static const char *exception_code[] = {
+ "Instruction address misaligned",
+ "Instruction access fault",
+ "Illegal instruction",
+ "Breakpoint",
+ "Load address misaligned"
+ };
+
+ printf("exception code: %d , %s , epc %08x , ra %08lx\n",
+ code, exception_code[code], epc, regs->ra);
+}
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index e67d428eb2..3f9e788e6c 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -478,6 +478,13 @@
wdt0: wdt@0 {
compatible = "sandbox,wdt";
};
+
+ chosen {
+ chosen-test {
+ compatible = "denx,u-boot-fdt-test";
+ reg = <9 1>;
+ };
+ };
};
#include "sandbox_pmic.dtsi"
diff --git a/board/AndesTech/nx25-ae250/Kconfig b/board/AndesTech/nx25-ae250/Kconfig
new file mode 100644
index 0000000000..2fb3234bad
--- /dev/null
+++ b/board/AndesTech/nx25-ae250/Kconfig
@@ -0,0 +1,24 @@
+if TARGET_NX25_AE250
+
+config SYS_CPU
+ default "nx25"
+
+config SYS_BOARD
+ default "nx25-ae250"
+
+config SYS_VENDOR
+ default "AndesTech"
+
+config SYS_SOC
+ default "ae250"
+
+config SYS_CONFIG_NAME
+ default "nx25-ae250"
+
+config ENV_SIZE
+ default 0x2000 if ENV_IS_IN_SPI_FLASH
+
+config ENV_OFFSET
+ default 0x140000 if ENV_IS_IN_SPI_FLASH
+
+endif
diff --git a/board/AndesTech/nx25-ae250/MAINTAINERS b/board/AndesTech/nx25-ae250/MAINTAINERS
new file mode 100644
index 0000000000..1bff127c64
--- /dev/null
+++ b/board/AndesTech/nx25-ae250/MAINTAINERS
@@ -0,0 +1,6 @@
+NX25-AE250 BOARD
+M: Rick Chen <rick@andestech.com>
+S: Maintained
+F: board/AndesTech/nx25-ae250/
+F: include/configs/nx25-ae250.h
+F: configs/nx25-ae250_defconfig
diff --git a/board/AndesTech/nx25-ae250/Makefile b/board/AndesTech/nx25-ae250/Makefile
new file mode 100644
index 0000000000..66b681492c
--- /dev/null
+++ b/board/AndesTech/nx25-ae250/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (C) 2017 Andes Technology Corporation.
+# Rick Chen, Andes Technology Corporation <rick@andestech.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y := nx25-ae250.o
diff --git a/board/AndesTech/nx25-ae250/nx25-ae250.c b/board/AndesTech/nx25-ae250/nx25-ae250.c
new file mode 100644
index 0000000000..12f2d3520b
--- /dev/null
+++ b/board/AndesTech/nx25-ae250/nx25-ae250.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/mach-types.h>
+#include <common.h>
+#if defined(CONFIG_FTMAC100) && !defined(CONFIG_DM_ETH)
+#include <netdev.h>
+#endif
+#include <linux/io.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Miscellaneous platform dependent initializations
+ */
+
+int board_init(void)
+{
+ gd->bd->bi_arch_number = MACH_TYPE_AE250;
+ gd->bd->bi_boot_params = PHYS_SDRAM_0 + 0x400;
+
+ return 0;
+}
+
+int dram_init(void)
+{
+ unsigned long sdram_base = PHYS_SDRAM_0;
+ unsigned long expected_size = PHYS_SDRAM_0_SIZE + PHYS_SDRAM_1_SIZE;
+ unsigned long actual_size;
+
+ actual_size = get_ram_size((void *)sdram_base, expected_size);
+ gd->ram_size = actual_size;
+
+ if (expected_size != actual_size) {
+ printf("Warning: Only %lu of %lu MiB SDRAM is working\n",
+ actual_size >> 20, expected_size >> 20);
+ }
+
+ return 0;
+}
+
+int dram_init_banksize(void)
+{
+ gd->bd->bi_dram[0].start = PHYS_SDRAM_0;
+ gd->bd->bi_dram[0].size = PHYS_SDRAM_0_SIZE;
+ gd->bd->bi_dram[1].start = PHYS_SDRAM_1;
+ gd->bd->bi_dram[1].size = PHYS_SDRAM_1_SIZE;
+
+ return 0;
+}
+
+#if defined(CONFIG_FTMAC100) && !defined(CONFIG_DM_ETH)
+int board_eth_init(bd_t *bd)
+{
+ return ftmac100_initialize(bd);
+}
+#endif
+
+ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info)
+{
+ return 0;
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifndef CONFIG_DM_MMC
+#ifdef CONFIG_FTSDC010
+ ftsdc010_mmc_init(0);
+#endif
+#endif
+ return 0;
+}
diff --git a/board/qualcomm/dragonboard410c/Makefile b/board/qualcomm/dragonboard410c/Makefile
index cd678088fa..5082383be4 100644
--- a/board/qualcomm/dragonboard410c/Makefile
+++ b/board/qualcomm/dragonboard410c/Makefile
@@ -5,4 +5,5 @@
#
obj-y := dragonboard410c.o
+obj-y += lowlevel_init.o
extra-y += head.o
diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.c b/board/qualcomm/dragonboard410c/dragonboard410c.c
index 848e27848b..9a600952a6 100644
--- a/board/qualcomm/dragonboard410c/dragonboard410c.c
+++ b/board/qualcomm/dragonboard410c/dragonboard410c.c
@@ -10,12 +10,27 @@
#include <dm.h>
#include <usb.h>
#include <asm/gpio.h>
+#include <fdt_support.h>
DECLARE_GLOBAL_DATA_PTR;
+/* pointer to the device tree ammended by the firmware */
+extern void *fw_dtb;
+
+void *board_fdt_blob_setup(void)
+{
+ if (fdt_magic(fw_dtb) != FDT_MAGIC) {
+ printf("Firmware provided invalid dtb!\n");
+ return NULL;
+ }
+
+ return fw_dtb;
+}
+
int dram_init(void)
{
gd->ram_size = PHYS_SDRAM_1_SIZE;
+
return 0;
}
@@ -27,7 +42,6 @@ int dram_init_banksize(void)
return 0;
}
-
int board_prepare_usb(enum usb_init_type type)
{
static struct udevice *pmic_gpio;
@@ -96,11 +110,6 @@ int board_prepare_usb(enum usb_init_type type)
return 0;
}
-int board_init(void)
-{
- return 0;
-}
-
/* Check for vol- button - if pressed - stop autoboot */
int misc_init_r(void)
{
@@ -134,3 +143,48 @@ int misc_init_r(void)
return 0;
}
+
+int board_init(void)
+{
+ return 0;
+}
+
+int ft_board_setup(void *blob, bd_t *bd)
+{
+ int offset, len, i;
+ const char *mac;
+ struct {
+ const char *compatible;
+ const char *property;
+ } fix[] = {
+ [0] = {
+ /* update the kernel's dtb with wlan mac */
+ .compatible = "qcom,wcnss-wlan",
+ .property = "local-mac-address",
+ },
+ [1] = {
+ /* update the kernel's dtb with bt mac */
+ .compatible = "qcom,wcnss-bt",
+ .property = "local-bd-address",
+ },
+ };
+
+ for (i = 0; i < sizeof(fix) / sizeof(fix[0]); i++) {
+ offset = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
+ fix[i].compatible);
+ if (offset < 0)
+ continue;
+
+ mac = fdt_getprop(gd->fdt_blob, offset, fix[i].property, &len);
+ if (mac)
+ do_fixup_by_compat(blob, fix[i].compatible,
+ fix[i].property, mac, ARP_HLEN, 1);
+ }
+
+ return 0;
+}
+
+void reset_cpu(ulong addr)
+{
+ psci_system_reset();
+}
diff --git a/board/qualcomm/dragonboard410c/lowlevel_init.S b/board/qualcomm/dragonboard410c/lowlevel_init.S
new file mode 100644
index 0000000000..15b2d0c7fd
--- /dev/null
+++ b/board/qualcomm/dragonboard410c/lowlevel_init.S
@@ -0,0 +1,28 @@
+/*
+ * (C) Copyright 2016
+ * Cédric Schieli <cschieli@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+
+.align 8
+.global fw_dtb
+fw_dtb:
+ .dword 0x0
+
+/*
+ * Routine: save_boot_params (called after reset from start.S)
+ * Description: save ATAG/FDT address provided by the firmware at boot time
+ */
+
+.global save_boot_params
+save_boot_params:
+
+ /* The firmware provided ATAG/FDT address can be found in r2/x0 */
+ adr x8, fw_dtb
+ str x0, [x8]
+
+ /* Returns */
+ b save_boot_params_ret
diff --git a/board/qualcomm/dragonboard820c/Kconfig b/board/qualcomm/dragonboard820c/Kconfig
new file mode 100644
index 0000000000..aff9af5271
--- /dev/null
+++ b/board/qualcomm/dragonboard820c/Kconfig
@@ -0,0 +1,15 @@
+if TARGET_DRAGONBOARD820C
+
+config SYS_BOARD
+ default "dragonboard820c"
+
+config SYS_VENDOR
+ default "qualcomm"
+
+config SYS_SOC
+ default "apq8096"
+
+config SYS_CONFIG_NAME
+ default "dragonboard820c"
+
+endif
diff --git a/board/qualcomm/dragonboard820c/MAINTAINERS b/board/qualcomm/dragonboard820c/MAINTAINERS
new file mode 100644
index 0000000000..a157033bf0
--- /dev/null
+++ b/board/qualcomm/dragonboard820c/MAINTAINERS
@@ -0,0 +1,6 @@
+DRAGONBOARD820C BOARD
+M: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+S: Maintained
+F: board/qualcomm/dragonboard820c/
+F: include/configs/dragonboard820c.h
+F: configs/dragonboard820c_defconfig
diff --git a/board/qualcomm/dragonboard820c/Makefile b/board/qualcomm/dragonboard820c/Makefile
new file mode 100644
index 0000000000..a1ce4b210f
--- /dev/null
+++ b/board/qualcomm/dragonboard820c/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2017 Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@gmail.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y := dragonboard820c.o
+extra-y += head.o
diff --git a/board/qualcomm/dragonboard820c/dragonboard820c.c b/board/qualcomm/dragonboard820c/dragonboard820c.c
new file mode 100644
index 0000000000..6040787cff
--- /dev/null
+++ b/board/qualcomm/dragonboard820c/dragonboard820c.c
@@ -0,0 +1,163 @@
+/*
+ * Board init file for Dragonboard 820C
+ *
+ * (C) Copyright 2017 Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/arch/sysmap-apq8096.h>
+#include <linux/arm-smccc.h>
+#include <linux/psci.h>
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <asm/psci.h>
+#include <asm/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int dram_init(void)
+{
+ gd->ram_size = PHYS_SDRAM_SIZE;
+
+ return 0;
+}
+
+int dram_init_banksize(void)
+{
+ gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
+ gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
+
+ gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
+ gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
+
+ return 0;
+}
+
+static void sdhci_power_init(void)
+{
+ const u32 TLMM_PULL_MASK = 0x3;
+ const u32 TLMM_HDRV_MASK = 0x7;
+
+ struct tlmm_cfg {
+ u32 bit; /* bit in the register */
+ u8 mask; /* mask clk/dat/cmd control */
+ u8 val;
+ };
+
+ /* bit offsets in the sdc tlmm register */
+ enum { SDC1_DATA_HDRV = 0,
+ SDC1_CMD_HDRV = 3,
+ SDC1_CLK_HDRV = 6,
+ SDC1_DATA_PULL = 9,
+ SDC1_CMD_PULL = 11,
+ SDC1_CLK_PULL = 13,
+ SDC1_RCLK_PULL = 15,
+ };
+
+ enum { TLMM_PULL_DOWN = 0x1,
+ TLMM_PULL_UP = 0x3,
+ TLMM_NO_PULL = 0x0,
+ };
+
+ enum { TLMM_CUR_VAL_10MA = 0x04,
+ TLMM_CUR_VAL_16MA = 0x07,
+ };
+ int i;
+
+ /* drive strength configs for sdhc pins */
+ const struct tlmm_cfg hdrv[] = {
+
+ { SDC1_CLK_HDRV, TLMM_CUR_VAL_16MA, TLMM_HDRV_MASK, },
+ { SDC1_CMD_HDRV, TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK, },
+ { SDC1_DATA_HDRV, TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK, },
+ };
+
+ /* pull configs for sdhc pins */
+ const struct tlmm_cfg pull[] = {
+
+ { SDC1_CLK_PULL, TLMM_NO_PULL, TLMM_PULL_MASK, },
+ { SDC1_CMD_PULL, TLMM_PULL_UP, TLMM_PULL_MASK, },
+ { SDC1_DATA_PULL, TLMM_PULL_UP, TLMM_PULL_MASK, },
+ };
+
+ const struct tlmm_cfg rclk[] = {
+
+ { SDC1_RCLK_PULL, TLMM_PULL_DOWN, TLMM_PULL_MASK,},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(hdrv); i++)
+ clrsetbits_le32(SDC1_HDRV_PULL_CTL_REG,
+ hdrv[i].mask << hdrv[i].bit,
+ hdrv[i].val << hdrv[i].bit);
+
+ for (i = 0; i < ARRAY_SIZE(pull); i++)
+ clrsetbits_le32(SDC1_HDRV_PULL_CTL_REG,
+ pull[i].mask << pull[i].bit,
+ pull[i].val << pull[i].bit);
+
+ for (i = 0; i < ARRAY_SIZE(rclk); i++)
+ clrsetbits_le32(SDC1_HDRV_PULL_CTL_REG,
+ rclk[i].mask << rclk[i].bit,
+ rclk[i].val << rclk[i].bit);
+}
+
+static void show_psci_version(void)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
+
+ printf("PSCI: v%ld.%ld\n",
+ PSCI_VERSION_MAJOR(res.a0),
+ PSCI_VERSION_MINOR(res.a0));
+}
+
+int board_init(void)
+{
+ sdhci_power_init();
+ show_psci_version();
+
+ return 0;
+}
+
+void reset_cpu(ulong addr)
+{
+ psci_system_reset();
+}
+
+/* Check for vol- button - if pressed - stop autoboot */
+int misc_init_r(void)
+{
+ struct udevice *pon;
+ struct gpio_desc resin;
+ int node, ret;
+
+ ret = uclass_get_device_by_name(UCLASS_GPIO, "pm8994_pon@800", &pon);
+ if (ret < 0) {
+ printf("Failed to find PMIC pon node. Check device tree\n");
+ return 0;
+ }
+
+ node = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(pon),
+ "key_vol_down");
+ if (node < 0) {
+ printf("Failed to find key_vol_down node. Check device tree\n");
+ return 0;
+ }
+
+ if (gpio_request_by_name_nodev(offset_to_ofnode(node), "gpios", 0,
+ &resin, 0)) {
+ printf("Failed to request key_vol_down button.\n");
+ return 0;
+ }
+
+ if (dm_gpio_get_value(&resin)) {
+ env_set("bootdelay", "-1");
+ printf("Power button pressed - dropping to console.\n");
+ }
+
+ return 0;
+}
diff --git a/board/qualcomm/dragonboard820c/head.S b/board/qualcomm/dragonboard820c/head.S
new file mode 100644
index 0000000000..06d82d5831
--- /dev/null
+++ b/board/qualcomm/dragonboard820c/head.S
@@ -0,0 +1,34 @@
+/*
+ * ARM64 header for proper chain-loading with Little Kernel.
+ *
+ * Little Kernel shipped with Dragonboard820C boots standard Linux images for
+ * ARM64. This file adds header that is required to boot U-Boot properly.
+ *
+ * For details see:
+ * https://www.kernel.org/doc/Documentation/arm64/booting.txt
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+
+/*
+ * per document in linux/Doc/arm64/booting.text
+ */
+.global _arm64_header
+_arm64_header:
+ b _start
+ .word 0
+ .quad CONFIG_SYS_TEXT_BASE-PHYS_SDRAM_1 /* Image load offset, LE */
+ .quad 0 /* Effective size of kernel image, little-endian */
+ .quad 0 /* kernel flags, little-endian */
+ .quad 0 /* reserved */
+ .quad 0 /* reserved */
+ .quad 0 /* reserved */
+ .byte 0x41 /* Magic number, "ARM\x64" */
+ .byte 0x52
+ .byte 0x4d
+ .byte 0x64
+ .word 0 /* reserved (used for PE COFF offset) */
diff --git a/board/qualcomm/dragonboard820c/readme.txt b/board/qualcomm/dragonboard820c/readme.txt
new file mode 100644
index 0000000000..1f310b31c7
--- /dev/null
+++ b/board/qualcomm/dragonboard820c/readme.txt
@@ -0,0 +1,459 @@
+#
+# (C) Copyright 2017 Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+================================================================================
+ What is working (enough to boot a distro from SD card)
+================================================================================
+ - UART
+ - SD card
+ - PSCI reset
+ - Environment in EXT4 partition 1 in SD card (check defconfig for details)
+ dont forget to insert the card in the SD slot before booting if you
+ are going to make mods to the environment
+
+================================================================================
+ Build & Run instructions
+================================================================================
+
+1) Install mkbootimg and dtbTool from Codeaurora:
+
+ git://codeaurora.org/quic/kernel/skales
+ commit 8492547e404e969262d9070dee9bdd15668bb70f worked for me.
+
+2) Setup CROSS_COMPILE to aarch64 compiler or if you use ccache just do
+ CROSS_COMPILE="ccache aarch64-linux-gnu-"
+
+3) cd to the u-boot tree
+
+ $ make dragonboard820c_config
+ $ make -j `nproc`
+
+4) generate fake, empty ramdisk (can have 0 bytes)
+
+ $ touch rd
+
+5) Generate qualcomm device tree table with dtbTool
+
+ $ dtbTool -o dt.img arch/arm/dts
+
+6) Generate Android boot image with mkbootimg:
+
+ $ mkbootimg --kernel=u-boot-dtb.bin \
+ --output=u-boot.img \
+ --dt=dt.img \
+ --pagesize 4096 \
+ --base 0x80000000 \
+ --ramdisk=rd \
+ --cmdline=""
+
+7) Reboot the board into fastboot mode
+ - plug the board micro-usb to your laptop usb host.
+ - reboot the board with vol- button pressed
+
+8) Boot the uboot image using fastboot
+
+ $ fastboot boot u-boot.img
+
+ or flash it to the UFS drive boot partition:
+
+ $ fastboot flash boot u-boot.img
+ $ fastboot reboot
+
+
+================================================================================
+ To boot a linux kernel from SDHCI with the ROOTFS on an NFS share:
+================================================================================
+
+1) create an EXT4 partition on the SD card (must be partition #1)
+
+2) build the kernel image and dtb (documented extensively somewhere else)
+
+3) copy the drivers to the NFS partition (ie: 192.168.1.2 /exports/db820c-rootfs)
+
+4) add the u-boot headers to the image:
+
+ $ mkimage -A arm64 \
+ -O linux \
+ -C none \
+ -T kernel \
+ -a 0x80080000 \
+ -e 0x80080000 \
+ -n Dragonboard820c \
+ -d $kernel/arch/arm64/boot/Image \
+ uImage
+
+5) copy the generated uImage and the device tree binary to the SD card EXT4
+ partition
+
+ $ cp uImage /mnt/boot/
+ $ cp apq8096-db820c.dtb /mnt/boot/
+
+6) on the SD card create /extlinux/extlinux.conf as follows:
+
+ default nfs
+ prompt 1
+ timeout 10
+
+ LABEL nfs
+ MENU NFS entry
+ LINUX /uImage
+ FDT /apq8096-db820c.dtb
+ APPEND root=/dev/nfs rw \
+ nfsroot=192.168.1.2:/exports/db829c-rootfs,v3,tcp \
+ rootwait \
+ ip=dhcp consoleblank=0 \
+ console=tty0 \
+ console=ttyMSM0,115200n8 \
+ earlyprintk earlycon=msm_serial_dm,0x75b0000 \
+ androidboot.bootdevice=624000.ufshc \
+ androidboot.verifiedbootstate=orange \
+ androidboot.ver0
+
+7) remove the SD card from the laptop and insert it back to the db820 board.
+ the SD card EXT4 partition#1 should contain:
+ /uImage
+ /apq8096-db820c.dtb
+ /extlinux/extlinux.conf
+
+8) reboot the db820 board
+
+================================================================================
+ Successful boot sequence
+================================================================================
+
+Format: Log Type - Time(microsec) - Message - Optional Info
+Log Type: B - Since Boot(Power On Reset), D - Delta, S - Statistic
+S - QC_IMAGE_VERSION_STRING=BOOT.XF.1.0-00301
+S - IMAGE_VARIANT_STRING=M8996LAB
+S - OEM_IMAGE_VERSION_STRING=crm-ubuntu68
+S - Boot Interface: UFS
+S - Secure Boot: Off
+S - Boot Config @ 0x00076044 = 0x000001c9
+S - JTAG ID @ 0x000760f4 = 0x4003e0e1
+S - OEM ID @ 0x000760f8 = 0x00000000
+S - Serial Number @ 0x00074138 = 0x2e8844ce
+S - OEM Config Row 0 @ 0x00074188 = 0x0000000000000000
+S - OEM Config Row 1 @ 0x00074190 = 0x0000000000000000
+S - Feature Config Row 0 @ 0x000741a0 = 0x0050000010000100
+S - Feature Config Row 1 @ 0x000741a8 = 0x00fff00001ffffff
+S - Core 0 Frequency, 1228 MHz
+B - 0 - PBL, Start
+B - 10412 - bootable_media_detect_entry, Start
+B - 47480 - bootable_media_detect_success, Start
+B - 47481 - elf_loader_entry, Start
+B - 49027 - auth_hash_seg_entry, Start
+B - 49129 - auth_hash_seg_exit, Start
+B - 82403 - elf_segs_hash_verify_entry, Start
+B - 84905 - PBL, End
+B - 86955 - SBL1, Start
+B - 182969 - usb: hs_phy_nondrive_start
+B - 183305 - usb: PLL lock success - 0x3
+B - 186294 - usb: hs_phy_nondrive_finish
+B - 190442 - boot_flash_init, Start
+D - 30 - boot_flash_init, Delta
+B - 197548 - sbl1_ddr_set_default_params, Start
+D - 30 - sbl1_ddr_set_default_params, Delta
+B - 205509 - boot_config_data_table_init, Start
+D - 200659 - boot_config_data_table_init, Delta - (60 Bytes)
+B - 410713 - CDT Version:3,Platform ID:24,Major ID:1,Minor ID:0,Subtype:0
+B - 415410 - Image Load, Start
+D - 22570 - PMIC Image Loaded, Delta - (37272 Bytes)
+B - 437980 - pm_device_init, Start
+B - 443744 - PON REASON:PM0:0x200000061 PM1:0x200000021
+B - 480161 - PM_SET_VAL:Skip
+D - 40016 - pm_device_init, Delta
+B - 482083 - pm_driver_init, Start
+D - 2928 - pm_driver_init, Delta
+B - 488671 - pm_sbl_chg_init, Start
+D - 91 - pm_sbl_chg_init, Delta
+B - 495442 - vsense_init, Start
+D - 0 - vsense_init, Delta
+B - 505171 - Pre_DDR_clock_init, Start
+D - 396 - Pre_DDR_clock_init, Delta
+B - 509045 - ddr_initialize_device, Start
+B - 512766 - 8996 v3.x detected, Max frequency = 1.8 GHz
+B - 522373 - ddr_initialize_device, Delta
+B - 522404 - DDR ID, Rank 0, Rank 1, 0x6, 0x300, 0x300
+B - 526247 - Basic DDR tests done
+B - 594994 - clock_init, Start
+D - 274 - clock_init, Delta
+B - 598349 - Image Load, Start
+D - 4331 - QSEE Dev Config Image Loaded, Delta - (46008 Bytes)
+B - 603808 - Image Load, Start
+D - 5338 - APDP Image Loaded, Delta - (0 Bytes)
+B - 612409 - usb: UFS Serial - 2f490ecf
+B - 616801 - usb: fedl, vbus_low
+B - 620431 - Image Load, Start
+D - 55418 - QSEE Image Loaded, Delta - (1640572 Bytes)
+B - 675849 - Image Load, Start
+D - 2013 - SEC Image Loaded, Delta - (4096 Bytes)
+B - 683413 - sbl1_efs_handle_cookies, Start
+D - 457 - sbl1_efs_handle_cookies, Delta
+B - 691892 - Image Load, Start
+D - 14396 - QHEE Image Loaded, Delta - (254184 Bytes)
+B - 706319 - Image Load, Start
+D - 14061 - RPM Image Loaded, Delta - (223900 Bytes)
+B - 721111 - Image Load, Start
+D - 3233 - STI Image Loaded, Delta - (0 Bytes)
+B - 727913 - Image Load, Start
+D - 34709 - APPSBL Image Loaded, Delta - (748716 Bytes)
+B - 762713 - SBL1, End
+D - 680028 - SBL1, Delta
+S - Flash Throughput, 94000 KB/s (2959024 Bytes, 31250 us)
+S - DDR Frequency, 1017 MHz
+Android Bootloader - UART_DM Initialized!!!
+
+[0] BUILD_VERSION=
+[0] BUILD_DATE=16:07:51 - Nov 17 2017
+[0] welcome to lk
+[10] platform_init()
+[10] target_init()
+[10] RPM GLink Init
+[10] Opening RPM Glink Port success
+[10] Opening SSR Glink Port success
+[20] Glink Connection between APPS and RPM established
+[20] Glink Connection between APPS and RPM established
+[40] UFS init success
+[80] Qseecom Init Done in Appsbl
+[80] secure app region addr=0x86600000 size=0x2200000[90] TZ App region notif returned with status:0 addr:86600000 size:35651584
+[100] TZ App log region register returned with status:0 addr:916d4000 size:4096
+[100] Qseecom TZ Init Done in Appsbl
+[120] Loading cmnlib done
+[120] qseecom_start_app: Loading app keymaster for the first time
+[150] <8>keymaster: "\"KEYMASTER Init \""
+[160] Selected panel: none
+Skip panel configuration
+[160] pm8x41_get_is_cold_boot: cold boot
+[170] boot_verifier: Device is in ORANGE boot state.
+[180] Device is unlocked! Skipping verification...
+[180] Loading (boot) image (348160): start
+[190] Loading (boot) image (348160): done
+[190] use_signed_kernel=1, is_unlocked=1, is_tampered=0.
+[200] Your device has been unlocked and cant be trusted.
+Wait for 5 seconds before proceeding
+
+[5200] mdtp: mdtp_img loaded
+[5210] mdtp: is_test_mode: test mode is set to 1
+[5210] mdtp: read_metadata: SUCCESS
+[5230] LK SEC APP Handle: 0x1
+[5230] Return value from recv_data: 14
+[5240] Return value from recv_data: 14
+[5250] Return value from recv_data: 14
+[5260] DTB Total entry: 1, DTB version: 3
+[5260] Using DTB entry 0x00000123/00000000/0x00000018/0 for device 0x00000123/00030001/0x00010018/0
+[5270] cmdline: androidboot.bootdevice=624000.ufshc androidboot.verifiedbootstate=orange androidboot.veritymode=enforcing androidboot.serialno=2f490ecf androidboot.baseband=apq mdss_mdp.panel=0
+[5290] Updating device tree: start
+[5290] Updating device tree: done
+[5290] Return value from recv_data: 14
+[5300] RPM GLINK UnInit
+[5300] Qseecom De-Init Done in Appsbl
+[5300] booting linux @ 0x80080000, ramdisk @ 0x82200000 (0), tags/device tree @ 0x82000000
+[5310] Jumping to kernel via monitor
+
+U-Boot 2017.11-00145-ge895117 (Nov 29 2017 - 10:04:06 +0100)
+Qualcomm-DragonBoard 820C
+
+DRAM: 3 GiB
+PSCI: v1.0
+MMC: sdhci@74a4900: 0
+In: serial@75b0000
+Out: serial@75b0000
+Err: serial@75b0000
+Net: Net Initialization Skipped
+No ethernet found.
+Hit any key to stop autoboot: 0
+switch to partitions #0, OK
+mmc0 is current device
+Scanning mmc 0:1...
+Found /extlinux/extlinux.conf
+Retrieving file: /extlinux/extlinux.conf
+433 bytes read in 71 ms (5.9 KiB/s)
+1: nfs root
+
+Retrieving file: /uImage
+19397184 bytes read in 2024 ms (9.1 MiB/s)
+append: root=/dev/nfs rw nfsroot=192.168.1.2:/db820c/rootfs,v3,tcp rootwait ip=dhcp consoleblank=0 console=tty0 console=ttyMSM0,115200n8 earlyprintk earlycon=msm_serial_dm,0x75b0000 androidboot.bootdevice=624000.ufshc androidboot.verifiedbootstate=orange androidboot.ver0
+
+Retrieving file: /apq8096-db820c.dtb
+38134 bytes read in 37 ms (1005.9 KiB/s)
+
+## Booting kernel from Legacy Image at 95000000 ...
+ Image Name: Dragonboard820c
+ Image Type: AArch64 Linux Kernel Image (uncompressed)
+ Data Size: 19397120 Bytes = 18.5 MiB
+ Load Address: 80080000
+ Entry Point: 80080000
+ Verifying Checksum ... OK
+## Flattened Device Tree blob at 93000000
+ Booting using the fdt blob at 0x93000000
+ Loading Kernel Image ... OK
+ Using Device Tree in place at 0000000093000000, end 000000009300c4f5
+
+Starting kernel ...
+
+[ 0.000000] Booting Linux on physical CPU 0x0
+[ 0.000000] Linux version 4.11.3-30039-g5a922a1 (jramirez@igloo) (gcc version 6.3.1 20170404 (Linaro GCC 6.3-2017.05) ) #1 SMP PREEMPT Wed Oct 18 10:21:11 CEST 2017
+[ 0.000000] Boot CPU: AArch64 Processor [511f2112]
+[ 0.000000] earlycon: msm_serial_dm0 at MMIO 0x00000000075b0000 (options '')
+[ 0.000000] bootconsole [msm_serial_dm0] enabled
+[ 0.000000] efi: Getting EFI parameters from FDT:
+[ 0.000000] efi: UEFI not found.
+[ 0.000000] OF: reserved mem: OVERLAP DETECTED!
+[ 0.000000] adsp@8ea00000 (0x000000008ea00000--0x0000000090400000) overlaps with gpu@8f200000 (0x000000008f200000--0x000000008f300000)
+[ 0.000000] Reserved memory: created DMA memory pool at 0x000000008f200000, size 1 MiB
+[ 0.000000] OF: reserved mem: initialized node gpu@8f200000, compatible id shared-dma-pool
+[ 0.000000] Reserved memory: created DMA memory pool at 0x0000000090400000, size 8 MiB
+[ 0.000000] OF: reserved mem: initialized node venus@90400000, compatible id shared-dma-pool
+[ 0.000000] cma: Reserved 128 MiB at 0x00000000b8000000
+[ 0.000000] NUMA: No NUMA configuration found
+[ 0.000000] NUMA: Faking a node at [mem 0x0000000000000000-0x00000000bfffffff]
+[ 0.000000] NUMA: Adding memblock [0x80000000 - 0x857fffff] on node 0
+[ 0.000000] NUMA: Adding memblock [0x91800000 - 0xbfffffff] on node 0
+[ 0.000000] NUMA: Initmem setup node 0 [mem 0x80000000-0xbfffffff]
+[ 0.000000] NUMA: NODE_DATA [mem 0xb7fb6680-0xb7fb817f]
+[ 0.000000] Zone ranges:
+[ 0.000000] DMA [mem 0x0000000080000000-0x00000000bfffffff]
+[ 0.000000] Normal empty
+[ 0.000000] Movable zone start for each node
+[ 0.000000] Early memory node ranges
+[ 0.000000] node 0: [mem 0x0000000080000000-0x00000000857fffff]
+[ 0.000000] node 0: [mem 0x0000000091800000-0x00000000bfffffff]
+[ 0.000000] Initmem setup node 0 [mem 0x0000000080000000-0x00000000bfffffff]
+[ 0.000000] psci: probing for conduit method from DT.
+[ 0.000000] psci: PSCIv1.0 detected in firmware.
+[ 0.000000] psci: Using standard PSCI v0.2 function IDs
+[ 0.000000] psci: MIGRATE_INFO_TYPE not supported.
+[ 0.000000] percpu: Embedded 23 pages/cpu @ffff8000de9a3000 s57240 r8192 d28776 u94208
+[ 0.000000] pcpu-alloc: s57240 r8192 d28776 u94208 alloc=23*4096
+[ 0.000000] pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3
+[ 0.000000] Detected PIPT I-cache on CPU0
+[ 0.000000] Built 1 zonelists in Node order, mobility grouping on. Total pages: 720293
+[ 0.000000] Policy zone: Normal
+[ 0.000000] Kernel command line: root=/dev/nfs rw nfsroot=192.168.1.2:/db820c/rootfs,v3,tcp rootwait ip=dhcp consoleblank=0
+console=tty0 console=ttyMSM0,115200n8 earlyprintk earlycon=msm_serial_dm,0x75b0000 androidboot.bootdevice=624000.ufshc androidboot.verifiedbootstate=orange a
+ndroidboot.ver0
+[ 0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
+[ 0.000000] software IO TLB [mem 0xd3fff000-0xd7fff000] (64MB) mapped at [ffff800053fff000-ffff800057ffefff]
+[ 0.000000] Memory: 2644172K/2926908K available (11196K kernel code, 1470K rwdata, 5132K rodata, 1088K init, 449K bss, 151664K reserved, 131072K cma-reser
+ved)
+[ 0.000000] Virtual kernel memory layout:
+[ 0.000000] modules : 0xffff000000000000 - 0xffff000008000000 ( 128 MB)
+[ 0.000000] vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000 (129022 GB)
+[ 0.000000] .text : 0xffff000008080000 - 0xffff000008b70000 ( 11200 KB)
+[ 0.000000] .rodata : 0xffff000008b70000 - 0xffff000009080000 ( 5184 KB)
+[ 0.000000] .init : 0xffff000009080000 - 0xffff000009190000 ( 1088 KB)
+[ 0.000000] .data : 0xffff000009190000 - 0xffff0000092ffa00 ( 1471 KB)
+[ 0.000000] .bss : 0xffff0000092ffa00 - 0xffff00000937014c ( 450 KB)
+[ 0.000000] fixed : 0xffff7dfffe7fd000 - 0xffff7dfffec00000 ( 4108 KB)
+[ 0.000000] PCI I/O : 0xffff7dfffee00000 - 0xffff7dffffe00000 ( 16 MB)
+[ 0.000000] vmemmap : 0xffff7e0000000000 - 0xffff800000000000 ( 2048 GB maximum)
+[ 0.000000] 0xffff7e0000000000 - 0xffff7e00037a93c0 ( 55 MB actual)
+[ 0.000000] memory : 0xffff800000000000 - 0xffff8000dea4f000 ( 3562 MB)
+[ 0.000000] SLUB: HWalign=128, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
+[ 0.000000] Preemptible hierarchical RCU implementation.
+[ 0.000000] Build-time adjustment of leaf fanout to 64.
+[ 0.000000] RCU restricting CPUs from NR_CPUS=64 to nr_cpu_ids=4.
+[ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=64, nr_cpu_ids=4
+[ 0.000000] NR_IRQS:64 nr_irqs:64 0
+[ 0.000000] GICv3: CPU0: found redistributor 0 region 0:0x0000000009c00000
+[ 0.000000] GICv2m: range[mem 0x09bd0000-0x09bd0fff], SPI[544:639]
+[ 0.000000] arm_arch_timer: Architected cp15 and mmio timer(s) running at 19.20MHz (virt/virt).
+[ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x46d987e47, max_idle_ns: 440795202767 ns
+[ 0.000002] sched_clock: 56 bits at 19MHz, resolution 52ns, wraps every 4398046511078ns
+
+[....]
+
+
+Some kernel information:
+
+root@linaro-developer:~# cat /proc/cpuinfo
+processor : 0
+BogoMIPS : 38.40
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0x1
+CPU part : 0x211
+CPU revision : 2
+
+processor : 1
+BogoMIPS : 38.40
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0x1
+CPU part : 0x211
+CPU revision : 2
+
+processor : 2
+BogoMIPS : 38.40
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0x1
+CPU part : 0x205
+CPU revision : 2
+
+processor : 3
+BogoMIPS : 38.40
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0x1
+CPU part : 0x205
+CPU revision : 2
+
+root@linaro-developer:~# uname -a
+Linux linaro-developer 4.11.3-30039-g5a922a1 #1 SMP PREEMPT Wed Oct 18 10:21:11 CEST 2017 aarch64 GNU/Linux
+
+root@linaro-developer:~# cat /proc/cmdline
+root=/dev/nfs rw nfsroot=192.168.1.2:/db820c/rootfs,v3,tcp rootwait ip=dhcp consoleblank=0 console=tty0 console=ttyMSM0,115200n8 earlyprintk earlycon=msm_serial_dm,0x75b0000 androidboot.bootdevice=624000.ufshc androidboot.verifiedbootstate=orange androidboot.ver0
+
+root@linaro-developer:~# cat /proc/meminfo
+MemTotal: 2776332 kB
+MemFree: 2593696 kB
+MemAvailable: 2561432 kB
+Buffers: 0 kB
+Cached: 94744 kB
+SwapCached: 0 kB
+Active: 43888 kB
+Inactive: 72972 kB
+Active(anon): 22968 kB
+Inactive(anon): 24616 kB
+Active(file): 20920 kB
+Inactive(file): 48356 kB
+Unevictable: 0 kB
+Mlocked: 0 kB
+SwapTotal: 0 kB
+SwapFree: 0 kB
+Dirty: 0 kB
+Writeback: 0 kB
+AnonPages: 22120 kB
+Mapped: 29284 kB
+Shmem: 25468 kB
+Slab: 32876 kB
+SReclaimable: 12924 kB
+SUnreclaim: 19952 kB
+KernelStack: 2144 kB
+PageTables: 928 kB
+NFS_Unstable: 0 kB
+Bounce: 0 kB
+WritebackTmp: 0 kB
+CommitLimit: 1388164 kB
+Committed_AS: 204192 kB
+VmallocTotal: 135290290112 kB
+VmallocUsed: 0 kB
+VmallocChunk: 0 kB
+AnonHugePages: 2048 kB
+ShmemHugePages: 0 kB
+ShmemPmdMapped: 0 kB
+CmaTotal: 131072 kB
+CmaFree: 130356 kB
+HugePages_Total: 0
+HugePages_Free: 0
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+Hugepagesize: 2048 kB
diff --git a/board/qualcomm/dragonboard820c/u-boot.lds b/board/qualcomm/dragonboard820c/u-boot.lds
new file mode 100644
index 0000000000..b84b4ac8b3
--- /dev/null
+++ b/board/qualcomm/dragonboard820c/u-boot.lds
@@ -0,0 +1,106 @@
+/*
+ * Override linker script for fastboot-readable images
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * Based on arch/arm/cpu/armv8/u-boot.lds (Just add header)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+ENTRY(_arm64_header)
+SECTIONS
+{
+ . = 0x00000000;
+
+ . = ALIGN(8);
+ .text :
+ {
+ *(.__image_copy_start)
+ board/qualcomm/dragonboard820c/head.o (.text*)
+ CPUDIR/start.o (.text*)
+ *(.text*)
+ }
+
+ . = ALIGN(8);
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+
+ . = ALIGN(8);
+ .data : {
+ *(.data*)
+ }
+
+ . = ALIGN(8);
+
+ . = .;
+
+ . = ALIGN(8);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ . = ALIGN(8);
+
+ .efi_runtime : {
+ __efi_runtime_start = .;
+ *(efi_runtime_text)
+ *(efi_runtime_data)
+ __efi_runtime_stop = .;
+ }
+
+ .efi_runtime_rel : {
+ __efi_runtime_rel_start = .;
+ *(.relaefi_runtime_text)
+ *(.relaefi_runtime_data)
+ __efi_runtime_rel_stop = .;
+ }
+
+ . = ALIGN(8);
+
+ .image_copy_end :
+ {
+ *(.__image_copy_end)
+ }
+
+ . = ALIGN(8);
+
+ .rel_dyn_start :
+ {
+ *(.__rel_dyn_start)
+ }
+
+ .rela.dyn : {
+ *(.rela*)
+ }
+
+ .rel_dyn_end :
+ {
+ *(.__rel_dyn_end)
+ }
+
+ _end = .;
+
+ . = ALIGN(8);
+
+ .bss_start : {
+ KEEP(*(.__bss_start));
+ }
+
+ .bss : {
+ *(.bss*)
+ . = ALIGN(8);
+ }
+
+ .bss_end : {
+ KEEP(*(.__bss_end));
+ }
+
+ /DISCARD/ : { *(.dynsym) }
+ /DISCARD/ : { *(.dynstr*) }
+ /DISCARD/ : { *(.dynamic*) }
+ /DISCARD/ : { *(.plt*) }
+ /DISCARD/ : { *(.interp*) }
+ /DISCARD/ : { *(.gnu*) }
+}
diff --git a/cmd/bdinfo.c b/cmd/bdinfo.c
index 27ffcd55bc..c7ebad17d1 100644
--- a/cmd/bdinfo.c
+++ b/cmd/bdinfo.c
@@ -417,6 +417,21 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return 0;
}
+#elif defined(CONFIG_RISCV)
+
+int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ bd_t *bd = gd->bd;
+
+ print_num("arch_number", bd->bi_arch_number);
+ print_bi_boot_params(bd);
+ print_bi_dram(bd);
+ print_eth_ip_addr();
+ print_baudrate();
+
+ return 0;
+}
+
#elif defined(CONFIG_ARC)
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
diff --git a/cmd/mmc.c b/cmd/mmc.c
index 5def4ea1a2..58fdc36f08 100644
--- a/cmd/mmc.c
+++ b/cmd/mmc.c
@@ -23,7 +23,12 @@ static void print_mmcinfo(struct mmc *mmc)
(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
- printf("Tran Speed: %d\n", mmc->tran_speed);
+ printf("Bus Speed: %d\n", mmc->clock);
+#if CONFIG_IS_ENABLED(MMC_VERBOSE)
+ printf("Mode : %s\n", mmc_mode_name(mmc->selected_mode));
+ mmc_dump_capabilities("card capabilities", mmc->card_caps);
+ mmc_dump_capabilities("host capabilities", mmc->host_caps);
+#endif
printf("Rd Block Len: %d\n", mmc->read_bl_len);
printf("%s version %d.%d", IS_SD(mmc) ? "SD" : "MMC",
@@ -40,15 +45,19 @@ static void print_mmcinfo(struct mmc *mmc)
printf("Bus Width: %d-bit%s\n", mmc->bus_width,
mmc->ddr_mode ? " DDR" : "");
+#if CONFIG_IS_ENABLED(MMC_WRITE)
puts("Erase Group Size: ");
print_size(((u64)mmc->erase_grp_size) << 9, "\n");
+#endif
if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) {
bool has_enh = (mmc->part_support & ENHNCD_SUPPORT) != 0;
bool usr_enh = has_enh && (mmc->part_attr & EXT_CSD_ENH_USR);
+#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
puts("HC WP Group Size: ");
print_size(((u64)mmc->hc_wp_grp_size) << 9, "\n");
+#endif
puts("User Capacity: ");
print_size(mmc->capacity_user, usr_enh ? " ENH" : "");
@@ -297,6 +306,8 @@ static int do_mmc_read(cmd_tbl_t *cmdtp, int flag,
return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
}
+
+#if CONFIG_IS_ENABLED(MMC_WRITE)
static int do_mmc_write(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
@@ -355,6 +366,8 @@ static int do_mmc_erase(cmd_tbl_t *cmdtp, int flag,
return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
}
+#endif
+
static int do_mmc_rescan(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
@@ -433,6 +446,7 @@ static int do_mmc_list(cmd_tbl_t *cmdtp, int flag,
return CMD_RET_SUCCESS;
}
+#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
static int parse_hwpart_user(struct mmc_hwpart_conf *pconf,
int argc, char * const argv[])
{
@@ -582,6 +596,7 @@ static int do_mmc_hwpartition(cmd_tbl_t *cmdtp, int flag,
return CMD_RET_FAILURE;
}
}
+#endif
#ifdef CONFIG_SUPPORT_EMMC_BOOT
static int do_mmc_bootbus(cmd_tbl_t *cmdtp, int flag,
@@ -785,13 +800,17 @@ static int do_mmc_bkops_enable(cmd_tbl_t *cmdtp, int flag,
static cmd_tbl_t cmd_mmc[] = {
U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""),
U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""),
+#if CONFIG_IS_ENABLED(MMC_WRITE)
U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""),
U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""),
+#endif
U_BOOT_CMD_MKENT(rescan, 1, 1, do_mmc_rescan, "", ""),
U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""),
U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
+#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
U_BOOT_CMD_MKENT(hwpartition, 28, 0, do_mmc_hwpartition, "", ""),
+#endif
#ifdef CONFIG_SUPPORT_EMMC_BOOT
U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""),
U_BOOT_CMD_MKENT(bootpart-resize, 4, 0, do_mmc_boot_resize, "", ""),
diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c
index a1997ac0d3..23fb8cd807 100644
--- a/cmd/mvebu/bubt.c
+++ b/cmd/mvebu/bubt.c
@@ -110,7 +110,7 @@ static ulong get_load_addr(void)
/********************************************************************
* eMMC services
********************************************************************/
-#ifdef CONFIG_DM_MMC
+#if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(MMC_WRITE)
static int mmc_burn_image(size_t image_size)
{
struct mmc *mmc;
diff --git a/common/Makefile b/common/Makefile
index 14166209fe..c7bde239c1 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -109,6 +109,7 @@ obj-$(CONFIG_IO_TRACE) += iotrace.o
obj-y += memsize.o
obj-y += stdio.o
+ifndef CONFIG_SPL_BUILD
# This option is not just y/n - it can have a numeric value
ifdef CONFIG_FASTBOOT_FLASH
obj-y += image-sparse.o
@@ -119,6 +120,7 @@ ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
obj-y += fb_nand.o
endif
endif
+endif
ifdef CONFIG_CMD_EEPROM_LAYOUT
obj-y += eeprom/eeprom_field.o eeprom/eeprom_layout.o
diff --git a/common/board_f.c b/common/board_f.c
index e46eceda7d..0bdce64ca5 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -218,7 +218,7 @@ static int setup_mon_len(void)
gd->mon_len = (ulong)&_end - (ulong)_init;
#elif defined(CONFIG_NIOS2) || defined(CONFIG_XTENSA)
gd->mon_len = CONFIG_SYS_MONITOR_LEN;
-#elif defined(CONFIG_NDS32) || defined(CONFIG_SH)
+#elif defined(CONFIG_NDS32) || defined(CONFIG_SH) || defined(CONFIG_RISCV)
gd->mon_len = (ulong)(&__bss_end) - (ulong)(&_start);
#elif defined(CONFIG_SYS_MONITOR_BASE)
/* TODO: use (ulong)&__bss_end - (ulong)&__text_start; ? */
diff --git a/common/board_r.c b/common/board_r.c
index 09167c13cc..2a9df6b716 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -126,7 +126,7 @@ static int initr_reloc_global_data(void)
{
#ifdef __ARM__
monitor_flash_len = _end - __image_copy_start;
-#elif defined(CONFIG_NDS32)
+#elif defined(CONFIG_NDS32) || defined(CONFIG_RISCV)
monitor_flash_len = (ulong)&_end - (ulong)&_start;
#elif !defined(CONFIG_SANDBOX) && !defined(CONFIG_NIOS2)
monitor_flash_len = (ulong)&__init_end - gd->relocaddr;
@@ -704,7 +704,7 @@ static init_fnc_t init_sequence_r[] = {
#ifdef CONFIG_DM
initr_dm,
#endif
-#if defined(CONFIG_ARM) || defined(CONFIG_NDS32)
+#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV)
board_init, /* Setup chipselects */
#endif
/*
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 9d35f41233..d686b1ecbd 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -301,6 +301,7 @@ config SPL_ENV_SUPPORT
config SPL_SAVEENV
bool "Support save environment"
depends on SPL_ENV_SUPPORT
+ select SPL_MMC_WRITE if ENV_IS_IN_MMC
help
Enable save environment support in SPL after setenv. By default
the saveenv option is not provided in SPL, but some boards need
@@ -415,6 +416,14 @@ config SPL_MMC_SUPPORT
this option to build the drivers in drivers/mmc as part of an SPL
build.
+config SPL_MMC_WRITE
+ bool "MMC/SD/SDIO card support for write operations in SPL"
+ depends on SPL_MMC_SUPPORT
+ default n
+ help
+ Enable write access to MMC and SD Cards in SPL
+
+
config SPL_MPC8XXX_INIT_DDR_SUPPORT
bool "Support MPC8XXX DDR init"
help
diff --git a/configs/am335x_hs_evm_defconfig b/configs/am335x_hs_evm_defconfig
index 78cf48dde7..63e7a077ae 100644
--- a/configs/am335x_hs_evm_defconfig
+++ b/configs/am335x_hs_evm_defconfig
@@ -13,10 +13,12 @@ CONFIG_ANDROID_BOOT_IMAGE=y
CONFIG_FIT_IMAGE_POST_PROCESS=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
+CONFIG_LOGLEVEL=3
CONFIG_SYS_CONSOLE_INFO_QUIET=y
CONFIG_VERSION_VARIABLE=y
CONFIG_ARCH_MISC_INIT=y
CONFIG_SPL=y
+CONFIG_SPL_FIT_IMAGE_TINY=y
# CONFIG_SPL_ENV_SUPPORT is not set
# CONFIG_SPL_EXT_SUPPORT is not set
CONFIG_SPL_MTD_SUPPORT=y
@@ -37,6 +39,7 @@ CONFIG_DFU_RAM=y
CONFIG_DM_I2C=y
CONFIG_MISC=y
CONFIG_DM_MMC=y
+# CONFIG_MMC_HW_PARTITIONING is not set
CONFIG_MMC_OMAP_HS=y
CONFIG_NAND=y
CONFIG_SPI_FLASH=y
@@ -60,5 +63,6 @@ CONFIG_USB_GADGET_VENDOR_NUM=0x0451
CONFIG_USB_GADGET_PRODUCT_NUM=0xd022
CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_USB_ETHER=y
+CONFIG_SPL_TINY_MEMSET=y
CONFIG_RSA=y
CONFIG_LZO=y
diff --git a/configs/dragonboard410c_defconfig b/configs/dragonboard410c_defconfig
index b71bff7592..4389f52b5c 100644
--- a/configs/dragonboard410c_defconfig
+++ b/configs/dragonboard410c_defconfig
@@ -30,7 +30,6 @@ CONFIG_DM_PMIC=y
CONFIG_PMIC_PM8916=y
CONFIG_MSM_SERIAL=y
CONFIG_SPMI_MSM=y
-CONFIG_SYSRESET=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_USB_EHCI_HCD=y
@@ -44,3 +43,8 @@ CONFIG_USB_ETHER_ASIX88179=y
CONFIG_USB_ETHER_MCS7830=y
CONFIG_USB_ETHER_SMSC95XX=y
CONFIG_OF_LIBFDT_OVERLAY=y
+CONFIG_OF_CONTROL=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_OF_BOARD_SETUP=y
+CONFIG_PSCI_RESET=y
+CONFIG_OF_SEPARATE=y
diff --git a/configs/dragonboard820c_defconfig b/configs/dragonboard820c_defconfig
new file mode 100644
index 0000000000..8af54aa3c4
--- /dev/null
+++ b/configs/dragonboard820c_defconfig
@@ -0,0 +1,43 @@
+CONFIG_ARM=y
+CONFIG_ARM_SMCCC=y
+CONFIG_ARCH_SNAPDRAGON=y
+CONFIG_TARGET_DRAGONBOARD820C=y
+CONFIG_IDENT_STRING="\nQualcomm-DragonBoard 820C"
+CONFIG_DEFAULT_DEVICE_TREE="dragonboard820c"
+CONFIG_USE_BOOTARGS=y
+# CONFIG_DISPLAY_CPUINFO is not set
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_BOOTARGS="console=ttyMSM0,115200n8"
+CONFIG_SYS_PROMPT="dragonboard820c => "
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_BOOTEFI=y
+CONFIG_EFI_LOADER=y
+CONFIG_CMD_BOOTEFI_HELLO=y
+CONFIG_CMD_PXE=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_TIMER=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_PMIC=y
+CONFIG_OF_CONTROL=y
+CONFIG_MSM_SERIAL=y
+CONFIG_SPMI_MSM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_SDHCI=y
+CONFIG_DM_MMC=y
+CONFIG_DM_GPIO=y
+CONFIG_DM_PMIC=y
+CONFIG_PMIC_PM8916=y
+CONFIG_PM8916_GPIO=y
+CONFIG_CLK=y
+CONFIG_PSCI_RESET=y
+CONFIG_ENV_IS_IN_EXT4=y
+CONFIG_ENV_EXT4_INTERFACE="mmc"
+CONFIG_ENV_EXT4_DEVICE_AND_PART="0:1"
+CONFIG_ENV_EXT4_FILE="/uboot.env"
diff --git a/configs/nx25-ae250_defconfig b/configs/nx25-ae250_defconfig
new file mode 100644
index 0000000000..1f68b66f4f
--- /dev/null
+++ b/configs/nx25-ae250_defconfig
@@ -0,0 +1,36 @@
+CONFIG_RISCV=y
+CONFIG_TARGET_NX25_AE250=y
+CONFIG_DEFAULT_DEVICE_TREE="ae250"
+CONFIG_FIT=y
+CONFIG_BOOTDELAY=3
+CONFIG_SYS_PROMPT="RISC-V # "
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SF_TEST=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_EXT2=y
+CONFIG_CMD_FAT=y
+CONFIG_OF_CONTROL=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_DM=y
+CONFIG_CLK=y
+CONFIG_MMC=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_DM_MMC=y
+CONFIG_MMC_NDS32=y
+CONFIG_FTSDC010=y
+CONFIG_DM_ETH=y
+CONFIG_FTMAC100=y
+CONFIG_BAUDRATE=38400
+CONFIG_DM_SERIAL=y
+CONFIG_SYS_NS16550=y
+CONFIG_DM_SPI=y
+CONFIG_ATCSPI200_SPI=y
+CONFIG_TIMER=y
+CONFIG_ATCPIT100_TIMER=y
diff --git a/configs/omapl138_lcdk_defconfig b/configs/omapl138_lcdk_defconfig
index 8d6b12f5b7..0d4506ec44 100644
--- a/configs/omapl138_lcdk_defconfig
+++ b/configs/omapl138_lcdk_defconfig
@@ -8,6 +8,7 @@ CONFIG_SPL_MMC_SUPPORT=y
CONFIG_SPL_SERIAL_SUPPORT=y
CONFIG_SPL_NAND_SUPPORT=y
CONFIG_BOOTDELAY=3
+CONFIG_LOGLEVEL=3
CONFIG_VERSION_VARIABLE=y
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
diff --git a/configs/openrd_base_defconfig b/configs/openrd_base_defconfig
index 1a829b763f..f91e0f9edb 100644
--- a/configs/openrd_base_defconfig
+++ b/configs/openrd_base_defconfig
@@ -25,6 +25,7 @@ CONFIG_CMD_UBI=y
CONFIG_ISO_PARTITION=y
CONFIG_ENV_IS_IN_NAND=y
CONFIG_MVSATA_IDE=y
+# CONFIG_MMC_HW_PARTITIONING is not set
CONFIG_SYS_NS16550=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
diff --git a/configs/openrd_client_defconfig b/configs/openrd_client_defconfig
index 7a95b5b54f..e65c437d88 100644
--- a/configs/openrd_client_defconfig
+++ b/configs/openrd_client_defconfig
@@ -25,6 +25,7 @@ CONFIG_CMD_UBI=y
CONFIG_ISO_PARTITION=y
CONFIG_ENV_IS_IN_NAND=y
CONFIG_MVSATA_IDE=y
+# CONFIG_MMC_HW_PARTITIONING is not set
CONFIG_SYS_NS16550=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
diff --git a/configs/openrd_ultimate_defconfig b/configs/openrd_ultimate_defconfig
index 757be16f53..dfd809dbbb 100644
--- a/configs/openrd_ultimate_defconfig
+++ b/configs/openrd_ultimate_defconfig
@@ -25,6 +25,7 @@ CONFIG_CMD_UBI=y
CONFIG_ISO_PARTITION=y
CONFIG_ENV_IS_IN_NAND=y
CONFIG_MVSATA_IDE=y
+# CONFIG_MMC_HW_PARTITIONING is not set
CONFIG_SYS_NS16550=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
diff --git a/doc/README.NX25 b/doc/README.NX25
new file mode 100644
index 0000000000..9f054e5cf2
--- /dev/null
+++ b/doc/README.NX25
@@ -0,0 +1,46 @@
+NX25 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.ae250 b/doc/README.ae250
new file mode 100644
index 0000000000..a80bb39b15
--- /dev/null
+++ b/doc/README.ae250
@@ -0,0 +1,137 @@
+Andes Technology SoC AE250
+===========================
+
+AE250 is the mainline SoC produced by Andes Technology using NX25 CPU core
+base on RISC-V architecture.
+
+AE250 has integrated both AHB and APB bus and many periphals for application
+and product development.
+
+NX25-AE250
+=========
+
+NX25-AE250 is the SoC with AE250 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/nx25-ae250.h".
+
+Build and boot steps
+====================
+
+build:
+1. Prepare the toolchains and make sure the $PATH to toolchains is correct.
+2. Use `make nx25-ae250_defconfig` in u-boot root to build the image.
+
+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
+====================
+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-ae250-64.bin
+ 1252 hello_world_ae250_32.bin
+ 328787 u-boot-ae250-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-ae250-32.bin
+reading u-boot-ae250-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 #
+
+TODO
+====================
+
+Boot bbl and riscv-linux
diff --git a/doc/README.standalone b/doc/README.standalone
index 659a12f6cb..28ebde1dec 100644
--- a/doc/README.standalone
+++ b/doc/README.standalone
@@ -58,6 +58,7 @@ Design Notes on Exporting U-Boot Functions to Standalone Applications:
Blackfin 0x00001000 0x00001000
NDS32 0x00300000 0x00300000
Nios II 0x02000000 0x02000000
+ RISC-V 0x00600000 0x00600000
For example, the "hello world" application may be loaded and
executed on a PowerPC board with the following commands:
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 976e2c4fdd..36336b65b6 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -266,6 +266,17 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob,
for (offset = fdt_first_subnode(blob, offset);
offset > 0;
offset = fdt_next_subnode(blob, offset)) {
+ /* "chosen" node isn't a device itself but may contain some: */
+ if (!strcmp(fdt_get_name(blob, offset, NULL), "chosen")) {
+ pr_debug("parsing subnodes of \"chosen\"\n");
+
+ err = dm_scan_fdt_node(parent, blob, offset,
+ pre_reloc_only);
+ if (err && !ret)
+ ret = err;
+ continue;
+ }
+
if (pre_reloc_only &&
!dm_fdt_pre_reloc(blob, offset))
continue;
diff --git a/drivers/gpio/pm8916_gpio.c b/drivers/gpio/pm8916_gpio.c
index 9ec2a24b3e..42f068ecb6 100644
--- a/drivers/gpio/pm8916_gpio.c
+++ b/drivers/gpio/pm8916_gpio.c
@@ -29,7 +29,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define REG_STATUS_VAL_MASK 0x1
/* MODE_CTL */
-#define REG_CTL 0x40
+#define REG_CTL 0x40
#define REG_CTL_MODE_MASK 0x70
#define REG_CTL_MODE_INPUT 0x00
#define REG_CTL_MODE_INOUT 0x20
@@ -183,7 +183,7 @@ static int pm8916_gpio_probe(struct udevice *dev)
return -ENODEV;
reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
- if (reg != 0x5)
+ if (reg != 0x5 && reg != 0x1)
return -ENODEV;
return 0;
@@ -203,6 +203,7 @@ static int pm8916_gpio_ofdata_to_platdata(struct udevice *dev)
static const struct udevice_id pm8916_gpio_ids[] = {
{ .compatible = "qcom,pm8916-gpio" },
+ { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
{ }
};
@@ -278,6 +279,7 @@ static int pm8941_pwrkey_ofdata_to_platdata(struct udevice *dev)
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
uc_priv->gpio_count = 2;
+ uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
if (uc_priv->bank_name == NULL)
uc_priv->bank_name = "pm8916_key";
@@ -286,6 +288,7 @@ static int pm8941_pwrkey_ofdata_to_platdata(struct udevice *dev)
static const struct udevice_id pm8941_pwrkey_ids[] = {
{ .compatible = "qcom,pm8916-pwrkey" },
+ { .compatible = "qcom,pm8994-pwrkey" },
{ }
};
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 8fbeaa740d..ab0627a8af 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -10,6 +10,13 @@ config MMC
If you want MMC/SD/SDIO support, you should say Y here and
also to your specific host controller driver.
+config MMC_WRITE
+ bool "support for MMC/SD write operations"
+ depends on MMC
+ default y
+ help
+ Enable write access to MMC and SD Cards
+
config DM_MMC
bool "Enable MMC controllers using Driver Model"
depends on DM
@@ -42,6 +49,75 @@ config ARM_PL180_MMCI
If you have an ARM(R) platform with a Multimedia Card slot,
say Y or M here.
+config MMC_QUIRKS
+ bool "Enable quirks"
+ default y
+ help
+ Some cards and hosts may sometimes behave unexpectedly (quirks).
+ This option enable workarounds to handle those quirks. Some of them
+ are enabled by default, other may require additionnal flags or are
+ enabled by the host driver.
+
+config MMC_HW_PARTITIONING
+ bool "Support for HW partitioning command(eMMC)"
+ default y
+ help
+ This adds a command and an API to do hardware partitioning on eMMC
+ devices.
+
+config MMC_IO_VOLTAGE
+ bool "Support IO voltage configuration"
+ help
+ IO voltage configuration allows selecting the voltage level of the IO
+ lines (not the level of main supply). This is required for UHS
+ support. For eMMC this not mandatory, but not enabling this option may
+ prevent the driver of using the faster modes.
+
+config SPL_MMC_IO_VOLTAGE
+ bool "Support IO voltage configuration in SPL"
+ default n
+ help
+ IO voltage configuration allows selecting the voltage level of the IO
+ lines (not the level of main supply). This is required for UHS
+ support. For eMMC this not mandatory, but not enabling this option may
+ prevent the driver of using the faster modes.
+
+config MMC_UHS_SUPPORT
+ bool "enable UHS support"
+ depends on MMC_IO_VOLTAGE
+ help
+ The Ultra High Speed (UHS) bus is available on some SDHC and SDXC
+ cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
+ frequency can go up to 208MHz (SDR104)
+
+config SPL_MMC_UHS_SUPPORT
+ bool "enable UHS support in SPL"
+ depends on SPL_MMC_IO_VOLTAGE
+ help
+ The Ultra High Speed (UHS) bus is available on some SDHC and SDXC
+ cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
+ frequency can go up to 208MHz (SDR104)
+
+config MMC_HS200_SUPPORT
+ bool "enable HS200 support"
+ help
+ The HS200 mode is support by some eMMC. The bus frequency is up to
+ 200MHz. This mode requires tuning the IO.
+
+
+config SPL_MMC_HS200_SUPPORT
+ bool "enable HS200 support in SPL"
+ help
+ The HS200 mode is support by some eMMC. The bus frequency is up to
+ 200MHz. This mode requires tuning the IO.
+
+config MMC_VERBOSE
+ bool "Output more information about the MMC"
+ default y
+ help
+ Enable the output of more information about the card such as the
+ operating mode.
+
config SPL_MMC_TINY
bool "Tiny MMC framework in SPL"
help
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 9af375b044..64b6f21c61 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -7,6 +7,7 @@
obj-y += mmc.o
obj-$(CONFIG_$(SPL_)DM_MMC) += mmc-uclass.o
+obj-$(CONFIG_$(SPL_)MMC_WRITE) += mmc_write.o
ifndef CONFIG_$(SPL_)BLK
obj-y += mmc_legacy.o
@@ -16,9 +17,6 @@ obj-$(CONFIG_SUPPORT_EMMC_BOOT) += mmc_boot.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
-obj-$(CONFIG_SPL_SAVEENV) += mmc_write.o
-else
-obj-y += mmc_write.o
endif
obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index 5edd383c68..e40575e589 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -168,6 +168,7 @@ static int exynos_dwmci_get_config(const void *blob, int node,
if (host->dev_index > 4) {
printf("DWMMC%d: Can't get the dev index\n", host->dev_index);
+ free(priv);
return -EINVAL;
}
@@ -178,6 +179,7 @@ static int exynos_dwmci_get_config(const void *blob, int node,
base = fdtdec_get_addr(blob, node, "reg");
if (!base) {
printf("DWMMC%d: Can't get base address\n", host->dev_index);
+ free(priv);
return -EINVAL;
}
host->ioaddr = (void *)base;
@@ -187,6 +189,7 @@ static int exynos_dwmci_get_config(const void *blob, int node,
if (err) {
printf("DWMMC%d: Can't get sdr-timings for devider\n",
host->dev_index);
+ free(priv);
return -EINVAL;
}
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 499d622c6d..71c62f4233 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -647,7 +647,11 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
esdhc_write32(&regs->clktunectrlstatus, 0x0);
/* Put VEND_SPEC to default value */
- esdhc_write32(&regs->vendorspec, VENDORSPEC_INIT);
+ if (priv->vs18_enable)
+ esdhc_write32(&regs->vendorspec, (VENDORSPEC_INIT |
+ ESDHC_VENDORSPEC_VSELECT));
+ else
+ esdhc_write32(&regs->vendorspec, VENDORSPEC_INIT);
/* Disable DLL_CTRL delay line */
esdhc_write32(&regs->dllctrl, 0x0);
@@ -665,7 +669,7 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
#endif
/* Set the initial clock speed */
- mmc_set_clock(mmc, 400000);
+ mmc_set_clock(mmc, 400000, false);
/* Disable the BRR and BWR bits in IRQSTAT */
esdhc_clrbits32(&regs->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
@@ -676,9 +680,6 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
/* Set timout to the maximum value */
esdhc_clrsetbits32(&regs->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16);
- if (priv->vs18_enable)
- esdhc_setbits32(&regs->vendorspec, ESDHC_VENDORSPEC_VSELECT);
-
return 0;
}
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c
index 22154d13d7..1c108b5470 100644
--- a/drivers/mmc/gen_atmel_mci.c
+++ b/drivers/mmc/gen_atmel_mci.c
@@ -74,6 +74,20 @@ static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
cmdr, cmdr & 0x3F, arg, status, msg);
}
+static inline void mci_set_blklen(atmel_mci_t *mci, int blklen)
+{
+ unsigned int version = atmel_mci_get_version(mci);
+
+ blklen &= 0xfffc;
+
+ /* MCI IP version >= 0x200 has blkr */
+ if (version >= 0x200)
+ writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->blkr)),
+ &mci->blkr);
+ else
+ writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->mr)), &mci->mr);
+}
+
/* Setup for MCI Clock and Block Size */
#ifdef CONFIG_DM_MMC
static void mci_set_mode(struct udevice *dev, u32 hz, u32 blklen)
@@ -124,7 +138,6 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
else
priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
- blklen &= 0xfffc;
mr = MMCI_BF(CLKDIV, clkdiv);
@@ -138,14 +151,10 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
*/
if (version >= 0x500)
mr |= MMCI_BF(CLKODD, clkodd);
- else
- mr |= MMCI_BF(BLKLEN, blklen);
writel(mr, &mci->mr);
- /* MCI IP version >= 0x200 has blkr */
- if (version >= 0x200)
- writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
+ mci_set_blklen(mci, blklen);
if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
writel(MMCI_BIT(HSMODE), &mci->cfg);
@@ -236,7 +245,6 @@ static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
{
struct atmel_mci_plat *plat = dev_get_platdata(dev);
struct atmel_mci_priv *priv = dev_get_priv(dev);
- struct mmc *mmc = mmc_get_mmc_dev(dev);
atmel_mci_t *mci = plat->mci;
#else
static int
@@ -257,11 +265,13 @@ mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
/* Figure out the transfer arguments */
cmdr = mci_encode_cmd(cmd, data, &error_flags);
+ mci_set_blklen(mci, data->blocksize);
+
/* For multi blocks read/write, set the block register */
if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
|| (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
- writel(data->blocks | MMCI_BF(BLKLEN, mmc->read_bl_len),
- &mci->blkr);
+ writel(data->blocks | MMCI_BF(BLKLEN, data->blocksize),
+ &mci->blkr);
/* Send the command */
writel(cmd->cmdarg, &mci->argr);
@@ -295,17 +305,15 @@ mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
if (data) {
u32 word_count, block_count;
u32* ioptr;
- u32 sys_blocksize, dummy, i;
+ u32 i;
u32 (*mci_data_op)
(atmel_mci_t *mci, u32* data, u32 error_flags);
if (data->flags & MMC_DATA_READ) {
mci_data_op = mci_data_read;
- sys_blocksize = mmc->read_bl_len;
ioptr = (u32*)data->dest;
} else {
mci_data_op = mci_data_write;
- sys_blocksize = mmc->write_bl_len;
ioptr = (u32*)data->src;
}
@@ -328,16 +336,6 @@ mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
1, cnt, 0);
}
#endif
-#ifdef DEBUG
- if (!status && word_count < (sys_blocksize / 4))
- printf("filling rest of block...\n");
-#endif
- /* fill the rest of a full block */
- while (!status && word_count < (sys_blocksize / 4)) {
- status = mci_data_op(mci, &dummy,
- error_flags);
- word_count++;
- }
if (status) {
dump_cmd(cmdr, cmd->cmdarg, status,
"Data Transfer Failed");
diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c
index 4652fab45e..a2cd5d3a44 100644
--- a/drivers/mmc/meson_gx_mmc.c
+++ b/drivers/mmc/meson_gx_mmc.c
@@ -250,7 +250,7 @@ static int meson_mmc_probe(struct udevice *dev)
mmc->priv = pdata;
upriv->mmc = mmc;
- mmc_set_clock(mmc, cfg->f_min);
+ mmc_set_clock(mmc, cfg->f_min, false);
/* reset all status bits */
meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS);
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 5dda20cda5..26c6ab7ad1 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -10,7 +10,6 @@
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
-#include <dm/root.h>
#include "mmc_private.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -51,6 +50,35 @@ int mmc_set_ios(struct mmc *mmc)
return dm_mmc_set_ios(mmc->dev);
}
+void dm_mmc_send_init_stream(struct udevice *dev)
+{
+ struct dm_mmc_ops *ops = mmc_get_ops(dev);
+
+ if (ops->send_init_stream)
+ ops->send_init_stream(dev);
+}
+
+void mmc_send_init_stream(struct mmc *mmc)
+{
+ dm_mmc_send_init_stream(mmc->dev);
+}
+
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout)
+{
+ struct dm_mmc_ops *ops = mmc_get_ops(dev);
+
+ if (!ops->wait_dat0)
+ return -ENOSYS;
+ return ops->wait_dat0(dev, state, timeout);
+}
+
+int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
+{
+ return dm_mmc_wait_dat0(mmc->dev, state, timeout);
+}
+#endif
+
int dm_mmc_get_wp(struct udevice *dev)
{
struct dm_mmc_ops *ops = mmc_get_ops(dev);
@@ -79,6 +107,73 @@ int mmc_getcd(struct mmc *mmc)
return dm_mmc_get_cd(mmc->dev);
}
+#ifdef MMC_SUPPORTS_TUNING
+int dm_mmc_execute_tuning(struct udevice *dev, uint opcode)
+{
+ struct dm_mmc_ops *ops = mmc_get_ops(dev);
+
+ if (!ops->execute_tuning)
+ return -ENOSYS;
+ return ops->execute_tuning(dev, opcode);
+}
+
+int mmc_execute_tuning(struct mmc *mmc, uint opcode)
+{
+ return dm_mmc_execute_tuning(mmc->dev, opcode);
+}
+#endif
+
+int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg)
+{
+ int val;
+
+ val = dev_read_u32_default(dev, "bus-width", 1);
+
+ switch (val) {
+ case 0x8:
+ cfg->host_caps |= MMC_MODE_8BIT;
+ /* fall through */
+ case 0x4:
+ cfg->host_caps |= MMC_MODE_4BIT;
+ /* fall through */
+ case 0x1:
+ cfg->host_caps |= MMC_MODE_1BIT;
+ break;
+ default:
+ debug("warning: %s invalid bus-width property. using 1-bit\n",
+ dev_read_name(dev));
+ cfg->host_caps |= MMC_MODE_1BIT;
+ break;
+ }
+
+ cfg->f_max = dev_read_u32_default(dev, "max-frequency", 52000000);
+
+ if (dev_read_bool(dev, "cap-sd-highspeed"))
+ cfg->host_caps |= MMC_CAP(SD_HS);
+ if (dev_read_bool(dev, "cap-mmc-highspeed"))
+ cfg->host_caps |= MMC_CAP(MMC_HS);
+ if (dev_read_bool(dev, "sd-uhs-sdr12"))
+ cfg->host_caps |= MMC_CAP(UHS_SDR12);
+ if (dev_read_bool(dev, "sd-uhs-sdr25"))
+ cfg->host_caps |= MMC_CAP(UHS_SDR25);
+ if (dev_read_bool(dev, "sd-uhs-sdr50"))
+ cfg->host_caps |= MMC_CAP(UHS_SDR50);
+ if (dev_read_bool(dev, "sd-uhs-sdr104"))
+ cfg->host_caps |= MMC_CAP(UHS_SDR104);
+ if (dev_read_bool(dev, "sd-uhs-ddr50"))
+ cfg->host_caps |= MMC_CAP(UHS_DDR50);
+ if (dev_read_bool(dev, "mmc-ddr-1_8v"))
+ cfg->host_caps |= MMC_CAP(MMC_DDR_52);
+ if (dev_read_bool(dev, "mmc-ddr-1_2v"))
+ cfg->host_caps |= MMC_CAP(MMC_DDR_52);
+ if (dev_read_bool(dev, "mmc-hs200-1_8v"))
+ cfg->host_caps |= MMC_CAP(MMC_HS_200);
+ if (dev_read_bool(dev, "mmc-hs200-1_2v"))
+ cfg->host_caps |= MMC_CAP(MMC_HS_200);
+
+ return 0;
+}
+
struct mmc *mmc_get_mmc_dev(struct udevice *dev)
{
struct mmc_uclass_priv *upriv;
@@ -275,7 +370,7 @@ static int mmc_blk_probe(struct udevice *dev)
static const struct blk_ops mmc_blk_ops = {
.read = mmc_bread,
-#ifndef CONFIG_SPL_BUILD
+#if CONFIG_IS_ENABLED(MMC_WRITE)
.write = mmc_bwrite,
.erase = mmc_berase,
#endif
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 38d2e07dd5..53c819187e 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -22,13 +22,9 @@
#include <div64.h>
#include "mmc_private.h"
-static const unsigned int sd_au_size[] = {
- 0, SZ_16K / 512, SZ_32K / 512,
- SZ_64K / 512, SZ_128K / 512, SZ_256K / 512,
- SZ_512K / 512, SZ_1M / 512, SZ_2M / 512,
- SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512,
- SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512,
-};
+static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
+static int mmc_power_cycle(struct mmc *mmc);
+static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
#if CONFIG_IS_ENABLED(MMC_TINY)
static struct mmc mmc_static;
@@ -54,6 +50,14 @@ struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
#endif
#if !CONFIG_IS_ENABLED(DM_MMC)
+
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
+{
+ return -ENOSYS;
+}
+#endif
+
__weak int board_mmc_getwp(struct mmc *mmc)
{
return -1;
@@ -149,6 +153,71 @@ void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
}
#endif
+#if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
+const char *mmc_mode_name(enum bus_mode mode)
+{
+ static const char *const names[] = {
+ [MMC_LEGACY] = "MMC legacy",
+ [SD_LEGACY] = "SD Legacy",
+ [MMC_HS] = "MMC High Speed (26MHz)",
+ [SD_HS] = "SD High Speed (50MHz)",
+ [UHS_SDR12] = "UHS SDR12 (25MHz)",
+ [UHS_SDR25] = "UHS SDR25 (50MHz)",
+ [UHS_SDR50] = "UHS SDR50 (100MHz)",
+ [UHS_SDR104] = "UHS SDR104 (208MHz)",
+ [UHS_DDR50] = "UHS DDR50 (50MHz)",
+ [MMC_HS_52] = "MMC High Speed (52MHz)",
+ [MMC_DDR_52] = "MMC DDR52 (52MHz)",
+ [MMC_HS_200] = "HS200 (200MHz)",
+ };
+
+ if (mode >= MMC_MODES_END)
+ return "Unknown mode";
+ else
+ return names[mode];
+}
+#endif
+
+static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
+{
+ static const int freqs[] = {
+ [SD_LEGACY] = 25000000,
+ [MMC_HS] = 26000000,
+ [SD_HS] = 50000000,
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ [UHS_SDR12] = 25000000,
+ [UHS_SDR25] = 50000000,
+ [UHS_SDR50] = 100000000,
+ [UHS_DDR50] = 50000000,
+#ifdef MMC_SUPPORTS_TUNING
+ [UHS_SDR104] = 208000000,
+#endif
+#endif
+ [MMC_HS_52] = 52000000,
+ [MMC_DDR_52] = 52000000,
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
+ [MMC_HS_200] = 200000000,
+#endif
+ };
+
+ if (mode == MMC_LEGACY)
+ return mmc->legacy_speed;
+ else if (mode >= MMC_MODES_END)
+ return 0;
+ else
+ return freqs[mode];
+}
+
+static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
+{
+ mmc->selected_mode = mode;
+ mmc->tran_speed = mmc_mode2freq(mmc, mode);
+ mmc->ddr_mode = mmc_is_mode_ddr(mode);
+ debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
+ mmc->tran_speed / 1000000);
+ return 0;
+}
+
#if !CONFIG_IS_ENABLED(DM_MMC)
int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
{
@@ -179,10 +248,11 @@ int mmc_send_status(struct mmc *mmc, int timeout)
(cmd.response[0] & MMC_STATUS_CURR_STATE) !=
MMC_STATE_PRG)
break;
- else if (cmd.response[0] & MMC_STATUS_MASK) {
+
+ if (cmd.response[0] & MMC_STATUS_MASK) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("Status Error: 0x%08X\n",
- cmd.response[0]);
+ pr_err("Status Error: 0x%08X\n",
+ cmd.response[0]);
#endif
return -ECOMM;
}
@@ -198,7 +268,7 @@ int mmc_send_status(struct mmc *mmc, int timeout)
mmc_trace_state(mmc, &cmd);
if (timeout <= 0) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("Timeout waiting card ready\n");
+ pr_err("Timeout waiting card ready\n");
#endif
return -ETIMEDOUT;
}
@@ -209,6 +279,7 @@ int mmc_send_status(struct mmc *mmc, int timeout)
int mmc_set_blocklen(struct mmc *mmc, int len)
{
struct mmc_cmd cmd;
+ int err;
if (mmc->ddr_mode)
return 0;
@@ -217,8 +288,95 @@ int mmc_set_blocklen(struct mmc *mmc, int len)
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = len;
- return mmc_send_cmd(mmc, &cmd, NULL);
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+#ifdef CONFIG_MMC_QUIRKS
+ if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
+ int retries = 4;
+ /*
+ * It has been seen that SET_BLOCKLEN may fail on the first
+ * attempt, let's try a few more time
+ */
+ do {
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (!err)
+ break;
+ } while (retries--);
+ }
+#endif
+
+ return err;
+}
+
+#ifdef MMC_SUPPORTS_TUNING
+static const u8 tuning_blk_pattern_4bit[] = {
+ 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+ 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
+ 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
+ 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
+ 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
+ 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
+ 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
+ 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
+};
+
+static const u8 tuning_blk_pattern_8bit[] = {
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+ 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+ 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+ 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+ 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+ 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+ 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+ 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+ 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+ 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+ 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+ 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+ 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
+};
+
+int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error)
+{
+ struct mmc_cmd cmd;
+ struct mmc_data data;
+ const u8 *tuning_block_pattern;
+ int size, err;
+
+ if (mmc->bus_width == 8) {
+ tuning_block_pattern = tuning_blk_pattern_8bit;
+ size = sizeof(tuning_blk_pattern_8bit);
+ } else if (mmc->bus_width == 4) {
+ tuning_block_pattern = tuning_blk_pattern_4bit;
+ size = sizeof(tuning_blk_pattern_4bit);
+ } else {
+ return -EINVAL;
+ }
+
+ ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size);
+
+ cmd.cmdidx = opcode;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1;
+
+ data.dest = (void *)data_buf;
+ data.blocks = 1;
+ data.blocksize = size;
+ data.flags = MMC_DATA_READ;
+
+ err = mmc_send_cmd(mmc, &cmd, &data);
+ if (err)
+ return err;
+
+ if (memcmp(data_buf, tuning_block_pattern, size))
+ return -EIO;
+
+ return 0;
}
+#endif
static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
lbaint_t blkcnt)
@@ -252,7 +410,7 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
cmd.resp_type = MMC_RSP_R1b;
if (mmc_send_cmd(mmc, &cmd, NULL)) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("mmc fail to send stop cmd\n");
+ pr_err("mmc fail to send stop cmd\n");
#endif
return 0;
}
@@ -292,8 +450,8 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
if ((start + blkcnt) > block_dev->lba) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
- start + blkcnt, block_dev->lba);
+ pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
+ start + blkcnt, block_dev->lba);
#endif
return 0;
}
@@ -339,7 +497,69 @@ static int mmc_go_idle(struct mmc *mmc)
return 0;
}
-static int sd_send_op_cond(struct mmc *mmc)
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
+{
+ struct mmc_cmd cmd;
+ int err = 0;
+
+ /*
+ * Send CMD11 only if the request is to switch the card to
+ * 1.8V signalling.
+ */
+ if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
+ return mmc_set_signal_voltage(mmc, signal_voltage);
+
+ cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err)
+ return err;
+
+ if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
+ return -EIO;
+
+ /*
+ * The card should drive cmd and dat[0:3] low immediately
+ * after the response of cmd11, but wait 100 us to be sure
+ */
+ err = mmc_wait_dat0(mmc, 0, 100);
+ if (err == -ENOSYS)
+ udelay(100);
+ else if (err)
+ return -ETIMEDOUT;
+
+ /*
+ * During a signal voltage level switch, the clock must be gated
+ * for 5 ms according to the SD spec
+ */
+ mmc_set_clock(mmc, mmc->clock, true);
+
+ err = mmc_set_signal_voltage(mmc, signal_voltage);
+ if (err)
+ return err;
+
+ /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
+ mdelay(10);
+ mmc_set_clock(mmc, mmc->clock, false);
+
+ /*
+ * Failure to switch is indicated by the card holding
+ * dat[0:3] low. Wait for at least 1 ms according to spec
+ */
+ err = mmc_wait_dat0(mmc, 1, 1000);
+ if (err == -ENOSYS)
+ udelay(1000);
+ else if (err)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+#endif
+
+static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
{
int timeout = 1000;
int err;
@@ -371,6 +591,9 @@ static int sd_send_op_cond(struct mmc *mmc)
if (mmc->version == SD_VERSION_2)
cmd.cmdarg |= OCR_HCS;
+ if (uhs_en)
+ cmd.cmdarg |= OCR_S18R;
+
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
@@ -401,6 +624,15 @@ static int sd_send_op_cond(struct mmc *mmc)
mmc->ocr = cmd.response[0];
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
+ == 0x41000000) {
+ err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
+ if (err)
+ return err;
+ }
+#endif
+
mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
mmc->rca = 0;
@@ -546,53 +778,86 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
}
-static int mmc_change_freq(struct mmc *mmc)
+static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
{
- ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
- char cardtype;
int err;
+ int speed_bits;
- mmc->card_caps = 0;
+ ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
- if (mmc_host_is_spi(mmc))
- return 0;
+ switch (mode) {
+ case MMC_HS:
+ case MMC_HS_52:
+ case MMC_DDR_52:
+ speed_bits = EXT_CSD_TIMING_HS;
+ break;
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
+ case MMC_HS_200:
+ speed_bits = EXT_CSD_TIMING_HS200;
+ break;
+#endif
+ case MMC_LEGACY:
+ speed_bits = EXT_CSD_TIMING_LEGACY;
+ break;
+ default:
+ return -EINVAL;
+ }
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+ speed_bits);
+ if (err)
+ return err;
- /* Only version 4 supports high-speed */
- if (mmc->version < MMC_VERSION_4)
- return 0;
+ if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
+ /* Now check to see that it worked */
+ err = mmc_send_ext_csd(mmc, test_csd);
+ if (err)
+ return err;
- mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
+ /* No high-speed support */
+ if (!test_csd[EXT_CSD_HS_TIMING])
+ return -ENOTSUPP;
+ }
- err = mmc_send_ext_csd(mmc, ext_csd);
+ return 0;
+}
- if (err)
- return err;
+static int mmc_get_capabilities(struct mmc *mmc)
+{
+ u8 *ext_csd = mmc->ext_csd;
+ char cardtype;
- cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
+ mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
+ if (mmc_host_is_spi(mmc))
+ return 0;
- if (err)
- return err;
+ /* Only version 4 supports high-speed */
+ if (mmc->version < MMC_VERSION_4)
+ return 0;
- /* Now check to see that it worked */
- err = mmc_send_ext_csd(mmc, ext_csd);
+ if (!ext_csd) {
+ pr_err("No ext_csd found!\n"); /* this should enver happen */
+ return -ENOTSUPP;
+ }
- if (err)
- return err;
+ mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
- /* No high-speed support */
- if (!ext_csd[EXT_CSD_HS_TIMING])
- return 0;
+ cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
+ mmc->cardtype = cardtype;
- /* High Speed is set, there are two types: 52MHz and 26MHz */
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
+ if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
+ EXT_CSD_CARD_TYPE_HS200_1_8V)) {
+ mmc->card_caps |= MMC_MODE_HS200;
+ }
+#endif
if (cardtype & EXT_CSD_CARD_TYPE_52) {
- if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
+ if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
mmc->card_caps |= MMC_MODE_DDR_52MHz;
- mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
- } else {
- mmc->card_caps |= MMC_MODE_HS;
+ mmc->card_caps |= MMC_MODE_HS_52MHz;
}
+ if (cardtype & EXT_CSD_CARD_TYPE_26)
+ mmc->card_caps |= MMC_MODE_HS;
return 0;
}
@@ -625,10 +890,46 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num)
return 0;
}
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
+static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
+{
+ int forbidden = 0;
+ bool change = false;
+
+ if (part_num & PART_ACCESS_MASK)
+ forbidden = MMC_CAP(MMC_HS_200);
+
+ if (MMC_CAP(mmc->selected_mode) & forbidden) {
+ debug("selected mode (%s) is forbidden for part %d\n",
+ mmc_mode_name(mmc->selected_mode), part_num);
+ change = true;
+ } else if (mmc->selected_mode != mmc->best_mode) {
+ debug("selected mode is not optimal\n");
+ change = true;
+ }
+
+ if (change)
+ return mmc_select_mode_and_width(mmc,
+ mmc->card_caps & ~forbidden);
+
+ return 0;
+}
+#else
+static inline int mmc_boot_part_access_chk(struct mmc *mmc,
+ unsigned int part_num)
+{
+ return 0;
+}
+#endif
+
int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
{
int ret;
+ ret = mmc_boot_part_access_chk(mmc, part_num);
+ if (ret)
+ return ret;
+
ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
(mmc->part_config & ~PART_ACCESS_MASK)
| (part_num & PART_ACCESS_MASK));
@@ -645,6 +946,7 @@ int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
return ret;
}
+#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
int mmc_hwpart_config(struct mmc *mmc,
const struct mmc_hwpart_conf *conf,
enum mmc_hwpart_conf_mode mode)
@@ -663,17 +965,17 @@ int mmc_hwpart_config(struct mmc *mmc,
return -EINVAL;
if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
- printf("eMMC >= 4.4 required for enhanced user data area\n");
+ pr_err("eMMC >= 4.4 required for enhanced user data area\n");
return -EMEDIUMTYPE;
}
if (!(mmc->part_support & PART_SUPPORT)) {
- printf("Card does not support partitioning\n");
+ pr_err("Card does not support partitioning\n");
return -EMEDIUMTYPE;
}
if (!mmc->hc_wp_grp_size) {
- printf("Card does not define HC WP group size\n");
+ pr_err("Card does not define HC WP group size\n");
return -EMEDIUMTYPE;
}
@@ -681,7 +983,7 @@ int mmc_hwpart_config(struct mmc *mmc,
if (conf->user.enh_size) {
if (conf->user.enh_size % mmc->hc_wp_grp_size ||
conf->user.enh_start % mmc->hc_wp_grp_size) {
- printf("User data enhanced area not HC WP group "
+ pr_err("User data enhanced area not HC WP group "
"size aligned\n");
return -EINVAL;
}
@@ -700,7 +1002,7 @@ int mmc_hwpart_config(struct mmc *mmc,
for (pidx = 0; pidx < 4; pidx++) {
if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
- printf("GP%i partition not HC WP group size "
+ pr_err("GP%i partition not HC WP group size "
"aligned\n", pidx+1);
return -EINVAL;
}
@@ -712,7 +1014,7 @@ int mmc_hwpart_config(struct mmc *mmc,
}
if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
- printf("Card does not support enhanced attribute\n");
+ pr_err("Card does not support enhanced attribute\n");
return -EMEDIUMTYPE;
}
@@ -725,7 +1027,7 @@ int mmc_hwpart_config(struct mmc *mmc,
(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
if (tot_enh_size_mult > max_enh_size_mult) {
- printf("Total enhanced size exceeds maximum (%u > %u)\n",
+ pr_err("Total enhanced size exceeds maximum (%u > %u)\n",
tot_enh_size_mult, max_enh_size_mult);
return -EMEDIUMTYPE;
}
@@ -759,7 +1061,7 @@ int mmc_hwpart_config(struct mmc *mmc,
if (ext_csd[EXT_CSD_PARTITION_SETTING] &
EXT_CSD_PARTITION_SETTING_COMPLETED) {
- printf("Card already partitioned\n");
+ pr_err("Card already partitioned\n");
return -EPERM;
}
@@ -838,6 +1140,7 @@ int mmc_hwpart_config(struct mmc *mmc,
return 0;
}
+#endif
#if !CONFIG_IS_ENABLED(DM_MMC)
int mmc_getcd(struct mmc *mmc)
@@ -878,16 +1181,19 @@ static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
}
-static int sd_change_freq(struct mmc *mmc)
+static int sd_get_capabilities(struct mmc *mmc)
{
int err;
struct mmc_cmd cmd;
- ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
- ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
+ ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
+ ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
struct mmc_data data;
int timeout;
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ u32 sd3_bus_mode;
+#endif
- mmc->card_caps = 0;
+ mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY);
if (mmc_host_is_spi(mmc))
return 0;
@@ -964,32 +1270,115 @@ retry_scr:
}
/* If high-speed isn't supported, we return */
- if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
- return 0;
+ if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
+ mmc->card_caps |= MMC_CAP(SD_HS);
- /*
- * If the host doesn't support SD_HIGHSPEED, do not switch card to
- * HIGHSPEED mode even if the card support SD_HIGHSPPED.
- * This can avoid furthur problem when the card runs in different
- * mode between the host.
- */
- if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
- (mmc->cfg->host_caps & MMC_MODE_HS)))
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ /* Version before 3.0 don't support UHS modes */
+ if (mmc->version < SD_VERSION_3)
return 0;
- err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
+ sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
+ if (sd3_bus_mode & SD_MODE_UHS_SDR104)
+ mmc->card_caps |= MMC_CAP(UHS_SDR104);
+ if (sd3_bus_mode & SD_MODE_UHS_SDR50)
+ mmc->card_caps |= MMC_CAP(UHS_SDR50);
+ if (sd3_bus_mode & SD_MODE_UHS_SDR25)
+ mmc->card_caps |= MMC_CAP(UHS_SDR25);
+ if (sd3_bus_mode & SD_MODE_UHS_SDR12)
+ mmc->card_caps |= MMC_CAP(UHS_SDR12);
+ if (sd3_bus_mode & SD_MODE_UHS_DDR50)
+ mmc->card_caps |= MMC_CAP(UHS_DDR50);
+#endif
+
+ return 0;
+}
+
+static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
+{
+ int err;
+
+ ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
+ int speed;
+
+ switch (mode) {
+ case SD_LEGACY:
+ speed = UHS_SDR12_BUS_SPEED;
+ break;
+ case SD_HS:
+ speed = HIGH_SPEED_BUS_SPEED;
+ break;
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ case UHS_SDR12:
+ speed = UHS_SDR12_BUS_SPEED;
+ break;
+ case UHS_SDR25:
+ speed = UHS_SDR25_BUS_SPEED;
+ break;
+ case UHS_SDR50:
+ speed = UHS_SDR50_BUS_SPEED;
+ break;
+ case UHS_DDR50:
+ speed = UHS_DDR50_BUS_SPEED;
+ break;
+ case UHS_SDR104:
+ speed = UHS_SDR104_BUS_SPEED;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
+ if (err)
+ return err;
+ if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
+ return -ENOTSUPP;
+
+ return 0;
+}
+
+int sd_select_bus_width(struct mmc *mmc, int w)
+{
+ int err;
+ struct mmc_cmd cmd;
+
+ if ((w != 4) && (w != 1))
+ return -EINVAL;
+
+ cmd.cmdidx = MMC_CMD_APP_CMD;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.cmdarg = mmc->rca << 16;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
- if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
- mmc->card_caps |= MMC_MODE_HS;
+ cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
+ cmd.resp_type = MMC_RSP_R1;
+ if (w == 4)
+ cmd.cmdarg = 2;
+ else if (w == 1)
+ cmd.cmdarg = 0;
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err)
+ return err;
return 0;
}
+#if CONFIG_IS_ENABLED(MMC_WRITE)
static int sd_read_ssr(struct mmc *mmc)
{
+ static const unsigned int sd_au_size[] = {
+ 0, SZ_16K / 512, SZ_32K / 512,
+ SZ_64K / 512, SZ_128K / 512, SZ_256K / 512,
+ SZ_512K / 512, SZ_1M / 512, SZ_2M / 512,
+ SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512,
+ SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512,
+ SZ_64M / 512,
+ };
int err, i;
struct mmc_cmd cmd;
ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
@@ -1043,7 +1432,7 @@ retry_ssr:
return 0;
}
-
+#endif
/* frequency bases */
/* divided by 10 to be nice to platforms without floating point */
static const int fbase[] = {
@@ -1075,15 +1464,42 @@ static const u8 multipliers[] = {
80,
};
+static inline int bus_width(uint cap)
+{
+ if (cap == MMC_MODE_8BIT)
+ return 8;
+ if (cap == MMC_MODE_4BIT)
+ return 4;
+ if (cap == MMC_MODE_1BIT)
+ return 1;
+ pr_warn("invalid bus witdh capability 0x%x\n", cap);
+ return 0;
+}
+
#if !CONFIG_IS_ENABLED(DM_MMC)
-static void mmc_set_ios(struct mmc *mmc)
+#ifdef MMC_SUPPORTS_TUNING
+static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
{
+ return -ENOTSUPP;
+}
+#endif
+
+static void mmc_send_init_stream(struct mmc *mmc)
+{
+}
+
+static int mmc_set_ios(struct mmc *mmc)
+{
+ int ret = 0;
+
if (mmc->cfg->ops->set_ios)
- mmc->cfg->ops->set_ios(mmc);
+ ret = mmc->cfg->ops->set_ios(mmc);
+
+ return ret;
}
#endif
-void mmc_set_clock(struct mmc *mmc, uint clock)
+int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
{
if (clock > mmc->cfg->f_max)
clock = mmc->cfg->f_max;
@@ -1092,27 +1508,619 @@ void mmc_set_clock(struct mmc *mmc, uint clock)
clock = mmc->cfg->f_min;
mmc->clock = clock;
+ mmc->clk_disable = disable;
- mmc_set_ios(mmc);
+ return mmc_set_ios(mmc);
}
-static void mmc_set_bus_width(struct mmc *mmc, uint width)
+static int mmc_set_bus_width(struct mmc *mmc, uint width)
{
mmc->bus_width = width;
- mmc_set_ios(mmc);
+ return mmc_set_ios(mmc);
+}
+
+#if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
+/*
+ * helper function to display the capabilities in a human
+ * friendly manner. The capabilities include bus width and
+ * supported modes.
+ */
+void mmc_dump_capabilities(const char *text, uint caps)
+{
+ enum bus_mode mode;
+
+ printf("%s: widths [", text);
+ if (caps & MMC_MODE_8BIT)
+ printf("8, ");
+ if (caps & MMC_MODE_4BIT)
+ printf("4, ");
+ if (caps & MMC_MODE_1BIT)
+ printf("1, ");
+ printf("\b\b] modes [");
+ for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
+ if (MMC_CAP(mode) & caps)
+ printf("%s, ", mmc_mode_name(mode));
+ printf("\b\b]\n");
+}
+#endif
+
+struct mode_width_tuning {
+ enum bus_mode mode;
+ uint widths;
+#ifdef MMC_SUPPORTS_TUNING
+ uint tuning;
+#endif
+};
+
+#if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
+int mmc_voltage_to_mv(enum mmc_voltage voltage)
+{
+ switch (voltage) {
+ case MMC_SIGNAL_VOLTAGE_000: return 0;
+ case MMC_SIGNAL_VOLTAGE_330: return 3300;
+ case MMC_SIGNAL_VOLTAGE_180: return 1800;
+ case MMC_SIGNAL_VOLTAGE_120: return 1200;
+ }
+ return -EINVAL;
+}
+
+static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
+{
+ int err;
+
+ if (mmc->signal_voltage == signal_voltage)
+ return 0;
+
+ mmc->signal_voltage = signal_voltage;
+ err = mmc_set_ios(mmc);
+ if (err)
+ debug("unable to set voltage (err %d)\n", err);
+
+ return err;
+}
+#else
+static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
+{
+ return 0;
+}
+#endif
+
+static const struct mode_width_tuning sd_modes_by_pref[] = {
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+#ifdef MMC_SUPPORTS_TUNING
+ {
+ .mode = UHS_SDR104,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ .tuning = MMC_CMD_SEND_TUNING_BLOCK
+ },
+#endif
+ {
+ .mode = UHS_SDR50,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+ {
+ .mode = UHS_DDR50,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+ {
+ .mode = UHS_SDR25,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+#endif
+ {
+ .mode = SD_HS,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ {
+ .mode = UHS_SDR12,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+#endif
+ {
+ .mode = SD_LEGACY,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ }
+};
+
+#define for_each_sd_mode_by_pref(caps, mwt) \
+ for (mwt = sd_modes_by_pref;\
+ mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
+ mwt++) \
+ if (caps & MMC_CAP(mwt->mode))
+
+static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
+{
+ int err;
+ uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
+ const struct mode_width_tuning *mwt;
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
+#else
+ bool uhs_en = false;
+#endif
+ uint caps;
+
+#ifdef DEBUG
+ mmc_dump_capabilities("sd card", card_caps);
+ mmc_dump_capabilities("host", mmc->host_caps);
+#endif
+
+ /* Restrict card's capabilities by what the host can do */
+ caps = card_caps & mmc->host_caps;
+
+ if (!uhs_en)
+ caps &= ~UHS_CAPS;
+
+ for_each_sd_mode_by_pref(caps, mwt) {
+ uint *w;
+
+ for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
+ if (*w & caps & mwt->widths) {
+ debug("trying mode %s width %d (at %d MHz)\n",
+ mmc_mode_name(mwt->mode),
+ bus_width(*w),
+ mmc_mode2freq(mmc, mwt->mode) / 1000000);
+
+ /* configure the bus width (card + host) */
+ err = sd_select_bus_width(mmc, bus_width(*w));
+ if (err)
+ goto error;
+ mmc_set_bus_width(mmc, bus_width(*w));
+
+ /* configure the bus mode (card) */
+ err = sd_set_card_speed(mmc, mwt->mode);
+ if (err)
+ goto error;
+
+ /* configure the bus mode (host) */
+ mmc_select_mode(mmc, mwt->mode);
+ mmc_set_clock(mmc, mmc->tran_speed, false);
+
+#ifdef MMC_SUPPORTS_TUNING
+ /* execute tuning if needed */
+ if (mwt->tuning && !mmc_host_is_spi(mmc)) {
+ err = mmc_execute_tuning(mmc,
+ mwt->tuning);
+ if (err) {
+ debug("tuning failed\n");
+ goto error;
+ }
+ }
+#endif
+
+#if CONFIG_IS_ENABLED(MMC_WRITE)
+ err = sd_read_ssr(mmc);
+ if (!err)
+ pr_warn("unable to read ssr\n");
+#endif
+ if (!err)
+ return 0;
+
+error:
+ /* revert to a safer bus speed */
+ mmc_select_mode(mmc, SD_LEGACY);
+ mmc_set_clock(mmc, mmc->tran_speed, false);
+ }
+ }
+ }
+
+ printf("unable to select a mode\n");
+ return -ENOTSUPP;
+}
+
+/*
+ * read the compare the part of ext csd that is constant.
+ * This can be used to check that the transfer is working
+ * as expected.
+ */
+static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
+{
+ int err;
+ const u8 *ext_csd = mmc->ext_csd;
+ ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
+
+ if (mmc->version < MMC_VERSION_4)
+ return 0;
+
+ err = mmc_send_ext_csd(mmc, test_csd);
+ if (err)
+ return err;
+
+ /* Only compare read only fields */
+ if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
+ == test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
+ ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
+ == test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
+ ext_csd[EXT_CSD_REV]
+ == test_csd[EXT_CSD_REV] &&
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
+ == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
+ memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+ &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
+ return 0;
+
+ return -EBADMSG;
+}
+
+#if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
+static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
+ uint32_t allowed_mask)
+{
+ u32 card_mask = 0;
+
+ switch (mode) {
+ case MMC_HS_200:
+ if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
+ card_mask |= MMC_SIGNAL_VOLTAGE_180;
+ if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
+ card_mask |= MMC_SIGNAL_VOLTAGE_120;
+ break;
+ case MMC_DDR_52:
+ if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
+ card_mask |= MMC_SIGNAL_VOLTAGE_330 |
+ MMC_SIGNAL_VOLTAGE_180;
+ if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
+ card_mask |= MMC_SIGNAL_VOLTAGE_120;
+ break;
+ default:
+ card_mask |= MMC_SIGNAL_VOLTAGE_330;
+ break;
+ }
+
+ while (card_mask & allowed_mask) {
+ enum mmc_voltage best_match;
+
+ best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
+ if (!mmc_set_signal_voltage(mmc, best_match))
+ return 0;
+
+ allowed_mask &= ~best_match;
+ }
+
+ return -ENOTSUPP;
+}
+#else
+static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
+ uint32_t allowed_mask)
+{
+ return 0;
+}
+#endif
+
+static const struct mode_width_tuning mmc_modes_by_pref[] = {
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
+ {
+ .mode = MMC_HS_200,
+ .widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
+ .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
+ },
+#endif
+ {
+ .mode = MMC_DDR_52,
+ .widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
+ },
+ {
+ .mode = MMC_HS_52,
+ .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+ {
+ .mode = MMC_HS,
+ .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+ {
+ .mode = MMC_LEGACY,
+ .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
+ }
+};
+
+#define for_each_mmc_mode_by_pref(caps, mwt) \
+ for (mwt = mmc_modes_by_pref;\
+ mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
+ mwt++) \
+ if (caps & MMC_CAP(mwt->mode))
+
+static const struct ext_csd_bus_width {
+ uint cap;
+ bool is_ddr;
+ uint ext_csd_bits;
+} ext_csd_bus_width[] = {
+ {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
+ {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
+ {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
+ {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
+ {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
+};
+
+#define for_each_supported_width(caps, ddr, ecbv) \
+ for (ecbv = ext_csd_bus_width;\
+ ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
+ ecbv++) \
+ if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
+
+static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
+{
+ int err;
+ const struct mode_width_tuning *mwt;
+ const struct ext_csd_bus_width *ecbw;
+
+#ifdef DEBUG
+ mmc_dump_capabilities("mmc", card_caps);
+ mmc_dump_capabilities("host", mmc->host_caps);
+#endif
+
+ /* Restrict card's capabilities by what the host can do */
+ card_caps &= mmc->host_caps;
+
+ /* Only version 4 of MMC supports wider bus widths */
+ if (mmc->version < MMC_VERSION_4)
+ return 0;
+
+ if (!mmc->ext_csd) {
+ debug("No ext_csd found!\n"); /* this should enver happen */
+ return -ENOTSUPP;
+ }
+
+ mmc_set_clock(mmc, mmc->legacy_speed, false);
+
+ for_each_mmc_mode_by_pref(card_caps, mwt) {
+ for_each_supported_width(card_caps & mwt->widths,
+ mmc_is_mode_ddr(mwt->mode), ecbw) {
+ enum mmc_voltage old_voltage;
+ debug("trying mode %s width %d (at %d MHz)\n",
+ mmc_mode_name(mwt->mode),
+ bus_width(ecbw->cap),
+ mmc_mode2freq(mmc, mwt->mode) / 1000000);
+ old_voltage = mmc->signal_voltage;
+ err = mmc_set_lowest_voltage(mmc, mwt->mode,
+ MMC_ALL_SIGNAL_VOLTAGE);
+ if (err)
+ continue;
+
+ /* configure the bus width (card + host) */
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
+ if (err)
+ goto error;
+ mmc_set_bus_width(mmc, bus_width(ecbw->cap));
+
+ /* configure the bus speed (card) */
+ err = mmc_set_card_speed(mmc, mwt->mode);
+ if (err)
+ goto error;
+
+ /*
+ * configure the bus width AND the ddr mode (card)
+ * The host side will be taken care of in the next step
+ */
+ if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ ecbw->ext_csd_bits);
+ if (err)
+ goto error;
+ }
+
+ /* configure the bus mode (host) */
+ mmc_select_mode(mmc, mwt->mode);
+ mmc_set_clock(mmc, mmc->tran_speed, false);
+#ifdef MMC_SUPPORTS_TUNING
+
+ /* execute tuning if needed */
+ if (mwt->tuning) {
+ err = mmc_execute_tuning(mmc, mwt->tuning);
+ if (err) {
+ debug("tuning failed\n");
+ goto error;
+ }
+ }
+#endif
+
+ /* do a transfer to check the configuration */
+ err = mmc_read_and_compare_ext_csd(mmc);
+ if (!err)
+ return 0;
+error:
+ mmc_set_signal_voltage(mmc, old_voltage);
+ /* if an error occured, revert to a safer bus mode */
+ mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
+ mmc_select_mode(mmc, MMC_LEGACY);
+ mmc_set_bus_width(mmc, 1);
+ }
+ }
+
+ pr_err("unable to select a mode\n");
+
+ return -ENOTSUPP;
+}
+
+static int mmc_startup_v4(struct mmc *mmc)
+{
+ int err, i;
+ u64 capacity;
+ bool has_parts = false;
+ bool part_completed;
+ static const u32 mmc_versions[] = {
+ MMC_VERSION_4,
+ MMC_VERSION_4_1,
+ MMC_VERSION_4_2,
+ MMC_VERSION_4_3,
+ MMC_VERSION_4_41,
+ MMC_VERSION_4_5,
+ MMC_VERSION_5_0,
+ MMC_VERSION_5_1
+ };
+
+ ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
+
+ if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
+ return 0;
+
+ /* check ext_csd version and capacity */
+ err = mmc_send_ext_csd(mmc, ext_csd);
+ if (err)
+ goto error;
+
+ /* store the ext csd for future reference */
+ if (!mmc->ext_csd)
+ mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN);
+ if (!mmc->ext_csd)
+ return -ENOMEM;
+ memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN);
+
+ if (ext_csd[EXT_CSD_REV] > ARRAY_SIZE(mmc_versions))
+ return -EINVAL;
+
+ mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]];
+
+ if (mmc->version >= MMC_VERSION_4_2) {
+ /*
+ * According to the JEDEC Standard, the value of
+ * ext_csd's capacity is valid if the value is more
+ * than 2GB
+ */
+ capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
+ | ext_csd[EXT_CSD_SEC_CNT + 1] << 8
+ | ext_csd[EXT_CSD_SEC_CNT + 2] << 16
+ | ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+ capacity *= MMC_MAX_BLOCK_LEN;
+ if ((capacity >> 20) > 2 * 1024)
+ mmc->capacity_user = capacity;
+ }
+
+ /* The partition data may be non-zero but it is only
+ * effective if PARTITION_SETTING_COMPLETED is set in
+ * EXT_CSD, so ignore any data if this bit is not set,
+ * except for enabling the high-capacity group size
+ * definition (see below).
+ */
+ part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
+ EXT_CSD_PARTITION_SETTING_COMPLETED);
+
+ /* store the partition info of emmc */
+ mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
+ if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
+ ext_csd[EXT_CSD_BOOT_MULT])
+ mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
+ if (part_completed &&
+ (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
+ mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
+
+ mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
+
+ mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
+
+ for (i = 0; i < 4; i++) {
+ int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
+ uint mult = (ext_csd[idx + 2] << 16) +
+ (ext_csd[idx + 1] << 8) + ext_csd[idx];
+ if (mult)
+ has_parts = true;
+ if (!part_completed)
+ continue;
+ mmc->capacity_gp[i] = mult;
+ mmc->capacity_gp[i] *=
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+ mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+ mmc->capacity_gp[i] <<= 19;
+ }
+
+#ifndef CONFIG_SPL_BUILD
+ if (part_completed) {
+ mmc->enh_user_size =
+ (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
+ (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
+ ext_csd[EXT_CSD_ENH_SIZE_MULT];
+ mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+ mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+ mmc->enh_user_size <<= 19;
+ mmc->enh_user_start =
+ (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
+ (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
+ (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
+ ext_csd[EXT_CSD_ENH_START_ADDR];
+ if (mmc->high_capacity)
+ mmc->enh_user_start <<= 9;
+ }
+#endif
+
+ /*
+ * Host needs to enable ERASE_GRP_DEF bit if device is
+ * partitioned. This bit will be lost every time after a reset
+ * or power off. This will affect erase size.
+ */
+ if (part_completed)
+ has_parts = true;
+ if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
+ (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
+ has_parts = true;
+ if (has_parts) {
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_ERASE_GROUP_DEF, 1);
+
+ if (err)
+ goto error;
+
+ ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+ }
+
+ if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
+#if CONFIG_IS_ENABLED(MMC_WRITE)
+ /* Read out group size from ext_csd */
+ mmc->erase_grp_size =
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
+#endif
+ /*
+ * if high capacity and partition setting completed
+ * SEC_COUNT is valid even if it is smaller than 2 GiB
+ * JEDEC Standard JESD84-B45, 6.2.4
+ */
+ if (mmc->high_capacity && part_completed) {
+ capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
+ (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
+ (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
+ (ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
+ capacity *= MMC_MAX_BLOCK_LEN;
+ mmc->capacity_user = capacity;
+ }
+ }
+#if CONFIG_IS_ENABLED(MMC_WRITE)
+ else {
+ /* Calculate the group size from the csd value. */
+ int erase_gsz, erase_gmul;
+
+ erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
+ erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
+ mmc->erase_grp_size = (erase_gsz + 1)
+ * (erase_gmul + 1);
+ }
+#endif
+#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
+ mmc->hc_wp_grp_size = 1024
+ * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
+ * ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+#endif
+
+ mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
+
+ return 0;
+error:
+ if (mmc->ext_csd) {
+ free(mmc->ext_csd);
+ mmc->ext_csd = NULL;
+ }
+ return err;
}
static int mmc_startup(struct mmc *mmc)
{
int err, i;
uint mult, freq;
- u64 cmult, csize, capacity;
+ u64 cmult, csize;
struct mmc_cmd cmd;
- ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
- ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
- bool has_parts = false;
- bool part_completed;
struct blk_desc *bdesc;
#ifdef CONFIG_MMC_SPI_CRC_ON
@@ -1121,7 +2129,6 @@ static int mmc_startup(struct mmc *mmc)
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 1;
err = mmc_send_cmd(mmc, &cmd, NULL);
-
if (err)
return err;
}
@@ -1135,6 +2142,21 @@ static int mmc_startup(struct mmc *mmc)
err = mmc_send_cmd(mmc, &cmd, NULL);
+#ifdef CONFIG_MMC_QUIRKS
+ if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
+ int retries = 4;
+ /*
+ * It has been seen that SEND_CID may fail on the first
+ * attempt, let's try a few more time
+ */
+ do {
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (!err)
+ break;
+ } while (retries--);
+ }
+#endif
+
if (err)
return err;
@@ -1203,15 +2225,18 @@ static int mmc_startup(struct mmc *mmc)
freq = fbase[(cmd.response[0] & 0x7)];
mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
- mmc->tran_speed = freq * mult;
+ mmc->legacy_speed = freq * mult;
+ mmc_select_mode(mmc, MMC_LEGACY);
mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
+#if CONFIG_IS_ENABLED(MMC_WRITE)
if (IS_SD(mmc))
mmc->write_bl_len = mmc->read_bl_len;
else
mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
+#endif
if (mmc->high_capacity) {
csize = (mmc->csd[1] & 0x3f) << 16
@@ -1233,15 +2258,17 @@ static int mmc_startup(struct mmc *mmc)
if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
+#if CONFIG_IS_ENABLED(MMC_WRITE)
if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
+#endif
if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
cmd.cmdidx = MMC_CMD_SET_DSR;
cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
cmd.resp_type = MMC_RSP_NONE;
if (mmc_send_cmd(mmc, &cmd, NULL))
- printf("MMC: SET_DSR failed\n");
+ pr_warn("MMC: SET_DSR failed\n");
}
/* Select the card, and put it into Transfer Mode */
@@ -1258,299 +2285,42 @@ static int mmc_startup(struct mmc *mmc)
/*
* For SD, its erase group is always one sector
*/
+#if CONFIG_IS_ENABLED(MMC_WRITE)
mmc->erase_grp_size = 1;
+#endif
mmc->part_config = MMCPART_NOAVAILABLE;
- if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
- /* check ext_csd version and capacity */
- err = mmc_send_ext_csd(mmc, ext_csd);
- if (err)
- return err;
- if (ext_csd[EXT_CSD_REV] >= 2) {
- /*
- * According to the JEDEC Standard, the value of
- * ext_csd's capacity is valid if the value is more
- * than 2GB
- */
- capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
- | ext_csd[EXT_CSD_SEC_CNT + 1] << 8
- | ext_csd[EXT_CSD_SEC_CNT + 2] << 16
- | ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
- capacity *= MMC_MAX_BLOCK_LEN;
- if ((capacity >> 20) > 2 * 1024)
- mmc->capacity_user = capacity;
- }
- switch (ext_csd[EXT_CSD_REV]) {
- case 1:
- mmc->version = MMC_VERSION_4_1;
- break;
- case 2:
- mmc->version = MMC_VERSION_4_2;
- break;
- case 3:
- mmc->version = MMC_VERSION_4_3;
- break;
- case 5:
- mmc->version = MMC_VERSION_4_41;
- break;
- case 6:
- mmc->version = MMC_VERSION_4_5;
- break;
- case 7:
- mmc->version = MMC_VERSION_5_0;
- break;
- case 8:
- mmc->version = MMC_VERSION_5_1;
- break;
- }
-
- /* The partition data may be non-zero but it is only
- * effective if PARTITION_SETTING_COMPLETED is set in
- * EXT_CSD, so ignore any data if this bit is not set,
- * except for enabling the high-capacity group size
- * definition (see below). */
- part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
- EXT_CSD_PARTITION_SETTING_COMPLETED);
-
- /* store the partition info of emmc */
- mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
- if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
- ext_csd[EXT_CSD_BOOT_MULT])
- mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
- if (part_completed &&
- (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
- mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
-
- mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
-
- mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
-
- for (i = 0; i < 4; i++) {
- int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
- uint mult = (ext_csd[idx + 2] << 16) +
- (ext_csd[idx + 1] << 8) + ext_csd[idx];
- if (mult)
- has_parts = true;
- if (!part_completed)
- continue;
- mmc->capacity_gp[i] = mult;
- mmc->capacity_gp[i] *=
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
- mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
- mmc->capacity_gp[i] <<= 19;
- }
-
- if (part_completed) {
- mmc->enh_user_size =
- (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
- (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
- ext_csd[EXT_CSD_ENH_SIZE_MULT];
- mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
- mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
- mmc->enh_user_size <<= 19;
- mmc->enh_user_start =
- (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
- (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
- (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
- ext_csd[EXT_CSD_ENH_START_ADDR];
- if (mmc->high_capacity)
- mmc->enh_user_start <<= 9;
- }
-
- /*
- * Host needs to enable ERASE_GRP_DEF bit if device is
- * partitioned. This bit will be lost every time after a reset
- * or power off. This will affect erase size.
- */
- if (part_completed)
- has_parts = true;
- if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
- (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
- has_parts = true;
- if (has_parts) {
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_ERASE_GROUP_DEF, 1);
-
- if (err)
- return err;
- else
- ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
- }
-
- if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
- /* Read out group size from ext_csd */
- mmc->erase_grp_size =
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
- /*
- * if high capacity and partition setting completed
- * SEC_COUNT is valid even if it is smaller than 2 GiB
- * JEDEC Standard JESD84-B45, 6.2.4
- */
- if (mmc->high_capacity && part_completed) {
- capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
- (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
- (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
- (ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
- capacity *= MMC_MAX_BLOCK_LEN;
- mmc->capacity_user = capacity;
- }
- } else {
- /* Calculate the group size from the csd value. */
- int erase_gsz, erase_gmul;
- erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
- erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
- mmc->erase_grp_size = (erase_gsz + 1)
- * (erase_gmul + 1);
- }
-
- mmc->hc_wp_grp_size = 1024
- * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
- * ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
-
- mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
- }
-
- err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
+ err = mmc_startup_v4(mmc);
if (err)
return err;
- if (IS_SD(mmc))
- err = sd_change_freq(mmc);
- else
- err = mmc_change_freq(mmc);
-
+ err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
if (err)
return err;
- /* Restrict card's capabilities by what the host can do */
- mmc->card_caps &= mmc->cfg->host_caps;
-
if (IS_SD(mmc)) {
- if (mmc->card_caps & MMC_MODE_4BIT) {
- cmd.cmdidx = MMC_CMD_APP_CMD;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = mmc->rca << 16;
-
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
-
- cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = 2;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
-
- mmc_set_bus_width(mmc, 4);
- }
-
- err = sd_read_ssr(mmc);
+ err = sd_get_capabilities(mmc);
if (err)
return err;
-
- if (mmc->card_caps & MMC_MODE_HS)
- mmc->tran_speed = 50000000;
- else
- mmc->tran_speed = 25000000;
- } else if (mmc->version >= MMC_VERSION_4) {
- /* Only version 4 of MMC supports wider bus widths */
- int idx;
-
- /* An array of possible bus widths in order of preference */
- static unsigned ext_csd_bits[] = {
- EXT_CSD_DDR_BUS_WIDTH_8,
- EXT_CSD_DDR_BUS_WIDTH_4,
- EXT_CSD_BUS_WIDTH_8,
- EXT_CSD_BUS_WIDTH_4,
- EXT_CSD_BUS_WIDTH_1,
- };
-
- /* An array to map CSD bus widths to host cap bits */
- static unsigned ext_to_hostcaps[] = {
- [EXT_CSD_DDR_BUS_WIDTH_4] =
- MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
- [EXT_CSD_DDR_BUS_WIDTH_8] =
- MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
- [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
- [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
- };
-
- /* An array to map chosen bus width to an integer */
- static unsigned widths[] = {
- 8, 4, 8, 4, 1,
- };
-
- for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
- unsigned int extw = ext_csd_bits[idx];
- unsigned int caps = ext_to_hostcaps[extw];
-
- /*
- * If the bus width is still not changed,
- * don't try to set the default again.
- * Otherwise, recover from switch attempts
- * by switching to 1-bit bus width.
- */
- if (extw == EXT_CSD_BUS_WIDTH_1 &&
- mmc->bus_width == 1) {
- err = 0;
- break;
- }
-
- /*
- * Check to make sure the card and controller support
- * these capabilities
- */
- if ((mmc->card_caps & caps) != caps)
- continue;
-
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH, extw);
-
- if (err)
- continue;
-
- mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
- mmc_set_bus_width(mmc, widths[idx]);
-
- err = mmc_send_ext_csd(mmc, test_csd);
-
- if (err)
- continue;
-
- /* Only compare read only fields */
- if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
- == test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
- ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
- == test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
- ext_csd[EXT_CSD_REV]
- == test_csd[EXT_CSD_REV] &&
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
- == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
- memcmp(&ext_csd[EXT_CSD_SEC_CNT],
- &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
- break;
- else
- err = -EBADMSG;
- }
-
+ err = sd_select_mode_and_width(mmc, mmc->card_caps);
+ } else {
+ err = mmc_get_capabilities(mmc);
if (err)
return err;
-
- if (mmc->card_caps & MMC_MODE_HS) {
- if (mmc->card_caps & MMC_MODE_HS_52MHz)
- mmc->tran_speed = 52000000;
- else
- mmc->tran_speed = 26000000;
- }
+ mmc_select_mode_and_width(mmc, mmc->card_caps);
}
- mmc_set_clock(mmc, mmc->tran_speed);
+ if (err)
+ return err;
+
+ mmc->best_mode = mmc->selected_mode;
/* Fix the block length for DDR mode */
if (mmc->ddr_mode) {
mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
+#if CONFIG_IS_ENABLED(MMC_WRITE)
mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
+#endif
}
/* fill in device description */
@@ -1618,22 +2388,18 @@ __weak void board_mmc_power_init(void)
static int mmc_power_init(struct mmc *mmc)
{
#if CONFIG_IS_ENABLED(DM_MMC)
-#if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD)
- struct udevice *vmmc_supply;
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
int ret;
ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
- &vmmc_supply);
- if (ret) {
+ &mmc->vmmc_supply);
+ if (ret)
debug("%s: No vmmc supply\n", mmc->dev->name);
- return 0;
- }
- ret = regulator_set_enable(vmmc_supply, true);
- if (ret) {
- puts("Error enabling VMMC supply\n");
- return ret;
- }
+ ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
+ &mmc->vqmmc_supply);
+ if (ret)
+ debug("%s: No vqmmc supply\n", mmc->dev->name);
#endif
#else /* !CONFIG_DM_MMC */
/*
@@ -1645,11 +2411,86 @@ static int mmc_power_init(struct mmc *mmc)
return 0;
}
+/*
+ * put the host in the initial state:
+ * - turn on Vdd (card power supply)
+ * - configure the bus width and clock to minimal values
+ */
+static void mmc_set_initial_state(struct mmc *mmc)
+{
+ int err;
+
+ /* First try to set 3.3V. If it fails set to 1.8V */
+ err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
+ if (err != 0)
+ err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
+ if (err != 0)
+ pr_warn("mmc: failed to set signal voltage\n");
+
+ mmc_select_mode(mmc, MMC_LEGACY);
+ mmc_set_bus_width(mmc, 1);
+ mmc_set_clock(mmc, 0, false);
+}
+
+static int mmc_power_on(struct mmc *mmc)
+{
+#if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
+ if (mmc->vmmc_supply) {
+ int ret = regulator_set_enable(mmc->vmmc_supply, true);
+
+ if (ret) {
+ puts("Error enabling VMMC supply\n");
+ return ret;
+ }
+ }
+#endif
+ return 0;
+}
+
+static int mmc_power_off(struct mmc *mmc)
+{
+ mmc_set_clock(mmc, 1, true);
+#if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
+ if (mmc->vmmc_supply) {
+ int ret = regulator_set_enable(mmc->vmmc_supply, false);
+
+ if (ret) {
+ debug("Error disabling VMMC supply\n");
+ return ret;
+ }
+ }
+#endif
+ return 0;
+}
+
+static int mmc_power_cycle(struct mmc *mmc)
+{
+ int ret;
+
+ ret = mmc_power_off(mmc);
+ if (ret)
+ return ret;
+ /*
+ * SD spec recommends at least 1ms of delay. Let's wait for 2ms
+ * to be on the safer side.
+ */
+ udelay(2000);
+ return mmc_power_on(mmc);
+}
+
int mmc_start_init(struct mmc *mmc)
{
bool no_card;
+ bool uhs_en = supports_uhs(mmc->cfg->host_caps);
int err;
+ /*
+ * all hosts are capable of 1 bit bus-width and able to use the legacy
+ * timings.
+ */
+ mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) |
+ MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
+
/* we pretend there's no card when init is NULL */
no_card = mmc_getcd(mmc) == 0;
#if !CONFIG_IS_ENABLED(DM_MMC)
@@ -1673,6 +2514,26 @@ int mmc_start_init(struct mmc *mmc)
if (err)
return err;
+#ifdef CONFIG_MMC_QUIRKS
+ mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
+ MMC_QUIRK_RETRY_SEND_CID;
+#endif
+
+ err = mmc_power_cycle(mmc);
+ if (err) {
+ /*
+ * if power cycling is not supported, we should not try
+ * to use the UHS modes, because we wouldn't be able to
+ * recover from an error during the UHS initialization.
+ */
+ debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
+ uhs_en = false;
+ mmc->host_caps &= ~UHS_CAPS;
+ err = mmc_power_on(mmc);
+ }
+ if (err)
+ return err;
+
#if CONFIG_IS_ENABLED(DM_MMC)
/* The device has already been probed ready for use */
#else
@@ -1682,8 +2543,10 @@ int mmc_start_init(struct mmc *mmc)
return err;
#endif
mmc->ddr_mode = 0;
- mmc_set_bus_width(mmc, 1);
- mmc_set_clock(mmc, 1);
+
+retry:
+ mmc_set_initial_state(mmc);
+ mmc_send_init_stream(mmc);
/* Reset the Card */
err = mmc_go_idle(mmc);
@@ -1698,7 +2561,12 @@ int mmc_start_init(struct mmc *mmc)
err = mmc_send_if_cond(mmc);
/* Now try to get the SD card's operating condition */
- err = sd_send_op_cond(mmc);
+ err = sd_send_op_cond(mmc, uhs_en);
+ if (err && uhs_en) {
+ uhs_en = false;
+ mmc_power_cycle(mmc);
+ goto retry;
+ }
/* If the command timed out, we check for an MMC card */
if (err == -ETIMEDOUT) {
@@ -1706,7 +2574,7 @@ int mmc_start_init(struct mmc *mmc)
if (err) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("Card did not respond to voltage select!\n");
+ pr_err("Card did not respond to voltage select!\n");
#endif
return -EOPNOTSUPP;
}
@@ -1812,7 +2680,7 @@ static int mmc_probe(bd_t *bis)
uclass_foreach_dev(dev, uc) {
ret = device_probe(dev);
if (ret)
- printf("%s - probe failed: %d\n", dev->name, ret);
+ pr_err("%s - probe failed: %d\n", dev->name, ret);
}
return 0;
diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h
index 1290eed590..a9be4b0102 100644
--- a/drivers/mmc/mmc_private.h
+++ b/drivers/mmc/mmc_private.h
@@ -28,7 +28,7 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
void *dst);
#endif
-#if !(defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_SAVEENV))
+#if CONFIG_IS_ENABLED(MMC_WRITE)
#if CONFIG_IS_ENABLED(BLK)
ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
@@ -40,7 +40,7 @@ ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt);
#endif
-#else /* CONFIG_SPL_BUILD and CONFIG_SPL_SAVEENV is not defined */
+#else /* CONFIG_SPL_MMC_WRITE is not defined */
/* declare dummies to reduce code size. */
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index efa43896fc..30443d13a0 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -28,9 +28,9 @@
#include <mmc.h>
#include <part.h>
#include <i2c.h>
-#include <twl4030.h>
-#include <twl6030.h>
+#if defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)
#include <palmas.h>
+#endif
#include <asm/io.h>
#include <asm/arch/mmc_host_def.h>
#if !defined(CONFIG_SOC_KEYSTONE)
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c
index fdb29a5505..8a5d256c11 100644
--- a/drivers/mmc/sandbox_mmc.c
+++ b/drivers/mmc/sandbox_mmc.c
@@ -48,9 +48,12 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
cmd->response[1] = 10 << 16; /* 1 << block_len */
break;
case SD_CMD_SWITCH_FUNC: {
+ if (!data)
+ break;
u32 *resp = (u32 *)data->dest;
-
resp[7] = cpu_to_be32(SD_HIGHSPEED_BUSY);
+ if ((cmd->cmdarg & 0xF) == UHS_SDR12_BUS_SPEED)
+ resp[4] = (cmd->cmdarg & 0xF) << 24;
break;
}
case MMC_CMD_READ_SINGLE_BLOCK:
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 11d1f0c24c..e2ddf5dccd 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -157,7 +157,6 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
/* Timeout unit - ms */
static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT;
- sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;
/* We shouldn't wait for data inihibit for stop commands, even
@@ -181,6 +180,8 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
udelay(1000);
}
+ sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
+
mask = SDHCI_INT_RESPONSE;
if (!(cmd->resp_type & MMC_RSP_PRESENT))
flags = SDHCI_CMD_RESP_NONE;
@@ -201,7 +202,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
flags |= SDHCI_CMD_DATA;
/* Set Transfer mode regarding to data flag */
- if (data != 0) {
+ if (data) {
sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
mode = SDHCI_TRNS_BLK_CNT_EN;
trans_bytes = data->blocks * data->blocksize;
@@ -249,7 +250,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);
#ifdef CONFIG_MMC_SDHCI_SDMA
- if (data != 0) {
+ if (data) {
trans_bytes = ALIGN(trans_bytes, CONFIG_SYS_CACHELINE_SIZE);
flush_cache(start_addr, trans_bytes);
}
diff --git a/drivers/power/power_core.c b/drivers/power/power_core.c
index b72286d429..46840a33e0 100644
--- a/drivers/power/power_core.c
+++ b/drivers/power/power_core.c
@@ -47,36 +47,6 @@ int pmic_set_output(struct pmic *p, u32 reg, int out, int on)
return 0;
}
-static void pmic_show_info(struct pmic *p)
-{
- printf("PMIC: %s\n", p->name);
-}
-
-static int pmic_dump(struct pmic *p)
-{
- int i, ret;
- u32 val;
-
- if (!p) {
- puts("Wrong PMIC name!\n");
- return -ENODEV;
- }
-
- pmic_show_info(p);
- for (i = 0; i < p->number_of_regs; i++) {
- ret = pmic_reg_read(p, i, &val);
- if (ret)
- puts("PMIC: Registers dump failed\n");
-
- if (!(i % 8))
- printf("\n0x%02x: ", i);
-
- printf("%08x ", val);
- }
- puts("\n");
- return 0;
-}
-
struct pmic *pmic_alloc(void)
{
struct pmic *p;
@@ -108,7 +78,33 @@ struct pmic *pmic_get(const char *s)
return NULL;
}
-const char *power_get_interface(int interface)
+#ifndef CONFIG_SPL_BUILD
+static int pmic_dump(struct pmic *p)
+{
+ int i, ret;
+ u32 val;
+
+ if (!p) {
+ puts("Wrong PMIC name!\n");
+ return -ENODEV;
+ }
+
+ printf("PMIC: %s\n", p->name);
+ for (i = 0; i < p->number_of_regs; i++) {
+ ret = pmic_reg_read(p, i, &val);
+ if (ret)
+ puts("PMIC: Registers dump failed\n");
+
+ if (!(i % 8))
+ printf("\n0x%02x: ", i);
+
+ printf("%08x ", val);
+ }
+ puts("\n");
+ return 0;
+}
+
+static const char *power_get_interface(int interface)
{
const char *power_interface[] = {"I2C", "SPI", "|+|-|"};
return power_interface[interface];
@@ -125,7 +121,7 @@ static void pmic_list_names(void)
}
}
-int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
u32 ret, reg, val;
char *cmd, *name;
@@ -221,3 +217,4 @@ U_BOOT_CMD(
"pmic name bat state - write register\n"
"pmic name bat charge - write register\n"
);
+#endif
diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c
index c226913f9e..dd7a1ead11 100644
--- a/drivers/spmi/spmi-msm.c
+++ b/drivers/spmi/spmi-msm.c
@@ -17,6 +17,10 @@
DECLARE_GLOBAL_DATA_PTR;
+/* PMIC Arbiter configuration registers */
+#define PMIC_ARB_VERSION 0x0000
+#define PMIC_ARB_VERSION_V2_MIN 0x20010000
+
#define ARB_CHANNEL_OFFSET(n) (0x4 * (n))
#define SPMI_CH_OFFSET(chnl) ((chnl) * 0x8000)
@@ -148,6 +152,8 @@ static int msm_spmi_probe(struct udevice *dev)
struct udevice *parent = dev->parent;
struct msm_spmi_priv *priv = dev_get_priv(dev);
int node = dev_of_offset(dev);
+ u32 hw_ver;
+ bool is_v1;
int i;
priv->arb_chnl = devfdt_get_addr(dev);
@@ -155,6 +161,12 @@ static int msm_spmi_probe(struct udevice *dev)
dev_of_offset(parent), node, "reg", 1, NULL, false);
priv->spmi_obs = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
dev_of_offset(parent), node, "reg", 2, NULL, false);
+
+ hw_ver = readl(priv->arb_chnl + PMIC_ARB_VERSION - 0x800);
+ is_v1 = (hw_ver < PMIC_ARB_VERSION_V2_MIN);
+
+ dev_dbg(dev, "PMIC Arb Version-%d (0x%x)\n", (is_v1 ? 1 : 2), hw_ver);
+
if (priv->arb_chnl == FDT_ADDR_T_NONE ||
priv->spmi_core == FDT_ADDR_T_NONE ||
priv->spmi_obs == FDT_ADDR_T_NONE)
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index 2e9598e300..000c288eeb 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -8,10 +8,8 @@ obj-$(CONFIG_SYSRESET) += sysreset-uclass.o
obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o
obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o
obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o
-
obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o
obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
-obj-$(CONFIG_ARCH_SNAPDRAGON) += sysreset_snapdragon.o
obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o
obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o
diff --git a/drivers/sysreset/sysreset_snapdragon.c b/drivers/sysreset/sysreset_snapdragon.c
deleted file mode 100644
index 9869813978..0000000000
--- a/drivers/sysreset/sysreset_snapdragon.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Qualcomm APQ8016 reset controller driver
- *
- * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <dm.h>
-#include <errno.h>
-#include <sysreset.h>
-#include <asm/io.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-static int msm_sysreset_request(struct udevice *dev, enum sysreset_t type)
-{
- phys_addr_t addr = devfdt_get_addr(dev);
- if (!addr)
- return -EINVAL;
- writel(0, addr);
- return -EINPROGRESS;
-}
-
-static struct sysreset_ops msm_sysreset_ops = {
- .request = msm_sysreset_request,
-};
-
-static const struct udevice_id msm_sysreset_ids[] = {
- { .compatible = "qcom,pshold" },
- { }
-};
-
-U_BOOT_DRIVER(msm_reset) = {
- .name = "msm_sysreset",
- .id = UCLASS_SYSRESET,
- .of_match = msm_sysreset_ids,
- .ops = &msm_sysreset_ops,
-};
diff --git a/env/Kconfig b/env/Kconfig
index bef6e89bfc..692f8633b8 100644
--- a/env/Kconfig
+++ b/env/Kconfig
@@ -81,6 +81,13 @@ config ENV_IS_IN_FAT
- CONFIG_FAT_WRITE:
This must be enabled. Otherwise it cannot save the environment file.
+config ENV_IS_IN_EXT4
+ bool "Environment is in a EXT4 filesystem"
+ depends on !CHAIN_OF_TRUST
+ select EXT4_WRITE
+ help
+ Define this if you want to use the EXT4 file system for the environment.
+
config ENV_IS_IN_FLASH
bool "Environment in flash memory"
depends on !CHAIN_OF_TRUST
@@ -396,6 +403,38 @@ config ENV_FAT_FILE
It's a string of the FAT file name. This file use to store the
environment.
+config ENV_EXT4_INTERFACE
+ string "Name of the block device for the environment"
+ depends on ENV_IS_IN_EXT4
+ help
+ Define this to a string that is the name of the block device.
+
+config ENV_EXT4_DEVICE_AND_PART
+ string "Device and partition for where to store the environemt in EXT4"
+ depends on ENV_IS_IN_EXT4
+ help
+ Define this to a string to specify the partition of the device. It can
+ be as following:
+
+ "D:P", "D:0", "D", "D:" or "D:auto" (D, P are integers. And P >= 1)
+ - "D:P": device D partition P. Error occurs if device D has no
+ partition table.
+ - "D:0": device D.
+ - "D" or "D:": device D partition 1 if device D has partition
+ table, or the whole device D if has no partition
+ table.
+ - "D:auto": first partition in device D with bootable flag set.
+ If none, first valid partition in device D. If no
+ partition table then means device D.
+
+config ENV_EXT4_FILE
+ string "Name of the EXT4 file to use for the environemnt"
+ depends on ENV_IS_IN_EXT4
+ default "uboot.env"
+ help
+ It's a string of the EXT4 file name. This file use to store the
+ environment (explicit path to the file)
+
if ARCH_SUNXI
config ENV_OFFSET
diff --git a/env/env.c b/env/env.c
index 76a5608628..7455632fd3 100644
--- a/env/env.c
+++ b/env/env.c
@@ -32,6 +32,8 @@ static enum env_location env_get_default_location(void)
return ENVL_EEPROM;
else if IS_ENABLED(CONFIG_ENV_IS_IN_FAT)
return ENVL_FAT;
+ else if IS_ENABLED(CONFIG_ENV_IS_IN_EXT4)
+ return ENVL_EXT4;
else if IS_ENABLED(CONFIG_ENV_IS_IN_FLASH)
return ENVL_FLASH;
else if IS_ENABLED(CONFIG_ENV_IS_IN_MMC)
diff --git a/env/ext4.c b/env/ext4.c
index 65202213d3..9cdf28e79f 100644
--- a/env/ext4.c
+++ b/env/ext4.c
@@ -46,9 +46,9 @@ static int env_ext4_save(void)
if (err)
return err;
- part = blk_get_device_part_str(EXT4_ENV_INTERFACE,
- EXT4_ENV_DEVICE_AND_PART,
- &dev_desc, &info, 1);
+ part = blk_get_device_part_str(CONFIG_ENV_EXT4_INTERFACE,
+ CONFIG_ENV_EXT4_DEVICE_AND_PART,
+ &dev_desc, &info, 1);
if (part < 0)
return 1;
@@ -57,16 +57,19 @@ static int env_ext4_save(void)
if (!ext4fs_mount(info.size)) {
printf("\n** Unable to use %s %s for saveenv **\n",
- EXT4_ENV_INTERFACE, EXT4_ENV_DEVICE_AND_PART);
+ CONFIG_ENV_EXT4_INTERFACE,
+ CONFIG_ENV_EXT4_DEVICE_AND_PART);
return 1;
}
- err = ext4fs_write(EXT4_ENV_FILE, (void *)&env_new, sizeof(env_t));
+ err = ext4fs_write(CONFIG_ENV_EXT4_FILE, (void *)&env_new,
+ sizeof(env_t));
ext4fs_close();
if (err == -1) {
printf("\n** Unable to write \"%s\" from %s%d:%d **\n",
- EXT4_ENV_FILE, EXT4_ENV_INTERFACE, dev, part);
+ CONFIG_ENV_EXT4_FILE, CONFIG_ENV_EXT4_INTERFACE, dev,
+ part);
return 1;
}
@@ -84,9 +87,9 @@ static int env_ext4_load(void)
int err;
loff_t off;
- part = blk_get_device_part_str(EXT4_ENV_INTERFACE,
- EXT4_ENV_DEVICE_AND_PART,
- &dev_desc, &info, 1);
+ part = blk_get_device_part_str(CONFIG_ENV_EXT4_INTERFACE,
+ CONFIG_ENV_EXT4_DEVICE_AND_PART,
+ &dev_desc, &info, 1);
if (part < 0)
goto err_env_relocate;
@@ -95,16 +98,19 @@ static int env_ext4_load(void)
if (!ext4fs_mount(info.size)) {
printf("\n** Unable to use %s %s for loading the env **\n",
- EXT4_ENV_INTERFACE, EXT4_ENV_DEVICE_AND_PART);
+ CONFIG_ENV_EXT4_INTERFACE,
+ CONFIG_ENV_EXT4_DEVICE_AND_PART);
goto err_env_relocate;
}
- err = ext4_read_file(EXT4_ENV_FILE, buf, 0, CONFIG_ENV_SIZE, &off);
+ err = ext4_read_file(CONFIG_ENV_EXT4_FILE, buf, 0, CONFIG_ENV_SIZE,
+ &off);
ext4fs_close();
if (err == -1) {
printf("\n** Unable to read \"%s\" from %s%d:%d **\n",
- EXT4_ENV_FILE, EXT4_ENV_INTERFACE, dev, part);
+ CONFIG_ENV_EXT4_FILE, CONFIG_ENV_EXT4_INTERFACE, dev,
+ part);
goto err_env_relocate;
}
diff --git a/examples/standalone/riscv.lds b/examples/standalone/riscv.lds
new file mode 100644
index 0000000000..7d8c482250
--- /dev/null
+++ b/examples/standalone/riscv.lds
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+SECTIONS
+{
+ . = ALIGN(4);
+ .text :
+ {
+ *(.text)
+ }
+
+ . = ALIGN(4);
+ .data : {
+ __global_pointer$ = . + 0x800;
+ *(.data)
+ }
+
+ . = ALIGN(4);
+
+ .got : {
+ __got_start = .;
+ *(.got)
+ __got_end = .;
+ }
+
+ . = ALIGN(4);
+ __bss_start = .;
+ .bss : { *(.bss) }
+ __bss_end = .;
+
+ . = ALIGN(4);
+ .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+
+ _end = .;
+}
diff --git a/examples/standalone/stubs.c b/examples/standalone/stubs.c
index 9c7a8c00f8..fadde669fa 100644
--- a/examples/standalone/stubs.c
+++ b/examples/standalone/stubs.c
@@ -172,6 +172,18 @@ gd_t *global_data;
" lwi $r16, [$r16 + (%1)]\n" \
" jr $r16\n" \
: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "$r16");
+#elif defined(CONFIG_RISCV)
+/*
+ * t7 holds the pointer to the global_data. gp is call clobbered.
+ */
+#define EXPORT_FUNC(f, a, x, ...) \
+ asm volatile ( \
+" .globl " #x "\n" \
+#x ":\n" \
+" lw x19, %0(gp)\n" \
+" lw x19, %1(x19)\n" \
+" jr x19\n" \
+ : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "x19");
#elif defined(CONFIG_ARC)
/*
* r25 holds the pointer to the global_data. r10 is call clobbered.
diff --git a/include/configs/dragonboard410c.h b/include/configs/dragonboard410c.h
index d2447b27d8..530d667da8 100644
--- a/include/configs/dragonboard410c.h
+++ b/include/configs/dragonboard410c.h
@@ -23,7 +23,7 @@
#define CONFIG_SYS_TEXT_BASE 0x80080000
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x80000)
-#define CONFIG_SYS_BOOTM_LEN 0x1000000 /* 16MB max kernel size */
+#define CONFIG_SYS_BOOTM_LEN SZ_64M
/* UART */
@@ -92,7 +92,7 @@ REFLASH(dragonboard/u-boot.img, 8)\
"initrd_high=0xffffffffffffffff\0" \
"linux_image=Image\0" \
"kernel_addr_r=0x81000000\0"\
- "fdtfile=apq8016-sbc.dtb\0" \
+ "fdtfile=qcom/apq8016-sbc.dtb\0" \
"fdt_addr_r=0x83000000\0"\
"ramdisk_addr_r=0x84000000\0"\
"scriptaddr=0x90000000\0"\
diff --git a/include/configs/dragonboard820c.h b/include/configs/dragonboard820c.h
new file mode 100644
index 0000000000..010bc44b33
--- /dev/null
+++ b/include/configs/dragonboard820c.h
@@ -0,0 +1,74 @@
+/*
+ * Board configuration file for Dragonboard 410C
+ *
+ * (C) Copyright 2017 Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIGS_DRAGONBOARD820C_H
+#define __CONFIGS_DRAGONBOARD820C_H
+
+#include <linux/sizes.h>
+#include <asm/arch/sysmap-apq8096.h>
+
+#define CONFIG_MISC_INIT_R /* To stop autoboot */
+
+/* Physical Memory Map */
+#define CONFIG_NR_DRAM_BANKS 2
+
+#define PHYS_SDRAM_SIZE 0xC0000000
+#define PHYS_SDRAM_1 0x80000000
+#define PHYS_SDRAM_1_SIZE 0x60000000
+#define PHYS_SDRAM_2 0x100000000
+#define PHYS_SDRAM_2_SIZE 0x5ea4ffff
+
+#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
+#define CONFIG_SYS_TEXT_BASE 0x80080000
+#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
+#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x80000)
+#define CONFIG_SYS_BOOTM_LEN SZ_64M
+#define CONFIG_SYS_LDSCRIPT "board/qualcomm/dragonboard820c/u-boot.lds"
+
+/* Generic Timer Definitions */
+#define COUNTER_FREQUENCY 19000000
+
+/* Partition table support */
+#define HAVE_BLOCK_DEVICE
+
+/* BOOTP options */
+#define CONFIG_BOOTP_BOOTFILESIZE
+
+#ifndef CONFIG_SPL_BUILD
+#include <config_distro_defaults.h>
+#include <config_distro_bootcmd.h>
+#endif
+
+#define BOOT_TARGET_DEVICES(func) \
+ func(MMC, mmc, 0)
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "loadaddr=0x95000000\0" \
+ "fdt_high=0xffffffffffffffff\0" \
+ "initrd_high=0xffffffffffffffff\0" \
+ "linux_image=uImage\0" \
+ "kernel_addr_r=0x95000000\0"\
+ "fdtfile=qcom/apq8096-db820c.dtb\0" \
+ "fdt_addr_r=0x93000000\0"\
+ "ramdisk_addr_r=0x91000000\0"\
+ "scriptaddr=0x90000000\0"\
+ "pxefile_addr_r=0x90100000\0"\
+ BOOTENV
+
+#define CONFIG_EXT4_WRITE
+#define CONFIG_ENV_SIZE 0x4000
+#define CONFIG_ENV_VARS_UBOOT_CONFIG
+
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + SZ_8M)
+
+/* Monitor Command Prompt */
+#define CONFIG_SYS_CBSIZE 512
+#define CONFIG_SYS_MAXARGS 64
+
+#endif
diff --git a/include/configs/nx25-ae250.h b/include/configs/nx25-ae250.h
new file mode 100644
index 0000000000..b5237972c9
--- /dev/null
+++ b/include/configs/nx25-ae250.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * CPU and Board Configuration Options
+ */
+#define CONFIG_SKIP_LOWLEVEL_INIT
+
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_BOOTP_SEND_HOSTNAME
+#define CONFIG_BOOTP_SERVERIP
+
+#ifdef CONFIG_SKIP_LOWLEVEL_INIT
+#define CONFIG_SYS_TEXT_BASE 0x00000000
+#ifdef CONFIG_OF_CONTROL
+#undef CONFIG_OF_SEPARATE
+#define CONFIG_OF_EMBED
+#endif
+#else
+#define CONFIG_SYS_TEXT_BASE 0x80000000
+#endif
+
+/*
+ * Miscellaneous configurable options
+ */
+#define CONFIG_SYS_LONGHELP /* undef to save memory */
+#define CONFIG_SYS_CBSIZE 1024 /* Console I/O Buffer Size */
+
+/*
+ * Print Buffer Size
+ */
+#define CONFIG_SYS_PBSIZE \
+ (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * max number of command args
+ */
+#define CONFIG_SYS_MAXARGS 16
+
+/*
+ * Boot Argument Buffer Size
+ */
+#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
+
+/*
+ * Size of malloc() pool
+ * 512kB is suggested, (CONFIG_ENV_SIZE + 128 * 1024) was not enough
+ */
+#define CONFIG_SYS_MALLOC_LEN (512 << 10)
+
+/*
+ * Physical Memory Map
+ */
+#define CONFIG_NR_DRAM_BANKS 2
+#define PHYS_SDRAM_0 0x00000000 /* SDRAM Bank #1 */
+#define PHYS_SDRAM_1 \
+ (PHYS_SDRAM_0 + PHYS_SDRAM_0_SIZE) /* SDRAM Bank #2 */
+#define PHYS_SDRAM_0_SIZE 0x20000000 /* 512 MB */
+#define PHYS_SDRAM_1_SIZE 0x20000000 /* 512 MB */
+#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_0
+
+/*
+ * Serial console configuration
+ */
+#define CONFIG_CONS_INDEX 1
+#define CONFIG_SYS_NS16550_SERIAL
+#ifndef CONFIG_DM_SERIAL
+#define CONFIG_SYS_NS16550_REG_SIZE -4
+#endif
+#define CONFIG_SYS_NS16550_CLK 19660800
+
+/*
+ * SD (MMC) controller
+ */
+#define CONFIG_FTSDC010_NUMBER 1
+#define CONFIG_FTSDC010_SDIO
+
+/* Init Stack Pointer */
+#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000000 - \
+ GENERATED_GBL_DATA_SIZE)
+
+/*
+ * Load address and memory test area should agree with
+ * arch/riscv/config.mk. Be careful not to overwrite U-Boot itself.
+ */
+#define CONFIG_SYS_LOAD_ADDR 0x100000 /* SDRAM */
+
+/*
+ * memtest works on 512 MB in DRAM
+ */
+#define CONFIG_SYS_MEMTEST_START PHYS_SDRAM_0
+#define CONFIG_SYS_MEMTEST_END (PHYS_SDRAM_0 + PHYS_SDRAM_0_SIZE)
+
+/* environments */
+#define CONFIG_ENV_SPI_BUS 0
+#define CONFIG_ENV_SPI_CS 0
+#define CONFIG_ENV_SPI_MAX_HZ 50000000
+#define CONFIG_ENV_SPI_MODE 0
+#define CONFIG_ENV_SECT_SIZE 0x1000
+#define CONFIG_ENV_OVERWRITE
+
+/* SPI FLASH */
+#define CONFIG_SF_DEFAULT_BUS 0
+#define CONFIG_SF_DEFAULT_CS 0
+#define CONFIG_SF_DEFAULT_SPEED 1000000
+#define CONFIG_SF_DEFAULT_MODE 0
+
+/*
+ * For booting Linux, the board info and command line data
+ * have to be in the first 16 MB of memory, since this is
+ * the maximum mapped by the Linux kernel during initialization.
+ */
+
+/* Initial Memory map for Linux*/
+#define CONFIG_SYS_BOOTMAPSZ (64 << 20)
+/* Increase max gunzip size */
+#define CONFIG_SYS_BOOTM_LEN (64 << 20)
+
+#endif /* __CONFIG_H */
diff --git a/include/configs/p2771-0000.h b/include/configs/p2771-0000.h
index 564069a665..29940a63de 100644
--- a/include/configs/p2771-0000.h
+++ b/include/configs/p2771-0000.h
@@ -24,9 +24,32 @@
/* PCI host support */
+#define BOARD_EXTRA_ENV_SETTINGS \
+ "calculated_vars=kernel_addr_r fdt_addr_r scriptaddr pxefile_addr_r " \
+ "ramdisk_addr_r\0" \
+ "kernel_addr_r_align=00200000\0" \
+ "kernel_addr_r_offset=00080000\0" \
+ "kernel_addr_r_size=02000000\0" \
+ "kernel_addr_r_aliases=loadaddr\0" \
+ "fdt_addr_r_align=00200000\0" \
+ "fdt_addr_r_offset=00000000\0" \
+ "fdt_addr_r_size=00200000\0" \
+ "scriptaddr_align=00200000\0" \
+ "scriptaddr_offset=00000000\0" \
+ "scriptaddr_size=00200000\0" \
+ "pxefile_addr_r_align=00200000\0" \
+ "pxefile_addr_r_offset=00000000\0" \
+ "pxefile_addr_r_size=00200000\0" \
+ "ramdisk_addr_r_align=00200000\0" \
+ "ramdisk_addr_r_offset=00000000\0" \
+ "ramdisk_addr_r_size=02000000\0"
+
#include "tegra-common-post.h"
/* Crystal is 38.4MHz. clk_m runs at half that rate */
#define COUNTER_FREQUENCY 19200000
+#undef CONFIG_NR_DRAM_BANKS
+#define CONFIG_NR_DRAM_BANKS (1024 + 2)
+
#endif
diff --git a/include/configs/poplar.h b/include/configs/poplar.h
index 1c39ed153f..8a12b526a8 100644
--- a/include/configs/poplar.h
+++ b/include/configs/poplar.h
@@ -18,7 +18,7 @@
#define CONFIG_NR_DRAM_BANKS 2
/* SYS */
-#define CONFIG_SYS_BOOTM_LEN 0x1400000
+#define CONFIG_SYS_BOOTM_LEN SZ_64M
#define CONFIG_SYS_INIT_SP_ADDR 0x200000
#define CONFIG_SYS_LOAD_ADDR 0x800000
#define CONFIG_SYS_MALLOC_LEN SZ_32M
diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h
index 3cdd9741b2..2d98a6fa64 100644
--- a/include/configs/tegra-common.h
+++ b/include/configs/tegra-common.h
@@ -78,17 +78,21 @@
#define CONFIG_SYS_BOOTMAPSZ (256 << 20) /* 256M */
+#ifndef CONFIG_ARM64
#define CONFIG_SYS_INIT_RAM_ADDR CONFIG_STACKBASE
#define CONFIG_SYS_INIT_RAM_SIZE CONFIG_SYS_MALLOC_LEN
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \
CONFIG_SYS_INIT_RAM_SIZE - \
GENERATED_GBL_DATA_SIZE)
+#endif
+#ifndef CONFIG_ARM64
/* Defines for SPL */
#define CONFIG_SPL_FRAMEWORK
#define CONFIG_SPL_MAX_FOOTPRINT (CONFIG_SYS_TEXT_BASE - \
CONFIG_SPL_TEXT_BASE)
#define CONFIG_SYS_SPL_MALLOC_SIZE 0x00010000
+#endif
/* Misc utility code */
#define CONFIG_BOUNCE_BUFFER
diff --git a/include/configs/tegra186-common.h b/include/configs/tegra186-common.h
index 98e4fc2d25..1c8772a117 100644
--- a/include/configs/tegra186-common.h
+++ b/include/configs/tegra186-common.h
@@ -14,11 +14,6 @@
*/
#define V_NS16550_CLK 408000000 /* 408MHz (pllp_out0) */
-/*
- * Miscellaneous configurable options
- */
-#define CONFIG_STACKBASE 0x82800000 /* 40MB */
-
/*-----------------------------------------------------------------------
* Physical Memory Map
*/
@@ -60,9 +55,4 @@
"fdt_addr_r=0x82000000\0" \
"ramdisk_addr_r=0x82100000\0"
-/* Defines for SPL */
-#define CONFIG_SPL_TEXT_BASE 0x80108000
-#define CONFIG_SYS_SPL_MALLOC_START 0x80090000
-#define CONFIG_SPL_STACK 0x800ffffc
-
#endif
diff --git a/include/configs/tegra210-common.h b/include/configs/tegra210-common.h
index 4c05576a90..35735f3b78 100644
--- a/include/configs/tegra210-common.h
+++ b/include/configs/tegra210-common.h
@@ -15,11 +15,6 @@
*/
#define V_NS16550_CLK 408000000 /* 408MHz (pllp_out0) */
-/*
- * Miscellaneous configurable options
- */
-#define CONFIG_STACKBASE 0x82800000 /* 40MB */
-
/*-----------------------------------------------------------------------
* Physical Memory Map
*/
@@ -60,11 +55,6 @@
"fdt_addr_r=0x82000000\0" \
"ramdisk_addr_r=0x82100000\0"
-/* Defines for SPL */
-#define CONFIG_SPL_TEXT_BASE 0x80108000
-#define CONFIG_SYS_SPL_MALLOC_START 0x80090000
-#define CONFIG_SPL_STACK 0x800ffffc
-
/* For USB EHCI controller */
#define CONFIG_EHCI_IS_TDI
#define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10
diff --git a/include/elf.h b/include/elf.h
index aaecac799e..fe2128f378 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -613,6 +613,11 @@ unsigned long elf_hash(const unsigned char *name);
#define R_AARCH64_NONE 0 /* No relocation. */
#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */
+/* RISC-V relocations */
+#define R_RISCV_32 1
+#define R_RISCV_64 2
+#define R_RISCV_RELATIVE 3
+
#ifndef __ASSEMBLER__
int valid_elf_image(unsigned long addr);
#endif
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 0fb3e07212..4afb9ac501 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -990,7 +990,8 @@ int fdtdec_setup(void);
/**
* Board-specific FDT initialization. Returns the address to a device tree blob.
- * Called when CONFIG_OF_BOARD is defined.
+ * Called when CONFIG_OF_BOARD is defined, or if CONFIG_OF_SEPARATE is defined
+ * and the board implements it.
*/
void *board_fdt_blob_setup(void);
diff --git a/include/image.h b/include/image.h
index a128a623e5..a41a8369c6 100644
--- a/include/image.h
+++ b/include/image.h
@@ -190,6 +190,7 @@ enum {
IH_ARCH_ARC, /* Synopsys DesignWare ARC */
IH_ARCH_X86_64, /* AMD x86_64, Intel and Via */
IH_ARCH_XTENSA, /* Xtensa */
+ IH_ARCH_RISCV, /* RISC-V */
IH_ARCH_COUNT,
};
diff --git a/include/mmc.h b/include/mmc.h
index 010ebe048c..a46eaed746 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -15,6 +15,13 @@
#include <linux/compiler.h>
#include <part.h>
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
+#define MMC_SUPPORTS_TUNING
+#endif
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+#define MMC_SUPPORTS_TUNING
+#endif
+
/* SD/MMC version bits; 8 flags, 8 major, 8 minor, 8 change */
#define SD_VERSION_SD (1U << 31)
#define MMC_VERSION_MMC (1U << 30)
@@ -52,12 +59,17 @@
#define MMC_VERSION_5_0 MAKE_MMC_VERSION(5, 0, 0)
#define MMC_VERSION_5_1 MAKE_MMC_VERSION(5, 1, 0)
-#define MMC_MODE_HS (1 << 0)
-#define MMC_MODE_HS_52MHz (1 << 1)
-#define MMC_MODE_4BIT (1 << 2)
-#define MMC_MODE_8BIT (1 << 3)
-#define MMC_MODE_SPI (1 << 4)
-#define MMC_MODE_DDR_52MHz (1 << 5)
+#define MMC_CAP(mode) (1 << mode)
+#define MMC_MODE_HS (MMC_CAP(MMC_HS) | MMC_CAP(SD_HS))
+#define MMC_MODE_HS_52MHz MMC_CAP(MMC_HS_52)
+#define MMC_MODE_DDR_52MHz MMC_CAP(MMC_DDR_52)
+#define MMC_MODE_HS200 MMC_CAP(MMC_HS_200)
+
+#define MMC_MODE_8BIT BIT(30)
+#define MMC_MODE_4BIT BIT(29)
+#define MMC_MODE_1BIT BIT(28)
+#define MMC_MODE_SPI BIT(27)
+
#define SD_DATA_4BIT 0x00040000
@@ -82,6 +94,8 @@
#define MMC_CMD_SET_BLOCKLEN 16
#define MMC_CMD_READ_SINGLE_BLOCK 17
#define MMC_CMD_READ_MULTIPLE_BLOCK 18
+#define MMC_CMD_SEND_TUNING_BLOCK 19
+#define MMC_CMD_SEND_TUNING_BLOCK_HS200 21
#define MMC_CMD_SET_BLOCK_COUNT 23
#define MMC_CMD_WRITE_SINGLE_BLOCK 24
#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
@@ -109,12 +123,34 @@
#define SD_CMD_APP_SEND_OP_COND 41
#define SD_CMD_APP_SEND_SCR 51
+static inline bool mmc_is_tuning_cmd(uint cmdidx)
+{
+ if ((cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) ||
+ (cmdidx == MMC_CMD_SEND_TUNING_BLOCK))
+ return true;
+ return false;
+}
+
/* SCR definitions in different words */
#define SD_HIGHSPEED_BUSY 0x00020000
#define SD_HIGHSPEED_SUPPORTED 0x00020000
+#define UHS_SDR12_BUS_SPEED 0
+#define HIGH_SPEED_BUS_SPEED 1
+#define UHS_SDR25_BUS_SPEED 1
+#define UHS_SDR50_BUS_SPEED 2
+#define UHS_SDR104_BUS_SPEED 3
+#define UHS_DDR50_BUS_SPEED 4
+
+#define SD_MODE_UHS_SDR12 BIT(UHS_SDR12_BUS_SPEED)
+#define SD_MODE_UHS_SDR25 BIT(UHS_SDR25_BUS_SPEED)
+#define SD_MODE_UHS_SDR50 BIT(UHS_SDR50_BUS_SPEED)
+#define SD_MODE_UHS_SDR104 BIT(UHS_SDR104_BUS_SPEED)
+#define SD_MODE_UHS_DDR50 BIT(UHS_DDR50_BUS_SPEED)
+
#define OCR_BUSY 0x80000000
#define OCR_HCS 0x40000000
+#define OCR_S18R 0x1000000
#define OCR_VOLTAGE_MASK 0x007FFF80
#define OCR_ACCESS_MODE 0x60000000
@@ -206,11 +242,23 @@
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V)
+#define EXT_CSD_CARD_TYPE_HS200_1_8V BIT(4) /* Card can run at 200MHz */
+ /* SDR mode @1.8V I/O */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V BIT(5) /* Card can run at 200MHz */
+ /* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
+ EXT_CSD_CARD_TYPE_HS200_1_2V)
+
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
+#define EXT_CSD_DDR_FLAG BIT(2) /* Flag for DDR mode */
+
+#define EXT_CSD_TIMING_LEGACY 0 /* no high speed */
+#define EXT_CSD_TIMING_HS 1 /* HS */
+#define EXT_CSD_TIMING_HS200 2 /* HS200 */
#define EXT_CSD_BOOT_ACK_ENABLE (1 << 6)
#define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3)
@@ -265,6 +313,20 @@
#define ENHNCD_SUPPORT (0x2)
#define PART_ENH_ATTRIB (0x1f)
+#define MMC_QUIRK_RETRY_SEND_CID BIT(0)
+#define MMC_QUIRK_RETRY_SET_BLOCKLEN BIT(1)
+
+enum mmc_voltage {
+ MMC_SIGNAL_VOLTAGE_000 = 0,
+ MMC_SIGNAL_VOLTAGE_120 = 1,
+ MMC_SIGNAL_VOLTAGE_180 = 2,
+ MMC_SIGNAL_VOLTAGE_330 = 4,
+};
+
+#define MMC_ALL_SIGNAL_VOLTAGE (MMC_SIGNAL_VOLTAGE_120 |\
+ MMC_SIGNAL_VOLTAGE_180 |\
+ MMC_SIGNAL_VOLTAGE_330)
+
/* Maximum block size for MMC */
#define MMC_MAX_BLOCK_LEN 512
@@ -347,6 +409,14 @@ struct dm_mmc_ops {
int (*set_ios)(struct udevice *dev);
/**
+ * send_init_stream() - send the initialization stream: 74 clock cycles
+ * This is used after power up before sending the first command
+ *
+ * @dev: Device to update
+ */
+ void (*send_init_stream)(struct udevice *dev);
+
+ /**
* get_cd() - See whether a card is present
*
* @dev: Device to check
@@ -361,6 +431,30 @@ struct dm_mmc_ops {
* @return 0 if write-enabled, 1 if write-protected, -ve on error
*/
int (*get_wp)(struct udevice *dev);
+
+#ifdef MMC_SUPPORTS_TUNING
+ /**
+ * execute_tuning() - Start the tuning process
+ *
+ * @dev: Device to start the tuning
+ * @opcode: Command opcode to send
+ * @return 0 if OK, -ve on error
+ */
+ int (*execute_tuning)(struct udevice *dev, uint opcode);
+#endif
+
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ /**
+ * wait_dat0() - wait until dat0 is in the target state
+ * (CLK must be running during the wait)
+ *
+ * @dev: Device to check
+ * @state: target state
+ * @timeout: timeout in us
+ * @return 0 if dat0 is in the target state, -ve on error
+ */
+ int (*wait_dat0)(struct udevice *dev, int state, int timeout);
+#endif
};
#define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops)
@@ -368,13 +462,19 @@ struct dm_mmc_ops {
int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data);
int dm_mmc_set_ios(struct udevice *dev);
+void dm_mmc_send_init_stream(struct udevice *dev);
int dm_mmc_get_cd(struct udevice *dev);
int dm_mmc_get_wp(struct udevice *dev);
+int dm_mmc_execute_tuning(struct udevice *dev, uint opcode);
+int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout);
/* Transition functions for compatibility */
int mmc_set_ios(struct mmc *mmc);
+void mmc_send_init_stream(struct mmc *mmc);
int mmc_getcd(struct mmc *mmc);
int mmc_getwp(struct mmc *mmc);
+int mmc_execute_tuning(struct mmc *mmc, uint opcode);
+int mmc_wait_dat0(struct mmc *mmc, int state, int timeout);
#else
struct mmc_ops {
@@ -406,6 +506,50 @@ struct sd_ssr {
unsigned int erase_offset; /* In milliseconds */
};
+enum bus_mode {
+ MMC_LEGACY,
+ SD_LEGACY,
+ MMC_HS,
+ SD_HS,
+ MMC_HS_52,
+ MMC_DDR_52,
+ UHS_SDR12,
+ UHS_SDR25,
+ UHS_SDR50,
+ UHS_DDR50,
+ UHS_SDR104,
+ MMC_HS_200,
+ MMC_MODES_END
+};
+
+const char *mmc_mode_name(enum bus_mode mode);
+void mmc_dump_capabilities(const char *text, uint caps);
+
+static inline bool mmc_is_mode_ddr(enum bus_mode mode)
+{
+ if (mode == MMC_DDR_52)
+ return true;
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ else if (mode == UHS_DDR50)
+ return true;
+#endif
+ else
+ return false;
+}
+
+#define UHS_CAPS (MMC_CAP(UHS_SDR12) | MMC_CAP(UHS_SDR25) | \
+ MMC_CAP(UHS_SDR50) | MMC_CAP(UHS_SDR104) | \
+ MMC_CAP(UHS_DDR50))
+
+static inline bool supports_uhs(uint caps)
+{
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ return (caps & UHS_CAPS) ? true : false;
+#else
+ return false;
+#endif
+}
+
/*
* With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device
* with mmc_get_mmc_dev().
@@ -421,9 +565,12 @@ struct mmc {
void *priv;
uint has_init;
int high_capacity;
+ bool clk_disable; /* true if the clock can be turned off */
uint bus_width;
uint clock;
+ enum mmc_voltage signal_voltage;
uint card_caps;
+ uint host_caps;
uint ocr;
uint dsr;
uint dsr_imp;
@@ -436,18 +583,27 @@ struct mmc {
u8 wr_rel_set;
u8 part_config;
uint tran_speed;
+ uint legacy_speed; /* speed for the legacy mode provided by the card */
uint read_bl_len;
+#if CONFIG_IS_ENABLED(MMC_WRITE)
uint write_bl_len;
uint erase_grp_size; /* in 512-byte sectors */
+#endif
+#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
uint hc_wp_grp_size; /* in 512-byte sectors */
+#endif
+#if CONFIG_IS_ENABLED(MMC_WRITE)
struct sd_ssr ssr; /* SD status register */
+#endif
u64 capacity;
u64 capacity_user;
u64 capacity_boot;
u64 capacity_rpmb;
u64 capacity_gp[4];
+#ifndef CONFIG_SPL_BUILD
u64 enh_user_start;
u64 enh_user_size;
+#endif
#if !CONFIG_IS_ENABLED(BLK)
struct blk_desc block_dev;
#endif
@@ -457,7 +613,21 @@ struct mmc {
int ddr_mode;
#if CONFIG_IS_ENABLED(DM_MMC)
struct udevice *dev; /* Device for this MMC controller */
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ struct udevice *vmmc_supply; /* Main voltage regulator (Vcc)*/
+ struct udevice *vqmmc_supply; /* IO voltage regulator (Vccq)*/
#endif
+#endif
+ u8 *ext_csd;
+ u32 cardtype; /* cardtype read from the MMC */
+ enum mmc_voltage current_voltage;
+ enum bus_mode selected_mode; /* mode currently used */
+ enum bus_mode best_mode; /* best mode is the supported mode with the
+ * highest bandwidth. It may not always be the
+ * operating mode due to limitations when
+ * accessing the boot partitions
+ */
+ u32 quirks;
};
struct mmc_hwpart_conf {
@@ -507,8 +677,36 @@ void mmc_destroy(struct mmc *mmc);
int mmc_unbind(struct udevice *dev);
int mmc_initialize(bd_t *bis);
int mmc_init(struct mmc *mmc);
+int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error);
+
+/**
+ * mmc_of_parse() - Parse the device tree to get the capabilities of the host
+ *
+ * @dev: MMC device
+ * @cfg: MMC configuration
+ * @return 0 if OK, -ve on error
+ */
+int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg);
+
int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size);
-void mmc_set_clock(struct mmc *mmc, uint clock);
+
+/**
+ * mmc_voltage_to_mv() - Convert a mmc_voltage in mV
+ *
+ * @voltage: The mmc_voltage to convert
+ * @return the value in mV if OK, -EINVAL on error (invalid mmc_voltage value)
+ */
+int mmc_voltage_to_mv(enum mmc_voltage voltage);
+
+/**
+ * mmc_set_clock() - change the bus clock
+ * @mmc: MMC struct
+ * @clock: bus frequency in Hz
+ * @disable: flag indicating if the clock must on or off
+ * @return 0 if OK, -ve on error
+ */
+int mmc_set_clock(struct mmc *mmc, uint clock, bool disable);
+
struct mmc *find_mmc_device(int dev_num);
int mmc_set_dev(int dev_num);
void print_mmc_devices(char separator);
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 30ec6b92b2..6b138faf85 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -1272,6 +1272,28 @@ static int uncompress_blob(const void *src, ulong sz_src, void **dstp)
# endif
#endif
+#if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
+/*
+ * For CONFIG_OF_SEPARATE, the board may optionally implement this to
+ * provide and/or fixup the fdt.
+ */
+__weak void *board_fdt_blob_setup(void)
+{
+ void *fdt_blob = NULL;
+#ifdef CONFIG_SPL_BUILD
+ /* FDT is at end of BSS unless it is in a different memory region */
+ if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
+ fdt_blob = (ulong *)&_image_binary_end;
+ else
+ fdt_blob = (ulong *)&__bss_end;
+#else
+ /* FDT is at end of image */
+ fdt_blob = (ulong *)&_end;
+#endif
+ return fdt_blob;
+}
+#endif
+
int fdtdec_setup(void)
{
#if CONFIG_IS_ENABLED(OF_CONTROL)
@@ -1285,18 +1307,7 @@ int fdtdec_setup(void)
# else
gd->fdt_blob = __dtb_dt_begin;
# endif
-# elif defined CONFIG_OF_SEPARATE
-# ifdef CONFIG_SPL_BUILD
- /* FDT is at end of BSS unless it is in a different memory region */
- if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
- gd->fdt_blob = (ulong *)&_image_binary_end;
- else
- gd->fdt_blob = (ulong *)&__bss_end;
-# else
- /* FDT is at end of image */
- gd->fdt_blob = (ulong *)&_end;
-# endif
-# elif defined(CONFIG_OF_BOARD)
+# elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
/* Allow the board to override the fdt address. */
gd->fdt_blob = board_fdt_blob_setup();
# elif defined(CONFIG_OF_HOSTFILE)
diff --git a/test/dm/bus.c b/test/dm/bus.c
index 7006d4163d..1da398ae3a 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -105,7 +105,7 @@ UCLASS_DRIVER(testbus) = {
/* Test that we can probe for children */
static int dm_test_bus_children(struct unit_test_state *uts)
{
- int num_devices = 6;
+ int num_devices = 7;
struct udevice *bus;
struct uclass *uc;
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index dcc2ef8b65..920ccbf016 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -167,7 +167,7 @@ int dm_check_devices(struct unit_test_state *uts, int num_devices)
/* Test that FDT-based binding works correctly */
static int dm_test_fdt(struct unit_test_state *uts)
{
- const int num_devices = 6;
+ const int num_devices = 7;
struct udevice *dev;
struct uclass *uc;
int ret;
diff --git a/tools/Makefile b/tools/Makefile
index 4d32fe5910..571f571ec9 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -185,6 +185,7 @@ hostprogs-$(CONFIG_KIRKWOOD) += kwboot
hostprogs-$(CONFIG_ARCH_MVEBU) += kwboot
hostprogs-y += proftool
hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela
+hostprogs-$(CONFIG_RISCV) += prelink-riscv
hostprogs-y += fdtgrep
fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o
diff --git a/tools/prelink-riscv.c b/tools/prelink-riscv.c
new file mode 100644
index 0000000000..632d2da6ba
--- /dev/null
+++ b/tools/prelink-riscv.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 Andes Technology
+ * Chih-Mao Chen <cmchen@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Statically process runtime relocations on RISC-V ELF images
+ * so that it can be directly executed when loaded at LMA
+ * without fixup. Both RV32 and RV64 are supported.
+ */
+
+#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
+#error "Only little-endian host is supported"
+#endif
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <elf.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifndef EM_RISCV
+#define EM_RISCV 243
+#endif
+
+#ifndef R_RISCV_32
+#define R_RISCV_32 1
+#endif
+
+#ifndef R_RISCV_64
+#define R_RISCV_64 2
+#endif
+
+#ifndef R_RISCV_RELATIVE
+#define R_RISCV_RELATIVE 3
+#endif
+
+const char *argv0;
+
+#define die(fmt, ...) \
+ do { \
+ fprintf(stderr, "%s: " fmt "\n", argv0, ## __VA_ARGS__); \
+ exit(EXIT_FAILURE); \
+ } while (0)
+
+#define PRELINK_INC_BITS 32
+#include "prelink-riscv.inc"
+#undef PRELINK_INC_BITS
+
+#define PRELINK_INC_BITS 64
+#include "prelink-riscv.inc"
+#undef PRELINK_INC_BITS
+
+int main(int argc, const char *const *argv)
+{
+ argv0 = argv[0];
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <u-boot>\n", argv0);
+ exit(EXIT_FAILURE);
+ }
+
+ int fd = open(argv[1], O_RDWR, 0);
+
+ if (fd < 0)
+ die("Cannot open %s: %s", argv[1], strerror(errno));
+
+ struct stat st;
+
+ if (fstat(fd, &st) < 0)
+ die("Cannot stat %s: %s", argv[1], strerror(errno));
+
+ void *data =
+ mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ if (data == MAP_FAILED)
+ die("Cannot mmap %s: %s", argv[1], strerror(errno));
+
+ close(fd);
+
+ unsigned char *e_ident = (unsigned char *)data;
+
+ if (memcmp(e_ident, ELFMAG, SELFMAG) != 0)
+ die("Invalid ELF file %s", argv[1]);
+
+ bool is64 = e_ident[EI_CLASS] == ELFCLASS64;
+
+ if (is64)
+ prelink64(data);
+ else
+ prelink32(data);
+
+ return 0;
+}
diff --git a/tools/prelink-riscv.inc b/tools/prelink-riscv.inc
new file mode 100644
index 0000000000..c07d930f7e
--- /dev/null
+++ b/tools/prelink-riscv.inc
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 Andes Technology
+ * Chih-Mao Chen <cmchen@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Statically process runtime relocations on RISC-V ELF images
+ * so that it can be directly executed when loaded at LMA
+ * without fixup. Both RV32 and RV64 are supported.
+ */
+
+#define CONCAT_IMPL(x, y) x##y
+#define CONCAT(x, y) CONCAT_IMPL(x, y)
+#define CONCAT3(x, y, z) CONCAT(CONCAT(x, y), z)
+
+#define prelink_nn CONCAT(prelink, PRELINK_INC_BITS)
+#define uintnn_t CONCAT3(uint, PRELINK_INC_BITS, _t)
+#define get_offset_nn CONCAT(get_offset_, PRELINK_INC_BITS)
+#define Elf_Ehdr CONCAT3(Elf, PRELINK_INC_BITS, _Ehdr)
+#define Elf_Phdr CONCAT3(Elf, PRELINK_INC_BITS, _Phdr)
+#define Elf_Rela CONCAT3(Elf, PRELINK_INC_BITS, _Rela)
+#define Elf_Sym CONCAT3(Elf, PRELINK_INC_BITS, _Sym)
+#define Elf_Dyn CONCAT3(Elf, PRELINK_INC_BITS, _Dyn)
+#define Elf_Addr CONCAT3(Elf, PRELINK_INC_BITS, _Addr)
+#define ELF_R_TYPE CONCAT3(ELF, PRELINK_INC_BITS, _R_TYPE)
+#define ELF_R_SYM CONCAT3(ELF, PRELINK_INC_BITS, _R_SYM)
+
+static void* get_offset_nn (void* data, Elf_Phdr* phdrs, size_t phnum, Elf_Addr addr)
+{
+ Elf_Phdr *p;
+
+ for (p = phdrs; p < phdrs + phnum; ++p)
+ if (p->p_vaddr <= addr && p->p_vaddr + p->p_memsz > addr)
+ return data + p->p_offset + (addr - p->p_vaddr);
+
+ return NULL;
+}
+
+static void prelink_nn(void *data)
+{
+ Elf_Ehdr *ehdr = data;
+ Elf_Phdr *p;
+ Elf_Dyn *dyn;
+ Elf_Rela *r;
+
+ if (ehdr->e_machine != EM_RISCV)
+ die("Machine type is not RISC-V");
+
+ Elf_Phdr *phdrs = data + ehdr->e_phoff;
+
+ Elf_Dyn *dyns = NULL;
+ for (p = phdrs; p < phdrs + ehdr->e_phnum; ++p) {
+ if (p->p_type == PT_DYNAMIC) {
+ dyns = data + p->p_offset;
+ break;
+ }
+ }
+
+ if (dyns == NULL)
+ die("No dynamic section found");
+
+ Elf_Rela *rela_dyn = NULL;
+ size_t rela_count = 0;
+ Elf_Sym *dynsym = NULL;
+ for (dyn = dyns;; ++dyn) {
+ if (dyn->d_tag == DT_NULL)
+ break;
+ else if (dyn->d_tag == DT_RELA)
+ rela_dyn = get_offset_nn(data, phdrs, ehdr->e_phnum, + dyn->d_un.d_ptr);
+ else if (dyn->d_tag == DT_RELASZ)
+ rela_count = dyn->d_un.d_val / sizeof(Elf_Rela);
+ else if (dyn->d_tag == DT_SYMTAB)
+ dynsym = get_offset_nn(data, phdrs, ehdr->e_phnum, + dyn->d_un.d_ptr);
+
+ }
+
+ if (rela_dyn == NULL)
+ die("No .rela.dyn found");
+
+ if (dynsym == NULL)
+ die("No .dynsym found");
+
+ for (r = rela_dyn; r < rela_dyn + rela_count; ++r) {
+ void* buf = get_offset_nn(data, phdrs, ehdr->e_phnum, r->r_offset);
+
+ if (buf == NULL)
+ continue;
+
+ if (ELF_R_TYPE(r->r_info) == R_RISCV_RELATIVE)
+ *((uintnn_t*) buf) = r->r_addend;
+ else if (ELF_R_TYPE(r->r_info) == R_RISCV_32)
+ *((uint32_t*) buf) = dynsym[ELF_R_SYM(r->r_info)].st_value;
+ else if (ELF_R_TYPE(r->r_info) == R_RISCV_64)
+ *((uint64_t*) buf) = dynsym[ELF_R_SYM(r->r_info)].st_value;
+ }
+}
+
+#undef prelink_nn
+#undef uintnn_t
+#undef get_offset_nn
+#undef Elf_Ehdr
+#undef Elf_Phdr
+#undef Elf_Rela
+#undef Elf_Sym
+#undef Elf_Dyn
+#undef Elf_Addr
+#undef ELF_R_TYPE
+#undef ELF_R_SYM
+
+#undef CONCAT_IMPL
+#undef CONCAT
+#undef CONCAT3