import i96 uboot aka overwrite official uboot with orangepi's so i can have a diff to work with

This commit is contained in:
julia 2022-06-26 12:41:51 +02:00
parent 1a78434253
commit bd4d8f6906
1032 changed files with 212862 additions and 15266 deletions

79
.gitignore vendored
View File

@ -5,52 +5,61 @@
#
# Normal rules
#
*.rej
*.orig
*.a
.*
*.o
*.o.*
*.a
*.s
*.su
*~
*.mod.c
*.i
*.lst
*.order
*.elf
*.swp
*.patch
*.bin
*.patch
*.cfgtmp
*.rda
*.img
# host programs on Cygwin
*.exe
# Build tree
/build-*
#
# Top-level generic files
#
/MLO
/MLO*
/SPL
/System.map
/u-boot
/u-boot.hex
/u-boot.imx
/u-boot.map
/u-boot.srec
/u-boot.ldr
/u-boot.ldr.hex
/u-boot.ldr.srec
/u-boot.img
/u-boot.kwb
/u-boot.sha1
/u-boot.dis
/u-boot.lds
/u-boot.ubl
/u-boot.ais
/u-boot.dtb
/u-boot.sb
/u-boot*
#
# git files that we don't want to ignore even it they are dot-files
#
!.gitignore
!.mailmap
#
# Generated files
#
*.depend*
/LOG
/errlog
/reloc_off
/tpl/
#
# Generated include files
#
/include/config/
/include/generated/
asm-offsets.s
/include/spl-autoconf.mk
/include/tpl-autoconf.mk
# stgit generated dirs
patches-*
@ -71,7 +80,15 @@ cscope.*
/ctags
/etags
# OneNAND IPL files
/onenand_ipl/onenand-ipl*
/onenand_ipl/board/*/onenand*
/onenand_ipl/board/*/*.S
# gnu global files
GPATH
GRTAGS
GSYMS
GTAGS
*.orig
*~
\#*#
/cur.log

49
CleanSpec.mk Normal file
View File

@ -0,0 +1,49 @@
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# If you don't need to do a full clean build but would like to touch
# a file or delete some intermediate files, add a clean step to the end
# of the list. These steps will only be run once, if they haven't been
# run before.
#
# E.g.:
# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
#
# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
# files that are missing or have been moved.
#
# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
# Use $(OUT_DIR) to refer to the "out" directory.
#
# If you need to re-do something that's already mentioned, just copy
# the command and add it to the bottom of the list. E.g., if a change
# that you made last week required touching a file and a change you
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
# For example:
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************

View File

@ -777,6 +777,10 @@ Linus Walleij <linus.walleij@linaro.org>
integratorap various
integratorcp various
Luka Perkov <uboot@lukaperkov.net>
ib62x0 ARM926EJS
Dave Peverley <dpeverley@mpc-data.co.uk>
omap730p2 ARM926EJS
@ -788,6 +792,16 @@ Stelian Pop <stelian@popies.net>
at91sam9263ek ARM926EJS (AT91SAM9263 SoC)
at91sam9rlek ARM926EJS (AT91SAM9RL SoC)
Dave Purdy <david.c.purdy@gmail.com>
pogo_e02 ARM926EJS (Kirkwood SoC)
Sricharan R <r.sricharan@ti.com>
omap4_panda ARM ARMV7 (OMAP4xx SoC)
omap4_sdp4430 ARM ARMV7 (OMAP4xx SoC)
omap5_evm ARM ARMV7 (OMAP5xx Soc)
Thierry Reding <thierry.reding@avionic-design.de>
plutux Tegra2 (ARM7 & A9 Dual Core)
@ -860,12 +874,6 @@ Greg Ungerer <greg.ungerer@opengear.com>
cm4116 ks8695p
cm4148 ks8695p
Aneesh V <aneesh@ti.com>
omap4_panda ARM ARMV7 (OMAP4xx SoC)
omap4_sdp4430 ARM ARMV7 (OMAP4xx SoC)
omap5_evm ARM ARMV7 (OMAP5xx Soc)
Marek Vasut <marek.vasut@gmail.com>
balloon3 xscale/pxa
@ -932,6 +940,10 @@ Sughosh Ganu <urwithsughosh@gmail.com>
hawkboard ARM926EJS (OMAP-L138)
Vladimir Zapolskiy <vz@mleia.com>
devkit3250 lpc32xx
-------------------------------------------------------------------------
Unknown / orphaned boards:
@ -1191,6 +1203,7 @@ Macpaul Lin <macpaul@andestech.com>
ADP-AG101 N1213 (AG101 SoC)
ADP-AG101P N1213 (AG101P XC5 FPGA)
ADP-AG102 N1213f (AG102 SoC with FPU)
#########################################################################
# OpenRISC Systems: #

174
MAKEALL Executable file → Normal file
View File

@ -34,6 +34,7 @@ usage()
CROSS_COMPILE cross-compiler toolchain prefix (default: "")
MAKEALL_LOGDIR output all logs to here (default: ./LOG/)
BUILD_DIR output build directory (default: ./)
BUILD_NBUILDS number of parallel targets (default: 1)
Examples:
- build all Power Architecture boards:
@ -178,18 +179,33 @@ else
LOG_DIR="LOG"
fi
if [ ! "${BUILD_DIR}" ] ; then
BUILD_DIR="."
: ${BUILD_NBUILDS:=1}
BUILD_MANY=0
if [ "${BUILD_NBUILDS}" -gt 1 ] ; then
BUILD_MANY=1
: ${BUILD_DIR:=./build}
mkdir -p "${BUILD_DIR}/ERR"
find "${BUILD_DIR}/ERR/" -type f -exec rm -f {} +
fi
[ -d ${LOG_DIR} ] || mkdir ${LOG_DIR} || exit 1
: ${BUILD_DIR:=.}
OUTPUT_PREFIX="${BUILD_DIR}"
[ -d ${LOG_DIR} ] || mkdir "${LOG_DIR}" || exit 1
find "${LOG_DIR}/" -type f -exec rm -f {} +
LIST=""
# Keep track of the number of builds and errors
ERR_CNT=0
ERR_LIST=""
WRN_CNT=0
WRN_LIST=""
TOTAL_CNT=0
CURRENT_CNT=0
OLDEST_IDX=1
RC=0
# Helper funcs for parsing boards.cfg
@ -326,12 +342,7 @@ LIST_ARM9="$(boards_by_cpu arm920t) \
#########################################################################
## ARM11 Systems
#########################################################################
LIST_ARM11="$(boards_by_cpu arm1136) \
imx31_phycore \
imx31_phycore_eet \
mx31pdk \
smdk6400 \
"
LIST_ARM11="$(boards_by_cpu arm1136)"
#########################################################################
## ARMV7 Systems
@ -351,10 +362,7 @@ LIST_at91="$(boards_by_soc at91)"
LIST_pxa="$(boards_by_cpu pxa)"
LIST_ixp="$(boards_by_cpu ixp)
pdnb3 \
scpu \
"
LIST_ixp="$(boards_by_cpu ixp)"
#########################################################################
## ARM groups
@ -592,41 +600,106 @@ list_target() {
echo ""
}
# Each finished build will have a file called ${donep}${n},
# where n is the index of the build. Each build
# we've already noted as finished will have ${skipp}${n}.
# The code managing the build process will use this information
# to ensure that only BUILD_NBUILDS builds are in flight at once
donep="${LOG_DIR}/._done_"
skipp="${LOG_DIR}/._skip_"
build_target() {
target=$1
build_idx=$2
if [ "$ONLY_LIST" == 'y' ] ; then
list_target ${target}
return
fi
if [ $BUILD_MANY == 1 ] ; then
output_dir="${OUTPUT_PREFIX}/${target}"
mkdir -p "${output_dir}"
else
output_dir="${OUTPUT_PREFIX}"
fi
export BUILD_DIR="${output_dir}"
${MAKE} distclean >/dev/null
${MAKE} -s ${target}_config
${MAKE} ${JOBS} all 2>&1 >${LOG_DIR}/$target.MAKELOG \
| tee ${LOG_DIR}/$target.ERR
${MAKE} ${JOBS} all \
>${LOG_DIR}/$target.MAKELOG 2> ${LOG_DIR}/$target.ERR
# Check for 'make' errors
if [ ${PIPESTATUS[0]} -ne 0 ] ; then
RC=1
fi
if [ -s ${LOG_DIR}/$target.ERR ] ; then
ERR_CNT=$((ERR_CNT + 1))
ERR_LIST="${ERR_LIST} $target"
if [ $BUILD_MANY == 1 ] ; then
${MAKE} tidy
if [ -s ${LOG_DIR}/${target}.ERR ] ; then
cp ${LOG_DIR}/${target}.ERR ${OUTPUT_PREFIX}/ERR/${target}
else
rm ${LOG_DIR}/${target}.ERR
fi
else
rm ${LOG_DIR}/$target.ERR
if [ -s ${LOG_DIR}/${target}.ERR ] ; then
if grep -iw error ${LOG_DIR}/${target}.ERR ; then
: $(( ERR_CNT += 1 ))
ERR_LIST="${ERR_LIST} $target"
else
: $(( WRN_CNT += 1 ))
WRN_LIST="${WRN_LIST} $target"
fi
else
rm ${LOG_DIR}/${target}.ERR
fi
fi
TOTAL_CNT=$((TOTAL_CNT + 1))
OBJS=${BUILD_DIR}/u-boot
if [ -e ${BUILD_DIR}/spl/u-boot-spl ]; then
OBJS="${OBJS} ${BUILD_DIR}/spl/u-boot-spl"
OBJS=${output_dir}/u-boot
if [ -e ${output_dir}/spl/u-boot-spl ]; then
OBJS="${OBJS} ${output_dir}/spl/u-boot-spl"
fi
${CROSS_COMPILE}size ${OBJS} | tee -a ${LOG_DIR}/$target.MAKELOG
[ -e "${LOG_DIR}/${target}.ERR" ] && cat "${LOG_DIR}/${target}.ERR"
touch "${donep}${build_idx}"
}
manage_builds() {
search_idx=${OLDEST_IDX}
if [ "$ONLY_LIST" == 'y' ] ; then return ; fi
while true; do
if [ -e "${donep}${search_idx}" ] ; then
: $(( CURRENT_CNT-- ))
[ ${OLDEST_IDX} -eq ${search_idx} ] &&
: $(( OLDEST_IDX++ ))
# Only want to count it once
rm -f "${donep}${search_idx}"
touch "${skipp}${search_idx}"
elif [ -e "${skipp}${search_idx}" ] ; then
[ ${OLDEST_IDX} -eq ${search_idx} ] &&
: $(( OLDEST_IDX++ ))
fi
: $(( search_idx++ ))
if [ ${search_idx} -gt ${TOTAL_CNT} ] ; then
if [ ${CURRENT_CNT} -ge ${BUILD_NBUILDS} ] ; then
search_idx=${OLDEST_IDX}
sleep 1
else
break
fi
fi
done
}
build_targets() {
for t in "$@" ; do
# If a LIST_xxx var exists, use it. But avoid variable
@ -639,23 +712,71 @@ build_targets() {
if [ -n "${list}" ] ; then
build_targets ${list}
else
build_target ${t}
: $((TOTAL_CNT += 1))
: $((CURRENT_CNT += 1))
rm -f "${donep}${TOTAL_CNT}"
rm -f "${skipp}${TOTAL_CNT}"
if [ $BUILD_MANY == 1 ] ; then
build_target ${t} ${TOTAL_CNT} &
else
build_target ${t} ${TOTAL_CNT}
fi
fi
# We maintain a running count of all the builds we have done.
# Each finished build will have a file called ${donep}${n},
# where n is the index of the build. Each build
# we've already noted as finished will have ${skipp}${n}.
# We track the current index via TOTAL_CNT, and the oldest
# index. When we exceed the maximum number of parallel builds,
# We look from oldest to current for builds that have completed,
# and update the current count and oldest index as appropriate.
# If we've gone through the entire list, wait a second, and
# reprocess the entire list until we find a build that has
# completed
if [ ${CURRENT_CNT} -ge ${BUILD_NBUILDS} ] ; then
manage_builds
fi
done
}
#-----------------------------------------------------------------------
kill_children() {
kill -- "-$1"
exit
}
print_stats() {
if [ "$ONLY_LIST" == 'y' ] ; then return ; fi
rm -f ${donep}* ${skipp}*
if [ $BUILD_MANY == 1 ] && [ -e "${OUTPUT_PREFIX}/ERR" ] ; then
ERR_LIST=`grep -iwl error ${OUTPUT_PREFIX}/ERR/*`
ERR_LIST=`for f in $ERR_LIST ; do echo -n " $(basename $f)" ; done`
ERR_CNT=`echo $ERR_LIST | wc -w | awk '{print $1}'`
WRN_LIST=`grep -iwL error ${OUTPUT_PREFIX}/ERR/*`
WRN_LIST=`for f in $WRN_LIST ; do echo -n " $(basename $f)" ; done`
WRN_CNT=`echo $WRN_LIST | wc -w | awk '{print $1}'`
fi
echo ""
echo "--------------------- SUMMARY ----------------------------"
echo "Boards compiled: ${TOTAL_CNT}"
if [ ${ERR_CNT} -gt 0 ] ; then
echo "Boards with warnings or errors: ${ERR_CNT} (${ERR_LIST} )"
echo "Boards with errors: ${ERR_CNT} (${ERR_LIST} )"
fi
if [ ${WRN_CNT} -gt 0 ] ; then
echo "Boards with warnings but no errors: ${WRN_CNT} (${WRN_LIST} )"
fi
echo "----------------------------------------------------------"
if [ $BUILD_MANY == 1 ] ; then
kill_children $$ &
fi
exit $RC
}
@ -666,3 +787,4 @@ set -- ${SELECTED} "$@"
# run PowerPC by default
[ $# = 0 ] && set -- powerpc
build_targets "$@"
wait

112
Makefile
View File

@ -23,8 +23,8 @@
VERSION = 2012
PATCHLEVEL = 04
SUBLEVEL =
EXTRAVERSION =
SUBLEVEL = 442
EXTRAVERSION = -rel5.0.2
ifneq "$(SUBLEVEL)" ""
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
else
@ -58,10 +58,15 @@ VENDOR=
#########################################################################
# Allow for silent builds
ifneq (1,$(V))
export MAKEFLAGS += -s --no-print-directory
export STDOUT_NULL := 1>/dev/null
endif
ifeq (,$(findstring s,$(MAKEFLAGS)))
XECHO = echo
export XECHO = :
else
XECHO = :
export XECHO = echo
endif
#########################################################################
@ -110,6 +115,7 @@ TOPDIR := $(SRCTREE)
LNDIR := $(OBJTREE)
export TOPDIR SRCTREE OBJTREE SPLTREE
MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG
@ -140,7 +146,7 @@ unexport CDPATH
# The "examples" conditionally depend on U-Boot (say, when USE_PRIVATE_LIBGCC
# is "yes"), so compile examples after U-Boot is compiled.
SUBDIR_TOOLS = tools
SUBDIR_EXAMPLES = examples/standalone examples/api
#SUBDIR_EXAMPLES = examples/standalone examples/api
SUBDIRS = $(SUBDIR_TOOLS)
.PHONY : $(SUBDIRS) $(VERSION_FILE) $(TIMESTAMP_FILE)
@ -301,6 +307,9 @@ LIBS += common/libcommon.o
LIBS += lib/libfdt/libfdt.o
LIBS += api/libapi.o
LIBS += post/libpost.o
LIBS += android/libandroid.o
LIBS += pdl/common/libpdl_common.o
LIBS += pdl/pdl-2/libpdl_stage.o
ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP34XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),)
LIBS += $(CPUDIR)/omap-common/libomap-common.o
@ -370,12 +379,13 @@ BOARD_SIZE_CHECK =
endif
# Always append ALL so that arch config.mk's can add custom ones
ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map
ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(obj)u-boot.img
ALL-$(CONFIG_NAND_U_BOOT) += $(obj)u-boot-nand.bin
ALL-$(CONFIG_ONENAND_U_BOOT) += $(obj)u-boot-onenand.bin
ONENAND_BIN ?= $(obj)onenand_ipl/onenand-ipl-2k.bin
ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin
ALL-$(CONFIG_SPL) += $(obj)u-boot$(RDASIGN).rda $(obj)spl/u-boot-spl$(RDASIGN).img \
$(obj)spl/u-boot-spl.bin
ALL-$(CONFIG_OF_SEPARATE) += $(obj)u-boot.dtb $(obj)u-boot-dtb.bin
all: $(ALL-y) $(SUBDIR_EXAMPLES)
@ -409,41 +419,82 @@ $(obj)u-boot.ldr.srec: $(obj)u-boot.ldr
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@ -I binary
$(obj)u-boot.img: $(obj)u-boot.bin
$(XECHO)
$(XECHO) " GEN $(@F)"
$(obj)tools/mkimage -A $(ARCH) -T firmware -C none \
-O u-boot -a $(CONFIG_SYS_TEXT_BASE) -e 0 \
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
-d $< $@
-d $< $@ $(STDOUT_NULL)
$(obj)u-boot.imx: $(obj)u-boot.bin
$(XECHO)
$(XECHO) " GEN $(@F)"
$(obj)tools/mkimage -n $(CONFIG_IMX_CONFIG) -T imximage \
-e $(CONFIG_SYS_TEXT_BASE) -d $< $@
-e $(CONFIG_SYS_TEXT_BASE) -d $< $@ $(STDOUT_NULL)
$(obj)u-boot.kwb: $(obj)u-boot.bin
$(XECHO)
$(XECHO) " GEN $(@F)"
$(obj)tools/mkimage -n $(CONFIG_SYS_KWD_CONFIG) -T kwbimage \
-a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) -d $< $@
-a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) -d \
$< $@ $(STDOUT_NULL)
$(obj)u-boot.sha1: $(obj)u-boot.bin
$(obj)tools/ubsha1 $(obj)u-boot.bin
ifeq ($(RDASIGN),)
$(obj)pdl1$(RDASIGN).bin: $(obj)spl/u-boot-spl.bin
cp $< $@
else
$(obj)pdl1$(RDASIGN).bin: $(obj)spl/u-boot-spl$(RDASIGN).img
cp $< $@
endif
$(obj)pdl2.bin: $(obj)u-boot.bin
cp $< $@
.PHONY: PDL
PDL: depend $(obj)pdl1$(RDASIGN).bin $(obj)pdl2$(RDASIGN).bin
$(obj)pdl2-sign.bin: $(obj)u-boot.bin
@echo "Signing: $(notdir $@)"
rdasign -Sba $(UBOOT_SIGN_FLAGS) -m $^ -x $@
$(obj)spl/u-boot-spl-sign.img: $(obj)spl/u-boot-spl.img
rdacryptotool -m indirect $(SPL_SIGN_FLAGS) -i $^ -o $@
$(obj)u-boot-sign.img: $(obj)u-boot.img
@echo "Signing: $(notdir $@)"
rdasign -Sba $(UBOOT_SIGN_FLAGS) -m $^ -x $@
$(obj)u-boot.dis: $(obj)u-boot
$(OBJDUMP) -d $< > $@
$(obj)u-boot.ubl: $(obj)spl/u-boot-spl.bin $(obj)u-boot.bin
$(XECHO)
$(XECHO) " GEN $(@F)"
$(OBJCOPY) ${OBJCFLAGS} --pad-to=$(PAD_TO) -O binary $(obj)spl/u-boot-spl $(obj)spl/u-boot-spl-pad.bin
cat $(obj)spl/u-boot-spl-pad.bin $(obj)u-boot.bin > $(obj)u-boot-ubl.bin
$(obj)tools/mkimage -n $(UBL_CONFIG) -T ublimage \
-e $(CONFIG_SYS_TEXT_BASE) -d $(obj)u-boot-ubl.bin $(obj)u-boot.ubl
-e $(CONFIG_SYS_TEXT_BASE) -d $(obj)u-boot-ubl.bin \
$(obj)u-boot.ubl $(STDOUT_NULL)
rm $(obj)u-boot-ubl.bin
rm $(obj)spl/u-boot-spl-pad.bin
$(obj)u-boot$(RDASIGN).rda: $(obj)spl/u-boot-spl$(RDASIGN).img $(obj)u-boot$(RDASIGN).img
$(shell $(TOPDIR)/tools/mkrdaimage.sh $(BOARD_NAND_PAGE_SIZE) \
$^ $(SPL_APPENDING_TO) $@)
$(obj)u-boot.ais: $(obj)spl/u-boot-spl.bin $(obj)u-boot.bin
$(XECHO)
$(XECHO) " GEN $(@F)"
$(obj)tools/mkimage -s -n /dev/null -T aisimage \
-e $(CONFIG_SPL_TEXT_BASE) \
-d $(obj)spl/u-boot-spl.bin \
$(obj)spl/u-boot-spl.ais
$(obj)spl/u-boot-spl.ais $(STDOUT_NULL)
$(OBJCOPY) ${OBJCFLAGS} -I binary \
--pad-to=$(CONFIG_SPL_MAX_SIZE) -O binary \
--pad-to=$(CONFIG_SPL_CODE_MAX_SIZE) -O binary \
$(obj)spl/u-boot-spl.ais $(obj)spl/u-boot-spl-pad.ais
cat $(obj)spl/u-boot-spl-pad.ais $(obj)u-boot.bin > \
$(obj)u-boot.ais
@ -479,26 +530,39 @@ ifeq ($(CONFIG_KALLSYMS),y)
endif
$(OBJS): depend
$(XECHO)
$(XECHO) " MAKE $(subst $(obj),,$@)"
$(MAKE) -C $(CPUDIR) $(if $(REMOTE_BUILD),$@,$(notdir $@))
$(LIBS): depend $(SUBDIR_TOOLS)
$(XECHO)
$(XECHO) " MAKE $(dir $(subst $(obj),,$@))"
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(LIBBOARD): depend $(LIBS)
$(XECHO)
$(XECHO) " MAKE $(dir $(subst $(obj),,$@))"
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(SUBDIRS): depend
$(XECHO)
$(XECHO) " MAKE $(subst $(obj),,$@)"
$(MAKE) -C $@ all
$(SUBDIR_EXAMPLES): $(obj)u-boot
$(LDSCRIPT): depend
$(XECHO)
$(XECHO) " GEN $(notdir $@)"
$(MAKE) -C $(dir $@) $(notdir $@)
$(obj)u-boot.lds: $(LDSCRIPT)
$(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >$@
.PHONY: nand_spl
nand_spl: $(TIMESTAMP_FILE) $(VERSION_FILE) depend
$(XECHO)
$(XECHO) " MAKE nand_spl/board/$(BOARDDIR)"
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(obj)u-boot-nand.bin: nand_spl $(obj)u-boot.bin
@ -510,10 +574,21 @@ onenand_ipl: $(TIMESTAMP_FILE) $(VERSION_FILE) $(obj)include/autoconf.mk
$(obj)u-boot-onenand.bin: onenand_ipl $(obj)u-boot.bin
cat $(ONENAND_BIN) $(obj)u-boot.bin > $(obj)u-boot-onenand.bin
$(obj)spl/u-boot-spl.bin: $(SUBDIR_TOOLS) depend
.PHONY: u-boot-spl
u-boot-spl: $(SUBDIR_TOOLS) depend
$(XECHO)
$(XECHO) " MAKE $@"
$(MAKE) -C spl all
$(obj)spl/u-boot-spl.img $(obj)spl/u-boot-spl.bin: u-boot-spl
# The line below make dependencies work, no idea why.
# Without the line you have to build twice to get get
# the new version of u-boot-spl.img linked at this level.
@echo "Build $(notdir $@)"
updater:
$(XECHO)
$(XECHO) " MAKE tools/updater"
$(MAKE) -C tools/updater all
# Explicitly make _depend in subdirs containing multiple targets to prevent
@ -556,6 +631,13 @@ SYSTEM_MAP = \
$(obj)System.map: $(obj)u-boot
@$(call SYSTEM_MAP,$<) > $(obj)System.map
checkthumb:
@if test $(call cc-version) -lt 0404; then \
echo -n '*** Your GCC does not produce working '; \
echo 'binaries in THUMB mode.'; \
echo '*** Your board is configured for THUMB mode.'; \
false; \
fi
#
# Auto-generate the autoconf.mk file (which is included by all makefiles)
#
@ -740,7 +822,7 @@ clean:
@rm -f $(obj)onenand_ipl/onenand-{ipl,ipl.bin,ipl.map}
@rm -f $(ONENAND_BIN)
@rm -f $(obj)onenand_ipl/u-boot.lds
@rm -f $(obj)spl/{u-boot-spl,u-boot-spl.bin,u-boot-spl.lds,u-boot-spl.map}
@rm -f $(obj)spl/{u-boot-spl,u-boot-spl.bin,u-boot-spl.img,u-boot-spl.lds,u-boot-spl.map}
@rm -f $(obj)MLO
@rm -f $(TIMESTAMP_FILE) $(VERSION_FILE)
@find $(OBJTREE) -type f \

51
README
View File

@ -432,6 +432,14 @@ The following options need to be configured:
Select high exception vectors of the ARM core, e.g., do not
clear the V bit of the c1 register of CP15.
CONFIG_SYS_THUMB_BUILD
Use this flag to build U-Boot using the Thumb instruction
set for ARM architectures. Thumb instruction set provides
better code density. For ARM architectures that support
Thumb2 this flag will result in Thumb2 code generated by
GCC.
- Linux Kernel Interface:
CONFIG_CLOCKS_IN_MHZ
@ -777,6 +785,8 @@ The following options need to be configured:
CONFIG_CMD_JFFS2 * JFFS2 Support
CONFIG_CMD_KGDB * kgdb
CONFIG_CMD_LDRINFO ldrinfo (display Blackfin loader)
CONFIG_CMD_LINK_LOCAL * link-local IP address auto-configuration
(169.254.*.*)
CONFIG_CMD_LOADB loadb
CONFIG_CMD_LOADS loads
CONFIG_CMD_MD5SUM print md5 message digest
@ -814,7 +824,7 @@ The following options need to be configured:
CONFIG_CMD_TIME * run command and report execution time
CONFIG_CMD_USB * USB support
CONFIG_CMD_CDP * Cisco Discover Protocol support
CONFIG_CMD_FSL * Microblaze FSL support
CONFIG_CMD_MFSL * Microblaze FSL support
EXAMPLE: If you want all functions except of network
@ -1584,10 +1594,17 @@ The following options need to be configured:
CONFIG_BOOTP_NTPSERVER
CONFIG_BOOTP_TIMEOFFSET
CONFIG_BOOTP_VENDOREX
CONFIG_BOOTP_MAY_FAIL
CONFIG_BOOTP_SERVERIP - TFTP server will be the serverip
environment variable, not the BOOTP server.
CONFIG_BOOTP_MAY_FAIL - If the DHCP server is not found
after the configured retry count, the call will fail
instead of starting over. This can be used to fail over
to Link-local IP address configuration if the DHCP server
is not available.
CONFIG_BOOTP_DNS2 - If a DHCP client requests the DNS
serverip from a DHCP server, it is possible that more
than one DNS serverip is offered to the client.
@ -1618,6 +1635,14 @@ The following options need to be configured:
the DHCP timeout and retry process takes a longer than
this delay.
- Link-local IP address negotiation:
Negotiate with other link-local clients on the local network
for an address that doesn't require explicit configuration.
This is especially useful if a DHCP server cannot be guaranteed
to exist in all environments that the device must operate.
See doc/README.link-local for more information.
- CDP Options:
CONFIG_CDP_DEVICE_ID
@ -3026,6 +3051,24 @@ to save the current settings.
environment area within the total memory of your DataFlash placed
at the specified address.
- CONFIG_ENV_IS_IN_REMOTE:
Define this if you have a remote memory space which you
want to use for the local device's environment.
- CONFIG_ENV_ADDR:
- CONFIG_ENV_SIZE:
These two #defines specify the address and size of the
environment area within the remote memory space. The
local device can get the environment from remote memory
space by SRIO or other links.
BE CAREFUL! For some special cases, the local device can not use
"saveenv" command. For example, the local device will get the
environment stored in a remote NOR flash by SRIO link, but it can
not erase, write this NOR flash by SRIO interface.
- CONFIG_ENV_IS_IN_NAND:
Define this if you have a NAND device which you want to use
@ -3462,6 +3505,12 @@ within that device.
Specifies that QE/FMAN firmware is located on the primary SPI
device. CONFIG_SYS_FMAN_FW_ADDR is the byte offset on that device.
- CONFIG_SYS_QE_FMAN_FW_IN_REMOTE
Specifies that QE/FMAN firmware is located in the remote (master)
memory space. CONFIG_SYS_FMAN_FW_ADDR is a virtual address which
can be mapped from slave TLB->slave LAW->slave SRIO outbound window
->master inbound window->master LAW->the ucode address in master's
NOR flash.
Building the Software:
======================

48
android/Makefile Normal file
View File

@ -0,0 +1,48 @@
#
# (C) Copyright 2004-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# See file CREDITS for list of people who contributed to this
# project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA
#
include $(TOPDIR)/config.mk
LIB = $(obj)libandroid.o
COBJS-y += android_boot.o
COBJS := $(sort $(COBJS-y))
SRCS := $(COBJS:.o=.c) $(XCOBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
CPPFLAGS += -I..
all: $(LIB)
$(LIB): $(obj).depend $(OBJS)
$(call cmd_link_o_target, $(OBJS))
#########################################################################
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################

50
android/android_boot.c Normal file
View File

@ -0,0 +1,50 @@
#include <common.h>
#include <android/android_boot.h>
#include <asm/mach-types.h>
void creat_atags(unsigned taddr, const char *cmdline,unsigned raddr, unsigned rsize)
{
unsigned n = 0;
unsigned *tags = (unsigned *)taddr;
//ATAG_CORE
tags[n++] = 2;
tags[n++] = 0x54410001;
if(rsize) {
//ATAG_INITRD2
tags[n++] = 4;
tags[n++] = 0x54420005;
tags[n++] = raddr;
tags[n++] = rsize;
}
if(cmdline && cmdline[0]) {
const char *src;
char *dst;
unsigned len = 0;
dst = (char*) (tags + n + 2);
src = cmdline;
while((*dst++ = *src++)) len++;
len++;
len = (len + 3) & (~3);
// ATAG_CMDLINE
tags[n++] = 2 + (len / 4);
tags[n++] = 0x54410009;
n += (len / 4);
}
// ATAG_NONE
tags[n++] = 0;
tags[n++] = 0;
}
void boot_linux(unsigned kaddr, unsigned taddr)
{
void (*entry)(unsigned,unsigned,unsigned) = (void*) kaddr;
entry(0, machine_arch_type, taddr);
}

View File

@ -21,38 +21,58 @@
# MA 02111-1307 USA
#
CROSS_COMPILE ?= arm-linux-
CROSS_COMPILE ?= arm-eabi-
ifndef CONFIG_STANDALONE_LOAD_ADDR
ifeq ($(SOC),omap3)
CONFIG_STANDALONE_LOAD_ADDR = 0x80300000
else
CONFIG_STANDALONE_LOAD_ADDR = 0xc100000
CONFIG_STANDALONE_LOAD_ADDR = 0x80008000
endif
endif
PLATFORM_CPPFLAGS += -DCONFIG_ARM -D__ARM__
# Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb:
PF_CPPFLAGS_ARM := $(call cc-option,-marm,)
# Choose between ARM/Thumb instruction sets
ifeq ($(CONFIG_SYS_THUMB_BUILD),y)
PF_CPPFLAGS_ARM := $(call cc-option, -mthumb -mthumb-interwork,\
$(call cc-option,-marm,)\
$(call cc-option,-mno-thumb-interwork,)\
)
else
PF_CPPFLAGS_ARM := $(call cc-option,-marm,) \
$(call cc-option,-mno-thumb-interwork,)
endif
# Only test once
ifneq ($(CONFIG_SPL_BUILD),y)
ALL-$(CONFIG_SYS_THUMB_BUILD) += checkthumb
endif
ifeq ($(CONFIG_SPL_BUILD),y)
ifeq ($(CONFIG_SPL_THUMB_BUILD),y)
PF_CPPFLAGS_ARM := $(call cc-option, -mthumb -mthumb-interwork,\
$(call cc-option,-marm,)\
$(call cc-option,-mno-thumb-interwork,)\
)
endif
endif
# Try if EABI is supported, else fall back to old API,
# i. e. for example:
# - with ELDK 4.2 (EABI supported), use:
# -mabi=aapcs-linux -mno-thumb-interwork
# -mabi=aapcs-linux
# - with ELDK 4.1 (gcc 4.x, no EABI), use:
# -mabi=apcs-gnu -mno-thumb-interwork
# -mabi=apcs-gnu
# - with ELDK 3.1 (gcc 3.x), use:
# -mapcs-32 -mno-thumb-interwork
# -mapcs-32
PF_CPPFLAGS_ABI := $(call cc-option,\
-mabi=aapcs-linux -mno-thumb-interwork,\
$(call cc-option,\
-mapcs-32,\
-mabi=aapcs-linux,\
$(call cc-option,\
-mabi=apcs-gnu,\
)\
) $(call cc-option,-mno-thumb-interwork,)\
)
-mapcs-32,\
$(call cc-option,\
-mabi=apcs-gnu,\
)\
)\
)
PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_ARM) $(PF_CPPFLAGS_ABI)
# For EABI, make sure to provide raise()

View File

@ -31,3 +31,9 @@ PLATFORM_CPPFLAGS += -march=armv5te
# =========================================================================
PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
ifneq ($(CONFIG_IMX_CONFIG),)
ALL-y += $(obj)u-boot.imx
endif

View File

@ -0,0 +1,45 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# See file CREDITS for list of people who contributed to this
# project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).o
COBJS = cpu.o clk.o devices.o timer.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS))
all: $(obj).depend $(LIB)
$(LIB): $(OBJS)
$(call cmd_link_o_target, $(OBJS))
#########################################################################
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################

View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <common.h>
#include <div64.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clk.h>
#include <asm/io.h>
static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
unsigned int get_sys_clk_rate(void)
{
if (readl(&clk->sysclk_ctrl) & CLK_SYSCLK_PLL397)
return RTC_CLK_FREQUENCY * 397;
else
return OSC_CLK_FREQUENCY;
}
unsigned int get_hclk_pll_rate(void)
{
unsigned long long fin, fref, fcco, fout;
u32 val, m_div, n_div, p_div;
/*
* Valid frequency ranges:
* 1 * 10^6 <= Fin <= 20 * 10^6
* 1 * 10^6 <= Fref <= 27 * 10^6
* 156 * 10^6 <= Fcco <= 320 * 10^6
*/
fref = fin = get_sys_clk_rate();
if (fin > 20000000ULL || fin < 1000000ULL)
return 0;
val = readl(&clk->hclkpll_ctrl);
m_div = ((val & CLK_HCLK_PLL_FEEDBACK_DIV_MASK) >> 1) + 1;
n_div = ((val & CLK_HCLK_PLL_PREDIV_MASK) >> 9) + 1;
if (val & CLK_HCLK_PLL_DIRECT)
p_div = 0;
else
p_div = ((val & CLK_HCLK_PLL_POSTDIV_MASK) >> 11) + 1;
p_div = 1 << p_div;
if (val & CLK_HCLK_PLL_BYPASS) {
do_div(fin, p_div);
return fin;
}
do_div(fref, n_div);
if (fref > 27000000ULL || fref < 1000000ULL)
return 0;
fout = fref * m_div;
if (val & CLK_HCLK_PLL_FEEDBACK) {
fcco = fout;
do_div(fout, p_div);
} else
fcco = fout * p_div;
if (fcco > 320000000ULL || fcco < 156000000ULL)
return 0;
return fout;
}
unsigned int get_hclk_clk_div(void)
{
u32 val;
val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK;
return 1 << val;
}
unsigned int get_hclk_clk_rate(void)
{
return get_hclk_pll_rate() / get_hclk_clk_div();
}
unsigned int get_periph_clk_div(void)
{
u32 val;
val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_PERIPH_DIV_MASK;
return (val >> 2) + 1;
}
unsigned int get_periph_clk_rate(void)
{
if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN))
return get_sys_clk_rate();
return get_hclk_pll_rate() / get_periph_clk_div();
}
int get_serial_clock(void)
{
return get_periph_clk_rate();
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <common.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clk.h>
#include <asm/arch/wdt.h>
#include <asm/io.h>
static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
static struct wdt_regs *wdt = (struct wdt_regs *)WDT_BASE;
void reset_cpu(ulong addr)
{
/* Enable watchdog clock */
setbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG);
/* Reset pulse length is 13005 peripheral clock frames */
writel(13000, &wdt->pulse);
/* Force WDOG_RESET2 and RESOUT_N signal active */
writel(WDTIM_MCTRL_RESFRC2 | WDTIM_MCTRL_RESFRC1 | WDTIM_MCTRL_M_RES2,
&wdt->mctrl);
while (1)
/* NOP */;
}
#if defined(CONFIG_ARCH_CPU_INIT)
int arch_cpu_init(void)
{
/*
* It might be necessary to flush data cache, if U-boot is loaded
* from kickstart bootloader, e.g. from S1L loader
*/
flush_dcache_all();
return 0;
}
#else
#error "You have to select CONFIG_ARCH_CPU_INIT"
#endif
#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo(void)
{
printf("CPU: NXP LPC32XX\n");
printf("CPU clock: %uMHz\n", get_hclk_pll_rate() / 1000000);
printf("AHB bus clock: %uMHz\n", get_hclk_clk_rate() / 1000000);
printf("Peripheral clock: %uMHz\n", get_periph_clk_rate() / 1000000);
return 0;
}
#endif

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <common.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clk.h>
#include <asm/arch/uart.h>
#include <asm/io.h>
static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE;
void lpc32xx_uart_init(unsigned int uart_id)
{
if (uart_id < 1 || uart_id > 7)
return;
/* Disable loopback mode, if it is set by S1L bootloader */
clrbits_le32(&ctrl->loop,
UART_LOOPBACK(CONFIG_SYS_LPC32XX_UART));
if (uart_id < 3 || uart_id > 6)
return;
/* Enable UART system clock */
setbits_le32(&clk->uartclk_ctrl, CLK_UART(uart_id));
/* Set UART into autoclock mode */
clrsetbits_le32(&ctrl->clkmode,
UART_CLKMODE_MASK(uart_id),
UART_CLKMODE_AUTO(uart_id));
/* Bypass pre-divider of UART clock */
writel(CLK_UART_X_DIV(1) | CLK_UART_Y_DIV(1),
&clk->u3clk + (uart_id - 3));
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2011 Vladimir Zapolskiy <vz@mleia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <common.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clk.h>
#include <asm/arch/timer.h>
#include <asm/io.h>
static struct timer_regs *timer0 = (struct timer_regs *)TIMER0_BASE;
static struct timer_regs *timer1 = (struct timer_regs *)TIMER1_BASE;
static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
static void lpc32xx_timer_clock(u32 bit, int enable)
{
if (enable)
setbits_le32(&clk->timclk_ctrl1, bit);
else
clrbits_le32(&clk->timclk_ctrl1, bit);
}
static void lpc32xx_timer_reset(struct timer_regs *timer, u32 freq)
{
writel(TIMER_TCR_COUNTER_RESET, &timer->tcr);
writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr);
writel(0, &timer->tc);
writel(0, &timer->pr);
/* Count mode is every rising PCLK edge */
writel(TIMER_CTCR_MODE_TIMER, &timer->ctcr);
/* Set prescale counter value */
writel((get_periph_clk_rate() / freq) - 1, &timer->pr);
}
static void lpc32xx_timer_count(struct timer_regs *timer, int enable)
{
if (enable)
writel(TIMER_TCR_COUNTER_ENABLE, &timer->tcr);
else
writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr);
}
int timer_init(void)
{
lpc32xx_timer_clock(CLK_TIMCLK_TIMER0, 1);
lpc32xx_timer_reset(timer0, CONFIG_SYS_HZ);
lpc32xx_timer_count(timer0, 1);
return 0;
}
ulong get_timer(ulong base)
{
return readl(&timer0->tc) - base;
}
void __udelay(unsigned long usec)
{
lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 1);
lpc32xx_timer_reset(timer1, CONFIG_SYS_HZ * 1000);
lpc32xx_timer_count(timer1, 1);
while (readl(&timer1->tc) < usec)
/* NOP */;
lpc32xx_timer_count(timer1, 0);
lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 0);
}
unsigned long long get_ticks(void)
{
return get_timer(0);
}
ulong get_tbclk(void)
{
return CONFIG_SYS_HZ;
}

View File

@ -28,10 +28,15 @@
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/imx25-pinmux.h>
#include <asm/arch/clock.h>
#ifdef CONFIG_MXC_MMC
#include <asm/arch/mxcmmc.h>
#endif
#ifdef CONFIG_FSL_ESDHC
DECLARE_GLOBAL_DATA_PTR;
#endif
/*
* get the system pll clock in Hz
*
@ -105,6 +110,20 @@ ulong imx_get_perclk(int clk)
return lldiv(fref, div);
}
unsigned int mxc_get_clock(enum mxc_clock clk)
{
if (clk >= MXC_CLK_NUM)
return -1;
switch (clk) {
case MXC_ARM_CLK:
return imx_get_armclk();
case MXC_FEC_CLK:
return imx_get_ahbclk();
default:
return imx_get_perclk(clk);
}
}
u32 get_cpu_rev(void)
{
u32 srev;
@ -182,6 +201,14 @@ int cpu_eth_init(bd_t *bis)
#endif
}
int get_clocks(void)
{
#ifdef CONFIG_FSL_ESDHC
gd->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
#endif
return 0;
}
/*
* Initializes on-chip MMC controllers.
* to override, implement board_mmc_init()

View File

@ -28,7 +28,7 @@ LIB = $(obj)lib$(SOC).o
COBJS = clock.o mx28.o iomux.o timer.o
ifdef CONFIG_SPL_BUILD
COBJS += spl_boot.o spl_mem_init.o spl_power_init.o
COBJS += spl_boot.o spl_lradc_init.o spl_mem_init.o spl_power_init.o
endif
SRCS := $(START:.o=.S) $(COBJS:.o=.c)

View File

@ -51,9 +51,16 @@ void reset_cpu(ulong ignored) __attribute__((noreturn));
void reset_cpu(ulong ignored)
{
struct mx28_rtc_regs *rtc_regs =
(struct mx28_rtc_regs *)MXS_RTC_BASE;
struct mx28_lcdif_regs *lcdif_regs =
(struct mx28_lcdif_regs *)MXS_LCDIF_BASE;
/*
* Shut down the LCD controller as it interferes with BootROM boot mode
* pads sampling.
*/
writel(LCDIF_CTRL_RUN, &lcdif_regs->hw_lcdif_ctrl_clr);
/* Wait 1 uS before doing the actual watchdog reset */
writel(1, &rtc_regs->hw_rtc_watchdog);
@ -185,8 +192,12 @@ int arch_cpu_init(void)
#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo(void)
{
struct mx28_spl_data *data = (struct mx28_spl_data *)
((CONFIG_SYS_TEXT_BASE - sizeof(struct mx28_spl_data)) & ~0xf);
printf("Freescale i.MX28 family at %d MHz\n",
mxc_get_clock(MXC_ARM_CLK) / 1000000);
printf("BOOT: %s\n", mx28_boot_modes[data->boot_mode_idx].mode);
return 0;
}
#endif
@ -279,22 +290,16 @@ void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
int mx28_dram_init(void)
{
struct mx28_digctl_regs *digctl_regs =
(struct mx28_digctl_regs *)MXS_DIGCTL_BASE;
uint32_t sz[2];
struct mx28_spl_data *data = (struct mx28_spl_data *)
((CONFIG_SYS_TEXT_BASE - sizeof(struct mx28_spl_data)) & ~0xf);
sz[0] = readl(&digctl_regs->hw_digctl_scratch0);
sz[1] = readl(&digctl_regs->hw_digctl_scratch1);
if (sz[0] != sz[1]) {
if (data->mem_dram_size == 0) {
printf("MX28:\n"
"Error, the RAM size in HW_DIGCTRL_SCRATCH0 and\n"
"HW_DIGCTRL_SCRATCH1 is not the same. Please\n"
"verify these two registers contain valid RAM size!\n");
"Error, the RAM size passed up from SPL is 0!\n");
hang();
}
gd->ram_size = sz[0];
gd->ram_size = data->mem_dram_size;
return 0;
}

View File

@ -37,5 +37,9 @@ static inline void mx28_power_wait_pswitch(void) { }
#endif
void mx28_mem_init(void);
uint32_t mx28_mem_get_size(void);
void mx28_lradc_init(void);
void mx28_lradc_enable_batt_measurement(void);
#endif /* __M28_INIT_H__ */

View File

@ -28,6 +28,8 @@
#include <asm/io.h>
#include <asm/arch/iomux-mx28.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sys_proto.h>
#include <asm/gpio.h>
#include "mx28_init.h"
@ -46,12 +48,65 @@ void early_delay(int delay)
;
}
#define MUX_CONFIG_BOOTMODE_PAD (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL)
const iomux_cfg_t iomux_boot[] = {
MX28_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD,
MX28_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD,
MX28_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD,
MX28_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD,
MX28_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD,
MX28_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD,
};
uint8_t mx28_get_bootmode_index(void)
{
uint8_t bootmode = 0;
int i;
uint8_t masked;
/* Setup IOMUX of bootmode pads to GPIO */
mxs_iomux_setup_multiple_pads(iomux_boot, ARRAY_SIZE(iomux_boot));
/* Setup bootmode pins as GPIO input */
gpio_direction_input(MX28_PAD_LCD_D00__GPIO_1_0);
gpio_direction_input(MX28_PAD_LCD_D01__GPIO_1_1);
gpio_direction_input(MX28_PAD_LCD_D02__GPIO_1_2);
gpio_direction_input(MX28_PAD_LCD_D03__GPIO_1_3);
gpio_direction_input(MX28_PAD_LCD_D04__GPIO_1_4);
gpio_direction_input(MX28_PAD_LCD_D05__GPIO_1_5);
/* Read bootmode pads */
bootmode |= (gpio_get_value(MX28_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0;
bootmode |= (gpio_get_value(MX28_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1;
bootmode |= (gpio_get_value(MX28_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2;
bootmode |= (gpio_get_value(MX28_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3;
bootmode |= (gpio_get_value(MX28_PAD_LCD_D04__GPIO_1_4) ? 1 : 0) << 4;
bootmode |= (gpio_get_value(MX28_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5;
for (i = 0; i < ARRAY_SIZE(mx28_boot_modes); i++) {
masked = bootmode & mx28_boot_modes[i].boot_mask;
if (masked == mx28_boot_modes[i].boot_pads)
break;
}
return i;
}
void mx28_common_spl_init(const iomux_cfg_t *iomux_setup,
const unsigned int iomux_size)
{
struct mx28_spl_data *data = (struct mx28_spl_data *)
((CONFIG_SYS_TEXT_BASE - sizeof(struct mx28_spl_data)) & ~0xf);
uint8_t bootmode = mx28_get_bootmode_index();
mxs_iomux_setup_multiple_pads(iomux_setup, iomux_size);
mx28_power_init();
mx28_mem_init();
data->mem_dram_size = mx28_mem_get_size();
data->boot_mode_idx = bootmode;
mx28_power_wait_pswitch();
}
@ -68,8 +123,10 @@ inline void board_init_r(gd_t *id, ulong dest_addr)
;
}
#ifndef CONFIG_SPL_SERIAL_SUPPORT
void serial_putc(const char c) {}
void serial_puts(const char *s) {}
#endif
void hang(void) __attribute__ ((noreturn));
void hang(void)
{

View File

@ -0,0 +1,86 @@
/*
* Freescale i.MX28 Battery measurement init
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <config.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include "mx28_init.h"
void mx28_lradc_init(void)
{
struct mx28_lradc_regs *regs = (struct mx28_lradc_regs *)MXS_LRADC_BASE;
writel(LRADC_CTRL0_SFTRST, &regs->hw_lradc_ctrl0_clr);
writel(LRADC_CTRL0_CLKGATE, &regs->hw_lradc_ctrl0_clr);
writel(LRADC_CTRL0_ONCHIP_GROUNDREF, &regs->hw_lradc_ctrl0_clr);
clrsetbits_le32(&regs->hw_lradc_ctrl3,
LRADC_CTRL3_CYCLE_TIME_MASK,
LRADC_CTRL3_CYCLE_TIME_6MHZ);
clrsetbits_le32(&regs->hw_lradc_ctrl4,
LRADC_CTRL4_LRADC7SELECT_MASK |
LRADC_CTRL4_LRADC6SELECT_MASK,
LRADC_CTRL4_LRADC7SELECT_CHANNEL7 |
LRADC_CTRL4_LRADC6SELECT_CHANNEL10);
}
void mx28_lradc_enable_batt_measurement(void)
{
struct mx28_lradc_regs *regs = (struct mx28_lradc_regs *)MXS_LRADC_BASE;
/* Check if the channel is present at all. */
if (!(readl(&regs->hw_lradc_status) & LRADC_STATUS_CHANNEL7_PRESENT))
return;
writel(LRADC_CTRL1_LRADC7_IRQ_EN, &regs->hw_lradc_ctrl1_clr);
writel(LRADC_CTRL1_LRADC7_IRQ, &regs->hw_lradc_ctrl1_clr);
clrsetbits_le32(&regs->hw_lradc_conversion,
LRADC_CONVERSION_SCALE_FACTOR_MASK,
LRADC_CONVERSION_SCALE_FACTOR_LI_ION);
writel(LRADC_CONVERSION_AUTOMATIC, &regs->hw_lradc_conversion_set);
/* Configure the channel. */
writel((1 << 7) << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
&regs->hw_lradc_ctrl2_clr);
writel(0xffffffff, &regs->hw_lradc_ch7_clr);
clrbits_le32(&regs->hw_lradc_ch7, LRADC_CH_NUM_SAMPLES_MASK);
writel(LRADC_CH_ACCUMULATE, &regs->hw_lradc_ch7_clr);
/* Schedule the channel. */
writel(1 << 7, &regs->hw_lradc_ctrl0_set);
/* Start the channel sampling. */
writel(((1 << 7) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) |
((1 << 3) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) |
100, &regs->hw_lradc_delay3);
writel(0xffffffff, &regs->hw_lradc_ch7_clr);
writel(LRADC_DELAY_KICK, &regs->hw_lradc_delay3_set);
}

View File

@ -39,7 +39,7 @@ uint32_t dram_vals[] = {
0x00000000, 0x00000100, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00010101, 0x01010101,
0x000f0f01, 0x0f02010a, 0x00000000, 0x00010101,
0x000f0f01, 0x0f02020a, 0x00000000, 0x00010101,
0x00000100, 0x00000100, 0x00000000, 0x00000002,
0x01010000, 0x05060302, 0x06005003, 0x0a0000c8,
0x02009c40, 0x0000030c, 0x0036a609, 0x031a0612,
@ -149,6 +149,8 @@ void mx28_mem_setup_cpu_and_hbus(void)
/* Disable CPU bypass */
writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
&clkctrl_regs->hw_clkctrl_clkseq_clr);
early_delay(15000);
}
void mx28_mem_setup_vdda(void)
@ -173,10 +175,8 @@ void mx28_mem_setup_vddd(void)
&power_regs->hw_power_vdddctrl);
}
void mx28_mem_get_size(void)
uint32_t mx28_mem_get_size(void)
{
struct mx28_digctl_regs *digctl_regs =
(struct mx28_digctl_regs *)MXS_DIGCTL_BASE;
uint32_t sz, da;
uint32_t *vt = (uint32_t *)0x20;
/* The following is "subs pc, r14, #4", used as return from DABT. */
@ -187,11 +187,11 @@ void mx28_mem_get_size(void)
vt[4] = data_abort_memdetect_handler;
sz = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE);
writel(sz, &digctl_regs->hw_digctl_scratch0);
writel(sz, &digctl_regs->hw_digctl_scratch1);
/* Restore the old DABT handler. */
vt[4] = da;
return sz;
}
void mx28_mem_init(void)
@ -239,6 +239,4 @@ void mx28_mem_init(void)
early_delay(10000);
mx28_mem_setup_cpu_and_hbus();
mx28_mem_get_size();
}

View File

@ -45,11 +45,11 @@ void mx28_power_clock2pll(void)
struct mx28_clkctrl_regs *clkctrl_regs =
(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
writel(CLKCTRL_PLL0CTRL0_POWER,
&clkctrl_regs->hw_clkctrl_pll0ctrl0_set);
setbits_le32(&clkctrl_regs->hw_clkctrl_pll0ctrl0,
CLKCTRL_PLL0CTRL0_POWER);
early_delay(100);
writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
&clkctrl_regs->hw_clkctrl_clkseq_clr);
setbits_le32(&clkctrl_regs->hw_clkctrl_clkseq,
CLKCTRL_CLKSEQ_BYPASS_CPU);
}
void mx28_power_clear_auto_restart(void)
@ -104,6 +104,62 @@ void mx28_power_set_linreg(void)
POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW);
}
int mx28_get_batt_volt(void)
{
struct mx28_power_regs *power_regs =
(struct mx28_power_regs *)MXS_POWER_BASE;
uint32_t volt = readl(&power_regs->hw_power_battmonitor);
volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
volt *= 8;
return volt;
}
int mx28_is_batt_ready(void)
{
return (mx28_get_batt_volt() >= 3600);
}
int mx28_is_batt_good(void)
{
struct mx28_power_regs *power_regs =
(struct mx28_power_regs *)MXS_POWER_BASE;
uint32_t volt = mx28_get_batt_volt();
if ((volt >= 2400) && (volt <= 4300))
return 1;
clrsetbits_le32(&power_regs->hw_power_5vctrl,
POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
&power_regs->hw_power_5vctrl_clr);
clrsetbits_le32(&power_regs->hw_power_charge,
POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
POWER_CHARGE_STOP_ILIMIT_10MA | 0x3);
writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr);
writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
&power_regs->hw_power_5vctrl_clr);
early_delay(500000);
volt = mx28_get_batt_volt();
if (volt >= 3500)
return 0;
if (volt >= 2400)
return 1;
writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
&power_regs->hw_power_charge_clr);
writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
return 0;
}
void mx28_power_setup_5v_detect(void)
{
struct mx28_power_regs *power_regs =
@ -399,9 +455,14 @@ void mx28_power_enable_4p2(void)
mx28_power_init_4p2_regulator();
/* Shutdown battery (none present) */
clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK);
writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr);
if (!mx28_is_batt_ready()) {
clrbits_le32(&power_regs->hw_power_dcdc4p2,
POWER_DCDC4P2_BO_MASK);
writel(POWER_CTRL_DCDC4P2_BO_IRQ,
&power_regs->hw_power_ctrl_clr);
writel(POWER_CTRL_ENIRQ_DCDC4P2_BO,
&power_regs->hw_power_ctrl_clr);
}
mx28_power_init_dcdc_4p2_source();
@ -459,6 +520,50 @@ void mx28_powerdown(void)
&power_regs->hw_power_reset);
}
void mx28_batt_boot(void)
{
struct mx28_power_regs *power_regs =
(struct mx28_power_regs *)MXS_POWER_BASE;
clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_ENABLE_DCDC);
clrbits_le32(&power_regs->hw_power_dcdc4p2,
POWER_DCDC4P2_ENABLE_DCDC | POWER_DCDC4P2_ENABLE_4P2);
writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_clr);
/* 5V to battery handoff. */
setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
early_delay(30);
clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr);
clrsetbits_le32(&power_regs->hw_power_minpwr,
POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS);
mx28_power_set_linreg();
clrbits_le32(&power_regs->hw_power_vdddctrl,
POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG);
clrbits_le32(&power_regs->hw_power_vddactrl,
POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG);
clrbits_le32(&power_regs->hw_power_vddioctrl,
POWER_VDDIOCTRL_DISABLE_FET);
setbits_le32(&power_regs->hw_power_5vctrl,
POWER_5VCTRL_PWD_CHARGE_4P2_MASK);
setbits_le32(&power_regs->hw_power_5vctrl,
POWER_5VCTRL_ENABLE_DCDC);
clrsetbits_le32(&power_regs->hw_power_5vctrl,
POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
0x8 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
}
void mx28_handle_5v_conflict(void)
{
struct mx28_power_regs *power_regs =
@ -483,25 +588,14 @@ void mx28_handle_5v_conflict(void)
mx28_powerdown();
break;
}
if (tmp & POWER_STS_PSWITCH_MASK) {
mx28_batt_boot();
break;
}
}
}
int mx28_get_batt_volt(void)
{
struct mx28_power_regs *power_regs =
(struct mx28_power_regs *)MXS_POWER_BASE;
uint32_t volt = readl(&power_regs->hw_power_battmonitor);
volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
volt *= 8;
return volt;
}
int mx28_is_batt_ready(void)
{
return (mx28_get_batt_volt() >= 3600);
}
void mx28_5v_boot(void)
{
struct mx28_power_regs *power_regs =
@ -553,62 +647,44 @@ void mx28_switch_vddd_to_dcdc_source(void)
POWER_VDDDCTRL_DISABLE_STEPPING);
}
int mx28_is_batt_good(void)
{
struct mx28_power_regs *power_regs =
(struct mx28_power_regs *)MXS_POWER_BASE;
uint32_t volt;
volt = readl(&power_regs->hw_power_battmonitor);
volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
volt *= 8;
if ((volt >= 2400) && (volt <= 4300))
return 1;
clrsetbits_le32(&power_regs->hw_power_5vctrl,
POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
&power_regs->hw_power_5vctrl_clr);
clrsetbits_le32(&power_regs->hw_power_charge,
POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
POWER_CHARGE_STOP_ILIMIT_10MA | 0x3);
writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr);
writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
&power_regs->hw_power_5vctrl_clr);
early_delay(500000);
volt = readl(&power_regs->hw_power_battmonitor);
volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
volt *= 8;
if (volt >= 3500)
return 0;
if (volt >= 2400)
return 1;
writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
&power_regs->hw_power_charge_clr);
writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
return 0;
}
void mx28_power_configure_power_source(void)
{
int batt_ready, batt_good;
struct mx28_power_regs *power_regs =
(struct mx28_power_regs *)MXS_POWER_BASE;
struct mx28_lradc_regs *lradc_regs =
(struct mx28_lradc_regs *)MXS_LRADC_BASE;
mx28_src_power_init();
mx28_5v_boot();
batt_ready = mx28_is_batt_ready();
if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
batt_good = mx28_is_batt_good();
if (batt_ready) {
/* 5V source detected, good battery detected. */
mx28_batt_boot();
} else {
if (batt_good) {
/* 5V source detected, low battery detceted. */
} else {
/* 5V source detected, bad battery detected. */
writel(LRADC_CONVERSION_AUTOMATIC,
&lradc_regs->hw_lradc_conversion_clr);
clrbits_le32(&power_regs->hw_power_battmonitor,
POWER_BATTMONITOR_BATT_VAL_MASK);
}
mx28_5v_boot();
}
} else {
/* 5V not detected, booting from battery. */
mx28_batt_boot();
}
mx28_power_clock2pll();
mx28_init_batt_bo();
mx28_switch_vddd_to_dcdc_source();
}
@ -883,6 +959,13 @@ void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout)
new_brownout << POWER_VDDDCTRL_BO_OFFSET_OFFSET);
}
void mx28_setup_batt_detect(void)
{
mx28_lradc_init();
mx28_lradc_enable_batt_measurement();
early_delay(10);
}
void mx28_power_init(void)
{
struct mx28_power_regs *power_regs =
@ -892,6 +975,9 @@ void mx28_power_init(void)
mx28_power_clear_auto_restart();
mx28_power_set_linreg();
mx28_power_setup_5v_detect();
mx28_setup_batt_detect();
mx28_power_configure_power_source();
mx28_enable_output_rail_protection();

View File

@ -0,0 +1,58 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
#
# See file CREDITS for list of people who contributed to this
# project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA
#
include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).o
COBJS-y += timer.o serial.o ifc.o cpu.o
ifdef CONFIG_SPL_BUILD
COBJS-y += spl.o
endif
SOBJS = reset.o
ifndef CONFIG_SKIP_LOWLEVEL_INIT
SOBJS += lowlevel_init.o
endif
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS-y) $(SOBJS))
START := $(addprefix $(obj),$(START))
all: $(obj).depend $(LIB)
$(LIB): $(OBJS)
$(call cmd_link_o_target, $(OBJS))
#########################################################################
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################

View File

@ -0,0 +1,32 @@
#
# (C) Copyright 2002
# Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
#
# See file CREDITS for list of people who contributed to this
# project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA
#
PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float
PLATFORM_CPPFLAGS += -march=armv5te
# =========================================================================
#
# Supply options according to compiler version
#
# =========================================================================
PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))

View File

@ -0,0 +1,12 @@
#include <common.h>
#include <asm/arch/hardware.h>
void enable_caches(void)
{
#ifndef CONFIG_SYS_ICACHE_OFF
icache_enable();
#endif
#ifndef CONFIG_SYS_DCACHE_OFF
dcache_enable();
#endif
}

View File

@ -0,0 +1,171 @@
#include "common.h"
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/reg_ifc.h>
#include <asm/arch/ifc.h>
#ifdef DEBUG
#include <assert.h>
#else
#define assert(...)
#endif
#define HAL_TRACE(...)
HAL_IFC_REQUEST_ID_T g_halModuleIfcChannelOwner[SYS_IFC_STD_CHAN_NB];
void hal_IfcOpen(void)
{
u8 channel;
// Initialize the channel table with unknown requests.
for (channel = 0; channel < SYS_IFC_STD_CHAN_NB; channel++)
{
g_halModuleIfcChannelOwner[channel] = HAL_IFC_NO_REQWEST;
}
}
HAL_IFC_REQUEST_ID_T hal_IfcGetOwner(u8 channel)
{
// Here, we consider the transfer as previously finished.
if (channel == HAL_UNKNOWN_CHANNEL) return HAL_IFC_NO_REQWEST;
// Channel number too big.
assert(channel < SYS_IFC_STD_CHAN_NB, channel);
return g_halModuleIfcChannelOwner[channel];
}
void hal_IfcChannelRelease(HAL_IFC_REQUEST_ID_T requestId, u8 channel)
{
//u32 status;
// Here, we consider the transfer as previously finished.
if (channel == HAL_UNKNOWN_CHANNEL) return;
// Channel number too big.
assert(channel < SYS_IFC_STD_CHAN_NB, channel);
//status = hal_SysEnterCriticalSection();
if (g_halModuleIfcChannelOwner[channel] == requestId)
{
// disable this channel
hwp_sysIfc->std_ch[channel].control = (SYS_IFC_REQ_SRC(requestId)
| SYS_IFC_CH_RD_HW_EXCH
| SYS_IFC_DISABLE);
// read the status of this channel
if (hwp_sysIfc->std_ch[channel].status & SYS_IFC_ENABLE)
{
HAL_TRACE(_HAL | TSTDOUT,0," Strange, the released channel not disabled yet");
}
// Write the TC to 0 for next time the channel is re-enabled
hwp_sysIfc->std_ch[channel].tc = 0;
}
//hal_SysExitCriticalSection(status);
}
void hal_IfcChannelFlush(HAL_IFC_REQUEST_ID_T requestId, u8 channel)
{
//u32 status;
// Here, we consider the transfer as previously finished.
if (channel == HAL_UNKNOWN_CHANNEL) return;
// Channel number too big.
assert(channel < SYS_IFC_STD_CHAN_NB, channel);
// Check that the channel is really owned by the peripheral
// which is doing the request, it could have been release
// automatically or by an IRQ handler.
//status = hal_SysEnterCriticalSection();
if (g_halModuleIfcChannelOwner[channel] == requestId)
{
// If fifo not empty, flush it.
if ( !(hwp_sysIfc->std_ch[channel].status & SYS_IFC_FIFO_EMPTY) )
{
hwp_sysIfc->std_ch[channel].control =
hwp_sysIfc->std_ch[channel].control | SYS_IFC_FLUSH;
}
}
//hal_SysExitCriticalSection(status);
}
BOOL hal_IfcChannelIsFifoEmpty(HAL_IFC_REQUEST_ID_T requestId, u8 channel)
{
//u32 status;
BOOL fifoIsEmpty = TRUE;
// Here, we consider the transfer as previously finished.
if (channel == HAL_UNKNOWN_CHANNEL) return fifoIsEmpty;
// Channel number too big.
assert(channel < SYS_IFC_STD_CHAN_NB, channel);
// Check that the channel is really owned by the peripheral
// which is doing the request, it could have been release
// automatically or by an IRQ handler.
//status = hal_SysEnterCriticalSection();
if (g_halModuleIfcChannelOwner[channel] == requestId)
{
fifoIsEmpty =
(FALSE != (hwp_sysIfc->std_ch[channel].status & SYS_IFC_FIFO_EMPTY));
}
//hal_SysExitCriticalSection(status);
return fifoIsEmpty;
}
u8 hal_IfcTransferStart(HAL_IFC_REQUEST_ID_T requestId, u8* memStartAddr, u32 xferSize, HAL_IFC_MODE_T ifcMode)
{
//u32 status = hal_SysEnterCriticalSection();
u8 channel;
u8 i;
// Check buffer alignment depending on the mode
if (ifcMode != HAL_IFC_SIZE_8_MODE_MANUAL && ifcMode != HAL_IFC_SIZE_8_MODE_AUTO)
{
// Then ifcMode == HAL_IFC_SIZE_32, check word alignment
assert(((u32)memStartAddr%4) == 0,
"HAL IFC: 32 bits transfer misaligned 0x@%08X", memStartAddr);
}
else
{
// ifcMode == HAL_IFC_SIZE_8, nothing to check
}
// Check the requested id is not currently already used.
for (i = 0; i < SYS_IFC_STD_CHAN_NB ; i++)
{
if (GET_BITFIELD(hwp_sysIfc->std_ch[i].control, SYS_IFC_REQ_SRC) == requestId)
{
// This channel is or was used for the requestId request.
// Check it is still in use.
assert((hwp_sysIfc->std_ch[i].status & SYS_IFC_ENABLE) == 0,
"HAL: Attempt to use the IFC to deal with a %d"
" request still active on channel %d", requestId, i);
}
}
channel = SYS_IFC_CH_TO_USE(hwp_sysIfc->get_ch) ;
if (channel >= SYS_IFC_STD_CHAN_NB)
{
serial_puts("HAL_UNKNOWN_CHANNEL\n");
//hal_SysExitCriticalSection(status);
return HAL_UNKNOWN_CHANNEL;
}
g_halModuleIfcChannelOwner[channel] = requestId;
hwp_sysIfc->std_ch[channel].start_addr = (u32) memStartAddr;
hwp_sysIfc->std_ch[channel].tc = xferSize;
hwp_sysIfc->std_ch[channel].control = (SYS_IFC_REQ_SRC(requestId)
| ifcMode
| SYS_IFC_CH_RD_HW_EXCH
| SYS_IFC_ENABLE);
//hal_SysExitCriticalSection(status);
return channel;
}

View File

@ -0,0 +1,32 @@
/*
* Processor reset using WDT for TI TMS320DM644x SoC.
*
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
*
* -----------------------------------------------------
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
.globl reset_cpu
reset_cpu:
nop
nop
nop
nop
reset_cpu_loop:
b reset_cpu_loop

View File

@ -0,0 +1,132 @@
#include <common.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/rda_iomap.h>
#include <asm/arch/reg_sysctrl.h>
#include <asm/arch/reg_uart.h>
DECLARE_GLOBAL_DATA_PTR;
void _serial_set_baudrate(int rate)
{
hwp_sysCtrlAp->Cfg_Clk_Uart[2] = 0x36; // 115200 @ 26MHz
//hwp_sysCtrlAp->Cfg_Clk_Uart[2] = 0x05; // 921600 @ 26MHz
}
void _serial_enable_rtscts(void)
{
hwp_uart->ctrl |= UART_AUTO_FLOW_CONTROL;
}
void _serial_disable_rtscts(void)
{
hwp_uart->ctrl &= ~UART_AUTO_FLOW_CONTROL;
}
void _serial_init(void)
{
_serial_set_baudrate(CONFIG_BAUDRATE);
hwp_uart->triggers = UART_AFC_LEVEL(1); //7 ?
hwp_uart->ctrl = UART_ENABLE | UART_DATA_BITS_8_BITS |
UART_TX_STOP_BITS_1_BIT | UART_PARITY_ENABLE_NO;
/* Allow reception */
hwp_uart->CMD_Set = UART_RTS;
}
void _serial_deinit(void)
{
hwp_uart->ctrl = 0;
hwp_uart->CMD_Clr = UART_RTS;
}
/*
* Test whether a character is in the RX buffer
*/
int _serial_tstc(const int port)
{
return (GET_BITFIELD(hwp_uart->status, UART_RX_FIFO_LEVEL));
}
int _serial_getc(const int port)
{
/* wait for character to arrive */ ;
while (!(GET_BITFIELD(hwp_uart->status, UART_RX_FIFO_LEVEL)))
;
return (hwp_uart->rxtx_buffer & 0xff);
}
void _serial_putc_hw(const char c, const int port)
{
// Place in the TX Fifo ?
while (!(GET_BITFIELD(hwp_uart->status, UART_TX_FIFO_SPACE)))
;
hwp_uart->rxtx_buffer = (u32)c;
}
void _serial_putc(const char c, const int port)
{
if (c == '\n') {
_serial_putc_hw('\r', 0);
}
_serial_putc_hw(c, 0);
}
void _serial_puts(const char *s, const int port)
{
while (*s) {
_serial_putc(*s++, 0);
}
}
static int hwflow = 0; /* turned off by default */
int hwflow_onoff(int on)
{
switch(on) {
case 0:
default:
break; /* return current */
case 1:
hwflow = 1;
_serial_enable_rtscts(); /* turn on */
break;
case -1:
hwflow = 0;
_serial_disable_rtscts(); /* turn off */
break;
}
return hwflow;
}
int serial_init(void)
{
//_serial_init(); // already init in boot_test
return 0;
}
int serial_getc(void)
{
return _serial_getc(0);
}
int serial_tstc(void)
{
return _serial_tstc(0);
}
void serial_putc(const char c)
{
_serial_putc(c, 0);
}
void serial_puts(const char *s)
{
_serial_puts(s, 0);
}
void serial_setbrg (void)
{
}

View File

@ -0,0 +1,74 @@
#include <common.h>
#include <asm/u-boot.h>
#include <asm/utils.h>
#include <nand.h>
#include <malloc.h>
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
DECLARE_GLOBAL_DATA_PTR;
/* Define global data structure pointer to it*/
static gd_t gdata __attribute__ ((section(".data")));
static bd_t bdata __attribute__ ((section(".data")));
#else
void puts(const char *str)
{
while (*str)
putc(*str++);
}
void putc(char c)
{
}
#endif /* CONFIG_SPL_LIBCOMMON_SUPPORT */
inline void hang(void)
{
puts("### ERROR ### Please RESET the board ###\n");
for (;;)
;
}
void board_init_f(ulong dummy)
{
relocate_code(CONFIG_SPL_STACK, NULL, CONFIG_SPL_TEXT_BASE);
}
void board_init_r(gd_t *id, ulong dummy)
{
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
gd = &gdata;
gd->bd = &bdata;
gd->flags |= GD_FLG_RELOC;
gd->baudrate = CONFIG_BAUDRATE;
serial_init(); /* serial communications setup */
gd->have_console = 1;
#endif
puts("board_init_r\n");
while(1)
;
#if 0
#ifdef CONFIG_SPL_NAND_LOAD
nand_init();
puts("Nand boot...\n");
nand_boot();
#endif
#ifdef CONFIG_SPL_SPI_LOAD
mem_malloc_init(CONFIG_SYS_TEXT_BASE - CONFIG_SYS_MALLOC_LEN,
CONFIG_SYS_MALLOC_LEN);
gd = &gdata;
gd->bd = &bdata;
gd->flags |= GD_FLG_RELOC;
gd->baudrate = CONFIG_BAUDRATE;
serial_init(); /* serial communications setup */
gd->have_console = 1;
puts("SPI boot...\n");
spi_boot();
#endif
#endif
}

View File

@ -0,0 +1,93 @@
#include <common.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/rda_iomap.h>
DECLARE_GLOBAL_DATA_PTR;
typedef volatile struct
{
REG32 OSTimer_Ctrl; //0x00000000
REG32 OSTimer_CurVal; //0x00000004
REG32 WDTimer_Ctrl; //0x00000008
REG32 WDTimer_LoadVal; //0x0000000C
REG32 HWTimer_Ctrl; //0x00000010
REG32 HWTimer_CurVal; //0x00000014
REG32 Timer_Irq_Mask_Set; //0x00000018
REG32 Timer_Irq_Mask_Clr; //0x0000001C
REG32 Timer_Irq_Clr; //0x00000020
REG32 Timer_Irq_Cause; //0x00000024
} HWP_TIMER_T;
#define hwp_timer ((HWP_TIMER_T*)(RDA_TIMER_BASE))
int timer_init(void)
{
gd->timer_rate_hz = CONFIG_SYS_HZ_CLOCK;
gd->timer_reset_value = 0;
/* We are using timer34 in unchained 32-bit mode, full speed */
return(0);
}
void reset_timer(void)
{
gd->timer_reset_value = get_ticks();
}
/*
* Get the current 64 bit timer tick count
*/
unsigned long long get_ticks(void)
{
unsigned long now = hwp_timer->HWTimer_CurVal;
/* increment tbu if tbl has rolled over */
if (now < gd->tbl)
gd->tbu++;
gd->tbl = now;
return (((unsigned long long)gd->tbu) << 32) | gd->tbl;
}
ulong get_timer(ulong base)
{
unsigned long long timer_diff;
timer_diff = get_ticks() - gd->timer_reset_value;
return (timer_diff / (gd->timer_rate_hz / CONFIG_SYS_HZ)) - base;
}
#pragma GCC push_options
#pragma GCC optimize ("O0")
void __udelay(unsigned long usec)
{
#if 0 /* our timer is 16kHz, can NOT support udelay */
unsigned long long endtime;
endtime = ((unsigned long long)usec * gd->timer_rate_hz) / 1000000UL;
endtime += get_ticks();
while (get_ticks() < endtime)
;
#else /* use loop instead */
#define USEC_LOOP (1)
int i, j;
for (i=0;i<(usec);i++)
for (j=0;j<USEC_LOOP;j++)
;
#endif
}
#pragma GCC pop_options
/*
* This function is derived from PowerPC code (timebase clock frequency).
* On ARM it returns the number of timer ticks per second.
*/
ulong get_tbclk(void)
{
return CONFIG_SYS_HZ;
}

View File

@ -105,7 +105,7 @@ void init_timer(void)
#if defined(CONFIG_OMAP_HSMMC) && !defined(CONFIG_SPL_BUILD)
int board_mmc_init(bd_t *bis)
{
return omap_mmc_init(0);
return omap_mmc_init(0, 0, 0);
}
#endif

View File

@ -22,8 +22,11 @@
#
PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float
# Make ARMv5 to allow more compilers to work, even though its v7a.
PLATFORM_CPPFLAGS += -march=armv5
# If armv7-a is not supported by GCC fall-back to armv5, which is
# supported by more tool-chains
PF_CPPFLAGS_ARMV7 := $(call cc-option, -march=armv7-a, -march=armv5)
PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_ARMV7)
# =========================================================================
#
# Supply options according to compiler version

View File

@ -22,7 +22,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).o
COBJS += clock.o soc.o
COBJS += clock.o power.o soc.o system.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS))

View File

@ -414,6 +414,170 @@ static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
writel(val, addr);
}
/* get_lcd_clk: return lcd clock frequency */
static unsigned long exynos4_get_lcd_clk(void)
{
struct exynos4_clock *clk =
(struct exynos4_clock *)samsung_get_base_clock();
unsigned long pclk, sclk;
unsigned int sel;
unsigned int ratio;
/*
* CLK_SRC_LCD0
* FIMD0_SEL [3:0]
*/
sel = readl(&clk->src_lcd0);
sel = sel & 0xf;
/*
* 0x6: SCLK_MPLL
* 0x7: SCLK_EPLL
* 0x8: SCLK_VPLL
*/
if (sel == 0x6)
sclk = get_pll_clk(MPLL);
else if (sel == 0x7)
sclk = get_pll_clk(EPLL);
else if (sel == 0x8)
sclk = get_pll_clk(VPLL);
else
return 0;
/*
* CLK_DIV_LCD0
* FIMD0_RATIO [3:0]
*/
ratio = readl(&clk->div_lcd0);
ratio = ratio & 0xf;
pclk = sclk / (ratio + 1);
return pclk;
}
void exynos4_set_lcd_clk(void)
{
struct exynos4_clock *clk =
(struct exynos4_clock *)samsung_get_base_clock();
unsigned int cfg = 0;
/*
* CLK_GATE_BLOCK
* CLK_CAM [0]
* CLK_TV [1]
* CLK_MFC [2]
* CLK_G3D [3]
* CLK_LCD0 [4]
* CLK_LCD1 [5]
* CLK_GPS [7]
*/
cfg = readl(&clk->gate_block);
cfg |= 1 << 4;
writel(cfg, &clk->gate_block);
/*
* CLK_SRC_LCD0
* FIMD0_SEL [3:0]
* MDNIE0_SEL [7:4]
* MDNIE_PWM0_SEL [8:11]
* MIPI0_SEL [12:15]
* set lcd0 src clock 0x6: SCLK_MPLL
*/
cfg = readl(&clk->src_lcd0);
cfg &= ~(0xf);
cfg |= 0x6;
writel(cfg, &clk->src_lcd0);
/*
* CLK_GATE_IP_LCD0
* CLK_FIMD0 [0]
* CLK_MIE0 [1]
* CLK_MDNIE0 [2]
* CLK_DSIM0 [3]
* CLK_SMMUFIMD0 [4]
* CLK_PPMULCD0 [5]
* Gating all clocks for FIMD0
*/
cfg = readl(&clk->gate_ip_lcd0);
cfg |= 1 << 0;
writel(cfg, &clk->gate_ip_lcd0);
/*
* CLK_DIV_LCD0
* FIMD0_RATIO [3:0]
* MDNIE0_RATIO [7:4]
* MDNIE_PWM0_RATIO [11:8]
* MDNIE_PWM_PRE_RATIO [15:12]
* MIPI0_RATIO [19:16]
* MIPI0_PRE_RATIO [23:20]
* set fimd ratio
*/
cfg &= ~(0xf);
cfg |= 0x1;
writel(cfg, &clk->div_lcd0);
}
void exynos4_set_mipi_clk(void)
{
struct exynos4_clock *clk =
(struct exynos4_clock *)samsung_get_base_clock();
unsigned int cfg = 0;
/*
* CLK_SRC_LCD0
* FIMD0_SEL [3:0]
* MDNIE0_SEL [7:4]
* MDNIE_PWM0_SEL [8:11]
* MIPI0_SEL [12:15]
* set mipi0 src clock 0x6: SCLK_MPLL
*/
cfg = readl(&clk->src_lcd0);
cfg &= ~(0xf << 12);
cfg |= (0x6 << 12);
writel(cfg, &clk->src_lcd0);
/*
* CLK_SRC_MASK_LCD0
* FIMD0_MASK [0]
* MDNIE0_MASK [4]
* MDNIE_PWM0_MASK [8]
* MIPI0_MASK [12]
* set src mask mipi0 0x1: Unmask
*/
cfg = readl(&clk->src_mask_lcd0);
cfg |= (0x1 << 12);
writel(cfg, &clk->src_mask_lcd0);
/*
* CLK_GATE_IP_LCD0
* CLK_FIMD0 [0]
* CLK_MIE0 [1]
* CLK_MDNIE0 [2]
* CLK_DSIM0 [3]
* CLK_SMMUFIMD0 [4]
* CLK_PPMULCD0 [5]
* Gating all clocks for MIPI0
*/
cfg = readl(&clk->gate_ip_lcd0);
cfg |= 1 << 3;
writel(cfg, &clk->gate_ip_lcd0);
/*
* CLK_DIV_LCD0
* FIMD0_RATIO [3:0]
* MDNIE0_RATIO [7:4]
* MDNIE_PWM0_RATIO [11:8]
* MDNIE_PWM_PRE_RATIO [15:12]
* MIPI0_RATIO [19:16]
* MIPI0_PRE_RATIO [23:20]
* set mipi ratio
*/
cfg &= ~(0xf << 16);
cfg |= (0x1 << 16);
writel(cfg, &clk->div_lcd0);
}
unsigned long get_pll_clk(int pllreg)
{
if (cpu_is_exynos5())
@ -453,3 +617,23 @@ void set_mmc_clk(int dev_index, unsigned int div)
else
exynos4_set_mmc_clk(dev_index, div);
}
unsigned long get_lcd_clk(void)
{
if (cpu_is_exynos4())
return exynos4_get_lcd_clk();
else
return 0;
}
void set_lcd_clk(void)
{
if (cpu_is_exynos4())
exynos4_set_lcd_clk();
}
void set_mipi_clk(void)
{
if (cpu_is_exynos4())
exynos4_set_mipi_clk();
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2012 Samsung Electronics
* Donghwa Lee <dh09.lee@samsung.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/power.h>
static void exynos4_mipi_phy_control(unsigned int dev_index,
unsigned int enable)
{
struct exynos4_power *pmu =
(struct exynos4_power *)samsung_get_base_power();
unsigned int addr, cfg = 0;
if (dev_index == 0)
addr = (unsigned int)&pmu->mipi_phy0_control;
else
addr = (unsigned int)&pmu->mipi_phy1_control;
cfg = readl(addr);
if (enable)
cfg |= (EXYNOS_MIPI_PHY_MRESETN | EXYNOS_MIPI_PHY_ENABLE);
else
cfg &= ~(EXYNOS_MIPI_PHY_MRESETN | EXYNOS_MIPI_PHY_ENABLE);
writel(cfg, addr);
}
void set_mipi_phy_ctrl(unsigned int dev_index, unsigned int enable)
{
if (cpu_is_exynos4())
exynos4_mipi_phy_control(dev_index, enable);
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2012 Samsung Electronics
* Donghwa Lee <dh09.lee@samsung.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/system.h>
static void exynos4_set_system_display(void)
{
struct exynos4_sysreg *sysreg =
(struct exynos4_sysreg *)samsung_get_base_sysreg();
unsigned int cfg = 0;
/*
* system register path set
* 0: MIE/MDNIE
* 1: FIMD Bypass
*/
cfg = readl(&sysreg->display_ctrl);
cfg |= (1 << 1);
writel(cfg, &sysreg->display_ctrl);
}
void set_system_display_ctrl(void)
{
if (cpu_is_exynos4())
exynos4_set_system_display();
}

View File

@ -29,12 +29,13 @@
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/crm_regs.h>
#ifdef CONFIG_FSL_ESDHC
#include <fsl_esdhc.h>
#endif
static char *get_reset_cause(void)
char *get_reset_cause(void)
{
u32 cause;
struct src *src_regs = (struct src *)SRC_BASE_ADDR;
@ -127,3 +128,15 @@ void reset_cpu(ulong addr)
{
__raw_writew(4, WDOG1_BASE_ADDR);
}
u32 get_ahb_clk(void)
{
struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
u32 reg, ahb_podf;
reg = __raw_readl(&imx_ccm->cbcdr);
reg &= MXC_CCM_CBCDR_AHB_PODF_MASK;
ahb_podf = reg >> MXC_CCM_CBCDR_AHB_PODF_OFFSET;
return get_periph_clk() / (ahb_podf + 1);
}

View File

@ -30,6 +30,7 @@
#include <asm/arch/crm_regs.h>
#include <asm/arch/clock.h>
#include <div64.h>
#include <asm/arch/sys_proto.h>
enum pll_clocks {
PLL1_CLOCK = 0,
@ -48,6 +49,42 @@ struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
#endif
};
#define AHB_CLK_ROOT 133333333
#define SZ_DEC_1M 1000000
#define PLL_PD_MAX 16 /* Actual pd+1 */
#define PLL_MFI_MAX 15
#define PLL_MFI_MIN 5
#define ARM_DIV_MAX 8
#define IPG_DIV_MAX 4
#define AHB_DIV_MAX 8
#define EMI_DIV_MAX 8
#define NFC_DIV_MAX 8
#define MX5_CBCMR 0x00015154
#define MX5_CBCDR 0x02888945
struct fixed_pll_mfd {
u32 ref_clk_hz;
u32 mfd;
};
const struct fixed_pll_mfd fixed_mfd[] = {
{CONFIG_SYS_MX5_HCLK, 24 * 16},
};
struct pll_param {
u32 pd;
u32 mfi;
u32 mfn;
u32 mfd;
};
#define PLL_FREQ_MAX(ref_clk) (4 * (ref_clk) * PLL_MFI_MAX)
#define PLL_FREQ_MIN(ref_clk) \
((2 * (ref_clk) * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
#define MAX_DDR_CLK 420000000
#define NFC_CLK_MAX 34000000
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
void set_usboh3_clk(void)
@ -192,7 +229,7 @@ u32 get_mcu_main_clk(void)
/*
* Get the rate of peripheral's root clock.
*/
static u32 get_periph_clk(void)
u32 get_periph_clk(void)
{
u32 reg;
@ -212,22 +249,6 @@ static u32 get_periph_clk(void)
/* NOTREACHED */
}
/*
* Get the rate of ahb clock.
*/
static u32 get_ahb_clk(void)
{
uint32_t freq, div, reg;
freq = get_periph_clk();
reg = __raw_readl(&mxc_ccm->cbcdr);
div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
return freq / div;
}
/*
* Get the rate of ipg clock.
*/
@ -306,7 +327,7 @@ static u32 get_uart_clk(void)
/*
* This function returns the low power audio clock.
*/
u32 get_lp_apm(void)
static u32 get_lp_apm(void)
{
u32 ret_val = 0;
u32 ccsr = __raw_readl(&mxc_ccm->ccsr);
@ -322,7 +343,7 @@ u32 get_lp_apm(void)
/*
* get cspi clock rate.
*/
u32 imx_get_cspiclk(void)
static u32 imx_get_cspiclk(void)
{
u32 ret_val = 0, pdf, pre_pdf, clk_sel;
u32 cscmr1 = __raw_readl(&mxc_ccm->cscmr1);
@ -359,8 +380,77 @@ u32 imx_get_cspiclk(void)
return ret_val;
}
static u32 get_axi_a_clk(void)
{
u32 cbcdr = __raw_readl(&mxc_ccm->cbcdr);
u32 pdf = (cbcdr & MXC_CCM_CBCDR_AXI_A_PODF_MASK) \
>> MXC_CCM_CBCDR_AXI_A_PODF_OFFSET;
return get_periph_clk() / (pdf + 1);
}
static u32 get_axi_b_clk(void)
{
u32 cbcdr = __raw_readl(&mxc_ccm->cbcdr);
u32 pdf = (cbcdr & MXC_CCM_CBCDR_AXI_B_PODF_MASK) \
>> MXC_CCM_CBCDR_AXI_B_PODF_OFFSET;
return get_periph_clk() / (pdf + 1);
}
static u32 get_emi_slow_clk(void)
{
u32 cbcdr = __raw_readl(&mxc_ccm->cbcdr);
u32 emi_clk_sel = cbcdr & MXC_CCM_CBCDR_EMI_CLK_SEL;
u32 pdf = (cbcdr & MXC_CCM_CBCDR_EMI_PODF_MASK) \
>> MXC_CCM_CBCDR_EMI_PODF_OFFSET;
if (emi_clk_sel)
return get_ahb_clk() / (pdf + 1);
return get_periph_clk() / (pdf + 1);
}
static u32 get_ddr_clk(void)
{
u32 ret_val = 0;
u32 cbcmr = __raw_readl(&mxc_ccm->cbcmr);
u32 ddr_clk_sel = (cbcmr & MXC_CCM_CBCMR_DDR_CLK_SEL_MASK) \
>> MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET;
#ifdef CONFIG_MX51
u32 cbcdr = __raw_readl(&mxc_ccm->cbcdr);
if (cbcdr & MXC_CCM_CBCDR_DDR_HIFREQ_SEL) {
u32 ddr_clk_podf = (cbcdr & MXC_CCM_CBCDR_DDR_PODF_MASK) >> \
MXC_CCM_CBCDR_DDR_PODF_OFFSET;
ret_val = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
ret_val /= ddr_clk_podf + 1;
return ret_val;
}
#endif
switch (ddr_clk_sel) {
case 0:
ret_val = get_axi_a_clk();
break;
case 1:
ret_val = get_axi_b_clk();
break;
case 2:
ret_val = get_emi_slow_clk();
break;
case 3:
ret_val = get_ahb_clk();
break;
default:
break;
}
return ret_val;
}
/*
* The API of get mxc clockes.
* The API of get mxc clocks.
*/
unsigned int mxc_get_clock(enum mxc_clock clk)
{
@ -380,10 +470,14 @@ unsigned int mxc_get_clock(enum mxc_clock clk)
case MXC_FEC_CLK:
return decode_pll(mxc_plls[PLL1_CLOCK],
CONFIG_SYS_MX5_HCLK);
case MXC_SATA_CLK:
return get_ahb_clk();
case MXC_DDR_CLK:
return get_ddr_clk();
default:
break;
}
return -1;
return -EINVAL;
}
u32 imx_get_uartclk(void)
@ -397,6 +491,362 @@ u32 imx_get_fecclk(void)
return mxc_get_clock(MXC_IPG_CLK);
}
static int gcd(int m, int n)
{
int t;
while (m > 0) {
if (n > m) {
t = m;
m = n;
n = t;
} /* swap */
m -= n;
}
return n;
}
/*
* This is to calculate various parameters based on reference clock and
* targeted clock based on the equation:
* t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
* This calculation is based on a fixed MFD value for simplicity.
*/
static int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
{
u64 pd, mfi = 1, mfn, mfd, t1;
u32 n_target = target;
u32 n_ref = ref, i;
/*
* Make sure targeted freq is in the valid range.
* Otherwise the following calculation might be wrong!!!
*/
if (n_target < PLL_FREQ_MIN(ref) ||
n_target > PLL_FREQ_MAX(ref)) {
printf("Targeted peripheral clock should be"
"within [%d - %d]\n",
PLL_FREQ_MIN(ref) / SZ_DEC_1M,
PLL_FREQ_MAX(ref) / SZ_DEC_1M);
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(fixed_mfd); i++) {
if (fixed_mfd[i].ref_clk_hz == ref) {
mfd = fixed_mfd[i].mfd;
break;
}
}
if (i == ARRAY_SIZE(fixed_mfd))
return -EINVAL;
/* Use n_target and n_ref to avoid overflow */
for (pd = 1; pd <= PLL_PD_MAX; pd++) {
t1 = n_target * pd;
do_div(t1, (4 * n_ref));
mfi = t1;
if (mfi > PLL_MFI_MAX)
return -EINVAL;
else if (mfi < 5)
continue;
break;
}
/*
* Now got pd and mfi already
*
* mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref;
*/
t1 = n_target * pd;
do_div(t1, 4);
t1 -= n_ref * mfi;
t1 *= mfd;
do_div(t1, n_ref);
mfn = t1;
debug("ref=%d, target=%d, pd=%d," "mfi=%d,mfn=%d, mfd=%d\n",
ref, n_target, (u32)pd, (u32)mfi, (u32)mfn, (u32)mfd);
i = 1;
if (mfn != 0)
i = gcd(mfd, mfn);
pll->pd = (u32)pd;
pll->mfi = (u32)mfi;
do_div(mfn, i);
pll->mfn = (u32)mfn;
do_div(mfd, i);
pll->mfd = (u32)mfd;
return 0;
}
#define calc_div(tgt_clk, src_clk, limit) ({ \
u32 v = 0; \
if (((src_clk) % (tgt_clk)) <= 100) \
v = (src_clk) / (tgt_clk); \
else \
v = ((src_clk) / (tgt_clk)) + 1;\
if (v > limit) \
v = limit; \
(v - 1); \
})
#define CHANGE_PLL_SETTINGS(pll, pd, fi, fn, fd) \
{ \
__raw_writel(0x1232, &pll->ctrl); \
__raw_writel(0x2, &pll->config); \
__raw_writel((((pd) - 1) << 0) | ((fi) << 4), \
&pll->op); \
__raw_writel(fn, &(pll->mfn)); \
__raw_writel((fd) - 1, &pll->mfd); \
__raw_writel((((pd) - 1) << 0) | ((fi) << 4), \
&pll->hfs_op); \
__raw_writel(fn, &pll->hfs_mfn); \
__raw_writel((fd) - 1, &pll->hfs_mfd); \
__raw_writel(0x1232, &pll->ctrl); \
while (!__raw_readl(&pll->ctrl) & 0x1) \
;\
}
static int config_pll_clk(enum pll_clocks index, struct pll_param *pll_param)
{
u32 ccsr = __raw_readl(&mxc_ccm->ccsr);
struct mxc_pll_reg *pll = mxc_plls[index];
switch (index) {
case PLL1_CLOCK:
/* Switch ARM to PLL2 clock */
__raw_writel(ccsr | 0x4, &mxc_ccm->ccsr);
CHANGE_PLL_SETTINGS(pll, pll_param->pd,
pll_param->mfi, pll_param->mfn,
pll_param->mfd);
/* Switch back */
__raw_writel(ccsr & ~0x4, &mxc_ccm->ccsr);
break;
case PLL2_CLOCK:
/* Switch to pll2 bypass clock */
__raw_writel(ccsr | 0x2, &mxc_ccm->ccsr);
CHANGE_PLL_SETTINGS(pll, pll_param->pd,
pll_param->mfi, pll_param->mfn,
pll_param->mfd);
/* Switch back */
__raw_writel(ccsr & ~0x2, &mxc_ccm->ccsr);
break;
case PLL3_CLOCK:
/* Switch to pll3 bypass clock */
__raw_writel(ccsr | 0x1, &mxc_ccm->ccsr);
CHANGE_PLL_SETTINGS(pll, pll_param->pd,
pll_param->mfi, pll_param->mfn,
pll_param->mfd);
/* Switch back */
__raw_writel(ccsr & ~0x1, &mxc_ccm->ccsr);
break;
case PLL4_CLOCK:
/* Switch to pll4 bypass clock */
__raw_writel(ccsr | 0x20, &mxc_ccm->ccsr);
CHANGE_PLL_SETTINGS(pll, pll_param->pd,
pll_param->mfi, pll_param->mfn,
pll_param->mfd);
/* Switch back */
__raw_writel(ccsr & ~0x20, &mxc_ccm->ccsr);
break;
default:
return -EINVAL;
}
return 0;
}
/* Config CPU clock */
static int config_core_clk(u32 ref, u32 freq)
{
int ret = 0;
struct pll_param pll_param;
memset(&pll_param, 0, sizeof(struct pll_param));
/* The case that periph uses PLL1 is not considered here */
ret = calc_pll_params(ref, freq, &pll_param);
if (ret != 0) {
printf("Error:Can't find pll parameters: %d\n", ret);
return ret;
}
return config_pll_clk(PLL1_CLOCK, &pll_param);
}
static int config_nfc_clk(u32 nfc_clk)
{
u32 reg;
u32 parent_rate = get_emi_slow_clk();
u32 div = parent_rate / nfc_clk;
if (nfc_clk <= 0)
return -EINVAL;
if (div == 0)
div++;
if (parent_rate / div > NFC_CLK_MAX)
div++;
reg = __raw_readl(&mxc_ccm->cbcdr);
reg &= ~MXC_CCM_CBCDR_NFC_PODF_MASK;
reg |= (div - 1) << MXC_CCM_CBCDR_NFC_PODF_OFFSET;
__raw_writel(reg, &mxc_ccm->cbcdr);
while (__raw_readl(&mxc_ccm->cdhipr) != 0)
;
return 0;
}
/* Config main_bus_clock for periphs */
static int config_periph_clk(u32 ref, u32 freq)
{
int ret = 0;
struct pll_param pll_param;
memset(&pll_param, 0, sizeof(struct pll_param));
if (__raw_readl(&mxc_ccm->cbcdr) & MXC_CCM_CBCDR_PERIPH_CLK_SEL) {
ret = calc_pll_params(ref, freq, &pll_param);
if (ret != 0) {
printf("Error:Can't find pll parameters: %d\n",
ret);
return ret;
}
switch ((__raw_readl(&mxc_ccm->cbcmr) & \
MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK) >> \
MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET) {
case 0:
return config_pll_clk(PLL1_CLOCK, &pll_param);
break;
case 1:
return config_pll_clk(PLL3_CLOCK, &pll_param);
break;
default:
return -EINVAL;
}
}
return 0;
}
static int config_ddr_clk(u32 emi_clk)
{
u32 clk_src;
s32 shift = 0, clk_sel, div = 1;
u32 cbcmr = __raw_readl(&mxc_ccm->cbcmr);
u32 cbcdr = __raw_readl(&mxc_ccm->cbcdr);
if (emi_clk > MAX_DDR_CLK) {
printf("Warning:DDR clock should not exceed %d MHz\n",
MAX_DDR_CLK / SZ_DEC_1M);
emi_clk = MAX_DDR_CLK;
}
clk_src = get_periph_clk();
/* Find DDR clock input */
clk_sel = (cbcmr >> 10) & 0x3;
switch (clk_sel) {
case 0:
shift = 16;
break;
case 1:
shift = 19;
break;
case 2:
shift = 22;
break;
case 3:
shift = 10;
break;
default:
return -EINVAL;
}
if ((clk_src % emi_clk) < 10000000)
div = clk_src / emi_clk;
else
div = (clk_src / emi_clk) + 1;
if (div > 8)
div = 8;
cbcdr = cbcdr & ~(0x7 << shift);
cbcdr |= ((div - 1) << shift);
__raw_writel(cbcdr, &mxc_ccm->cbcdr);
while (__raw_readl(&mxc_ccm->cdhipr) != 0)
;
__raw_writel(0x0, &mxc_ccm->ccdr);
return 0;
}
/*
* This function assumes the expected core clock has to be changed by
* modifying the PLL. This is NOT true always but for most of the times,
* it is. So it assumes the PLL output freq is the same as the expected
* core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
* In the latter case, it will try to increase the presc value until
* (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
* calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
* on the targeted PLL and reference input clock to the PLL. Lastly,
* it sets the register based on these values along with the dividers.
* Note 1) There is no value checking for the passed-in divider values
* so the caller has to make sure those values are sensible.
* 2) Also adjust the NFC divider such that the NFC clock doesn't
* exceed NFC_CLK_MAX.
* 3) IPU HSP clock is independent of AHB clock. Even it can go up to
* 177MHz for higher voltage, this function fixes the max to 133MHz.
* 4) This function should not have allowed diag_printf() calls since
* the serial driver has been stoped. But leave then here to allow
* easy debugging by NOT calling the cyg_hal_plf_serial_stop().
*/
int mxc_set_clock(u32 ref, u32 freq, enum mxc_clock clk)
{
freq *= SZ_DEC_1M;
switch (clk) {
case MXC_ARM_CLK:
if (config_core_clk(ref, freq))
return -EINVAL;
break;
case MXC_PERIPH_CLK:
if (config_periph_clk(ref, freq))
return -EINVAL;
break;
case MXC_DDR_CLK:
if (config_ddr_clk(freq))
return -EINVAL;
break;
case MXC_NFC_CLK:
if (config_nfc_clk(freq))
return -EINVAL;
break;
default:
printf("Warning:Unsupported or invalid clock type\n");
}
return 0;
}
#ifdef CONFIG_MX53
/*
* The clock for the external interface can be set to use internal clock
* if fuse bank 4, row 3, bit 2 is set.
* This is an undocumented feature and it was confirmed by Freescale's support:
* Fuses (but not pins) may be used to configure SATA clocks.
* Particularly the i.MX53 Fuse_Map contains the next information
* about configuring SATA clocks : SATA_ALT_REF_CLK[1:0] (offset 0x180C)
* '00' - 100MHz (External)
* '01' - 50MHz (External)
* '10' - 120MHz, internal (USB PHY)
* '11' - Reserved
*/
void mxc_set_sata_internal_clock(void)
{
u32 *tmp_base =
(u32 *)(IIM_BASE_ADDR + 0x180c);
set_usb_phy1_clk();
writel((readl(tmp_base) & (~0x7)) | 0x4, tmp_base);
}
#endif
/*
* Dump some core clockes.
*/
@ -419,6 +869,7 @@ int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
printf("AHB %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000);
printf("IPG %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000);
printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000);
printf("DDR %8d kHz\n", mxc_get_clock(MXC_DDR_CLK) / 1000);
return 0;
}

View File

@ -22,6 +22,7 @@
#include <config.h>
#include <asm/arch/imx-regs.h>
#include <generated/asm-offsets.h>
#include <linux/linkage.h>
/*
* L2CC Cache setup/invalidation/disable
@ -326,8 +327,7 @@
.section ".text.init", "x"
.globl lowlevel_init
lowlevel_init:
ENTRY(lowlevel_init)
#if defined(CONFIG_MX51)
ldr r0, =GPIO1_BASE_ADDR
ldr r1, [r0, #0x0]
@ -348,6 +348,7 @@ lowlevel_init:
/* r12 saved upper lr*/
mov pc,lr
ENDPROC(lowlevel_init)
/* Board level setting value */
W_DP_OP_864: .word DP_OP_864

View File

@ -24,8 +24,9 @@
#include <asm/io.h>
#include <asm/errno.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/ccm_regs.h>
#include <asm/arch/crm_regs.h>
#include <asm/arch/clock.h>
#include <asm/arch/sys_proto.h>
enum pll_clocks {
PLL_SYS, /* System PLL */
@ -34,7 +35,7 @@ enum pll_clocks {
PLL_ENET, /* ENET PLL */
};
struct imx_ccm_reg *imx_ccm = (struct imx_ccm_reg *)CCM_BASE_ADDR;
struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
void enable_usboh3_clk(unsigned char enable)
{
@ -92,7 +93,7 @@ static u32 get_mcu_main_clk(void)
return freq / (reg + 1);
}
static u32 get_periph_clk(void)
u32 get_periph_clk(void)
{
u32 reg, freq = 0;
@ -139,18 +140,6 @@ static u32 get_periph_clk(void)
return freq;
}
static u32 get_ahb_clk(void)
{
u32 reg, ahb_podf;
reg = __raw_readl(&imx_ccm->cbcdr);
reg &= MXC_CCM_CBCDR_AHB_PODF_MASK;
ahb_podf = reg >> MXC_CCM_CBCDR_AHB_PODF_OFFSET;
return get_periph_clk() / (ahb_podf + 1);
}
static u32 get_ipg_clk(void)
{
u32 reg, ipg_podf;
@ -303,6 +292,37 @@ u32 imx_get_fecclk(void)
return decode_pll(PLL_ENET, CONFIG_SYS_MX6_HCLK);
}
int enable_sata_clock(void)
{
u32 reg = 0;
s32 timeout = 100000;
struct mxc_ccm_reg *const imx_ccm
= (struct mxc_ccm_reg *) CCM_BASE_ADDR;
/* Enable sata clock */
reg = readl(&imx_ccm->CCGR5); /* CCGR5 */
reg |= MXC_CCM_CCGR5_CG2_MASK;
writel(reg, &imx_ccm->CCGR5);
/* Enable PLLs */
reg = readl(&imx_ccm->analog_pll_enet);
reg &= ~BM_ANADIG_PLL_SYS_POWERDOWN;
writel(reg, &imx_ccm->analog_pll_enet);
reg |= BM_ANADIG_PLL_SYS_ENABLE;
while (timeout--) {
if (readl(&imx_ccm->analog_pll_enet) & BM_ANADIG_PLL_SYS_LOCK)
break;
}
if (timeout <= 0)
return -EIO;
reg &= ~BM_ANADIG_PLL_SYS_BYPASS;
writel(reg, &imx_ccm->analog_pll_enet);
reg |= BM_ANADIG_PLL_ENET_ENABLE_SATA;
writel(reg, &imx_ccm->analog_pll_enet);
return 0 ;
}
unsigned int mxc_get_clock(enum mxc_clock clk)
{
switch (clk) {

View File

@ -18,7 +18,8 @@
*/
.section ".text.init", "x"
.globl lowlevel_init
lowlevel_init:
#include <linux/linkage.h>
ENTRY(lowlevel_init)
mov pc, lr
ENDPROC(lowlevel_init)

View File

@ -77,10 +77,40 @@ void init_aips(void)
writel(0x00000000, &aips2->opacr4);
}
/*
* Set the VDDSOC
*
* Mask out the REG_CORE[22:18] bits (REG2_TRIG) and set
* them to the specified millivolt level.
* Possible values are from 0.725V to 1.450V in steps of
* 0.025V (25mV).
*/
void set_vddsoc(u32 mv)
{
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
u32 val, reg = readl(&anatop->reg_core);
if (mv < 725)
val = 0x00; /* Power gated off */
else if (mv > 1450)
val = 0x1F; /* Power FET switched full on. No regulation */
else
val = (mv - 700) / 25;
/*
* Mask out the REG_CORE[22:18] bits (REG2_TRIG)
* and set them to the calculated value (0.7V + val * 0.25V)
*/
reg = (reg & ~(0x1F << 18)) | (val << 18);
writel(reg, &anatop->reg_core);
}
int arch_cpu_init(void)
{
init_aips();
set_vddsoc(1200); /* Set VDDSOC to 1.2V */
return 0;
}
#endif

View File

@ -37,6 +37,7 @@ ifneq ($(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),)
COBJS += hwinit-common.o
COBJS += clocks-common.o
COBJS += emif-common.o
COBJS += vc.o
endif
ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),)

View File

@ -245,6 +245,11 @@ void configure_mpu_dpll(void)
CM_CLKSEL_DCC_EN_MASK);
}
setbits_le32(&prcm->cm_mpu_mpu_clkctrl,
MPU_CLKCTRL_CLKSEL_EMIF_DIV_MODE_MASK);
setbits_le32(&prcm->cm_mpu_mpu_clkctrl,
MPU_CLKCTRL_CLKSEL_ABE_DIV_MODE_MASK);
params = get_mpu_dpll_params();
do_setup_dpll(&prcm->cm_clkmode_dpll_mpu, params, DPLL_LOCK, "mpu");
@ -360,56 +365,51 @@ static void setup_non_essential_dplls(void)
}
#endif
void do_scale_tps62361(u32 reg, u32 volt_mv)
void do_scale_tps62361(int gpio, u32 reg, u32 volt_mv)
{
u32 temp, step;
u32 step;
int ret = 0;
/* See if we can first get the GPIO if needed */
if (gpio >= 0)
ret = gpio_request(gpio, "TPS62361_VSEL0_GPIO");
if (ret < 0) {
printf("%s: gpio %d request failed %d\n", __func__, gpio, ret);
gpio = -1;
}
/* Pull the GPIO low to select SET0 register, while we program SET1 */
if (gpio >= 0)
gpio_direction_output(gpio, 0);
step = volt_mv - TPS62361_BASE_VOLT_MV;
step /= 10;
temp = TPS62361_I2C_SLAVE_ADDR |
(reg << PRM_VC_VAL_BYPASS_REGADDR_SHIFT) |
(step << PRM_VC_VAL_BYPASS_DATA_SHIFT) |
PRM_VC_VAL_BYPASS_VALID_BIT;
debug("do_scale_tps62361: volt - %d step - 0x%x\n", volt_mv, step);
writel(temp, &prcm->prm_vc_val_bypass);
if (!wait_on_value(PRM_VC_VAL_BYPASS_VALID_BIT, 0,
&prcm->prm_vc_val_bypass, LDELAY)) {
if (omap_vc_bypass_send_value(TPS62361_I2C_SLAVE_ADDR, reg, step))
puts("Scaling voltage failed for vdd_mpu from TPS\n");
}
/* Pull the GPIO high to select SET1 register */
if (gpio >= 0)
gpio_direction_output(gpio, 1);
}
void do_scale_vcore(u32 vcore_reg, u32 volt_mv)
{
u32 temp, offset_code;
u32 step = 12660; /* 12.66 mV represented in uV */
u32 offset_code;
u32 offset = volt_mv;
/* convert to uV for better accuracy in the calculations */
offset *= 1000;
if (omap_revision() == OMAP4430_ES1_0)
offset -= PHOENIX_SMPS_BASE_VOLT_STD_MODE_UV;
else
offset -= PHOENIX_SMPS_BASE_VOLT_STD_MODE_WITH_OFFSET_UV;
offset_code = (offset + step - 1) / step;
/* The code starts at 1 not 0 */
offset_code++;
offset_code = get_offset_code(offset);
debug("do_scale_vcore: volt - %d offset_code - 0x%x\n", volt_mv,
offset_code);
temp = SMPS_I2C_SLAVE_ADDR |
(vcore_reg << PRM_VC_VAL_BYPASS_REGADDR_SHIFT) |
(offset_code << PRM_VC_VAL_BYPASS_DATA_SHIFT) |
PRM_VC_VAL_BYPASS_VALID_BIT;
writel(temp, &prcm->prm_vc_val_bypass);
if (!wait_on_value(PRM_VC_VAL_BYPASS_VALID_BIT, 0,
&prcm->prm_vc_val_bypass, LDELAY)) {
if (omap_vc_bypass_send_value(SMPS_I2C_SLAVE_ADDR,
vcore_reg, offset_code))
printf("Scaling voltage failed for 0x%x\n", vcore_reg);
}
}
static inline void enable_clock_domain(u32 *const clkctrl_reg, u32 enable_mode)
@ -452,6 +452,7 @@ void freq_update_core(void)
{
u32 freq_config1 = 0;
const struct dpll_params *core_dpll_params;
u32 omap_rev = omap_revision();
core_dpll_params = get_core_dpll_params();
/* Put EMIF clock domain in sw wakeup mode */
@ -477,11 +478,18 @@ void freq_update_core(void)
hang();
}
/* Put EMIF clock domain back in hw auto mode */
enable_clock_domain(&prcm->cm_memif_clkstctrl,
CD_CLKCTRL_CLKTRCTRL_HW_AUTO);
wait_for_clk_enable(&prcm->cm_memif_emif_1_clkctrl);
wait_for_clk_enable(&prcm->cm_memif_emif_2_clkctrl);
/*
* Putting EMIF in HW_AUTO is seen to be causing issues with
* EMIF clocks and the master DLL. Put EMIF in SW_WKUP
* in OMAP5430 ES1.0 silicon
*/
if (omap_rev != OMAP5430_ES1_0) {
/* Put EMIF clock domain back in hw auto mode */
enable_clock_domain(&prcm->cm_memif_clkstctrl,
CD_CLKCTRL_CLKTRCTRL_HW_AUTO);
wait_for_clk_enable(&prcm->cm_memif_emif_1_clkctrl);
wait_for_clk_enable(&prcm->cm_memif_emif_2_clkctrl);
}
}
void bypass_dpll(u32 *const base)
@ -529,29 +537,6 @@ void setup_clocks_for_console(void)
CD_CLKCTRL_CLKTRCTRL_SHIFT);
}
void setup_sri2c(void)
{
u32 sys_clk_khz, cycles_hi, cycles_low, temp;
sys_clk_khz = get_sys_clk_freq() / 1000;
/*
* Setup the dedicated I2C controller for Voltage Control
* I2C clk - high period 40% low period 60%
*/
cycles_hi = sys_clk_khz * 4 / PRM_VC_I2C_CHANNEL_FREQ_KHZ / 10;
cycles_low = sys_clk_khz * 6 / PRM_VC_I2C_CHANNEL_FREQ_KHZ / 10;
/* values to be set in register - less by 5 & 7 respectively */
cycles_hi -= 5;
cycles_low -= 7;
temp = (cycles_hi << PRM_VC_CFG_I2C_CLK_SCLH_SHIFT) |
(cycles_low << PRM_VC_CFG_I2C_CLK_SCLL_SHIFT);
writel(temp, &prcm->prm_vc_cfg_i2c_clk);
/* Disable high speed mode and all advanced features */
writel(0x0, &prcm->prm_vc_cfg_i2c_mode);
}
void do_enable_clocks(u32 *const *clk_domains,
u32 *const *clk_modules_hw_auto,
u32 *const *clk_modules_explicit_en,

View File

@ -90,20 +90,33 @@ static void do_lpddr2_init(u32 base, u32 cs)
* tZQINIT = 1 us
* Enough loops assuming a maximum of 2GHz
*/
sdelay(2000);
set_mr(base, cs, LPDDR2_MR1, MR1_BL_8_BT_SEQ_WRAP_EN_NWR_3);
if (omap_revision() >= OMAP5430_ES1_0)
set_mr(base, cs, LPDDR2_MR1, MR1_BL_8_BT_SEQ_WRAP_EN_NWR_8);
else
set_mr(base, cs, LPDDR2_MR1, MR1_BL_8_BT_SEQ_WRAP_EN_NWR_3);
set_mr(base, cs, LPDDR2_MR16, MR16_REF_FULL_ARRAY);
/*
* Enable refresh along with writing MR2
* Encoding of RL in MR2 is (RL - 2)
*/
mr_addr = LPDDR2_MR2 | EMIF_REG_REFRESH_EN_MASK;
set_mr(base, cs, mr_addr, RL_FINAL - 2);
if (omap_revision() >= OMAP5430_ES1_0)
set_mr(base, cs, LPDDR2_MR3, 0x1);
}
static void lpddr2_init(u32 base, const struct emif_regs *regs)
{
struct emif_reg_struct *emif = (struct emif_reg_struct *)base;
u32 *ext_phy_ctrl_base = 0;
u32 *emif_ext_phy_ctrl_base = 0;
u32 i = 0;
/* Not NVM */
clrbits_le32(&emif->emif_lpddr2_nvm_config, EMIF_REG_CS1NVMEN_MASK);
@ -119,7 +132,31 @@ static void lpddr2_init(u32 base, const struct emif_regs *regs)
* un-locked frequency & default RL
*/
writel(regs->sdram_config_init, &emif->emif_sdram_config);
writel(regs->emif_ddr_phy_ctlr_1_init, &emif->emif_ddr_phy_ctrl_1);
writel(regs->emif_ddr_phy_ctlr_1, &emif->emif_ddr_phy_ctrl_1);
ext_phy_ctrl_base = (u32 *) &(regs->emif_ddr_ext_phy_ctrl_1);
emif_ext_phy_ctrl_base = (u32 *) &(emif->emif_ddr_ext_phy_ctrl_1);
if (omap_revision() >= OMAP5430_ES1_0) {
/* Configure external phy control timing registers */
for (i = 0; i < EMIF_EXT_PHY_CTRL_TIMING_REG; i++) {
writel(*ext_phy_ctrl_base, emif_ext_phy_ctrl_base++);
/* Update shadow registers */
writel(*ext_phy_ctrl_base++, emif_ext_phy_ctrl_base++);
}
/*
* external phy 6-24 registers do not change with
* ddr frequency
*/
for (i = 0; i < EMIF_EXT_PHY_CTRL_CONST_REG; i++) {
writel(ext_phy_ctrl_const_base[i],
emif_ext_phy_ctrl_base++);
/* Update shadow registers */
writel(ext_phy_ctrl_const_base[i],
emif_ext_phy_ctrl_base++);
}
}
do_lpddr2_init(base, CS0);
if (regs->sdram_config & EMIF_REG_EBANK_MASK)

View File

@ -202,22 +202,16 @@ int checkboard(void)
return 0;
}
/*
* This function is called by start_armboot. You can reliably use static
* data. Any boot-time function that require static data should be
* called from here
*/
int arch_cpu_init(void)
{
return 0;
}
/*
* get_device_type(): tell if GP/HS/EMU/TST
*/
u32 get_device_type(void)
{
return 0;
struct omap_sys_ctrl_regs *ctrl =
(struct omap_sys_ctrl_regs *) SYSCTRL_GENERAL_CORE_BASE;
return (readl(&ctrl->control_status) &
(DEVICE_TYPE_MASK)) >> DEVICE_TYPE_SHIFT;
}
/*

View File

@ -27,9 +27,9 @@
*/
#include <asm/arch/omap.h>
#include <linux/linkage.h>
.global save_boot_params
save_boot_params:
ENTRY(save_boot_params)
/*
* See if the rom code passed pointer is valid:
* It is not valid if it is not in non-secure SRAM
@ -76,10 +76,9 @@ save_boot_params:
strb r2, [r3, #CH_FLAGS_OFFSET]
1:
bx lr
ENDPROC(save_boot_params)
.globl lowlevel_init
lowlevel_init:
ENTRY(lowlevel_init)
/*
* Setup a temporary stack
*/
@ -95,12 +94,13 @@ lowlevel_init:
*/
bl s_init
pop {ip, pc}
ENDPROC(lowlevel_init)
.globl set_pl310_ctrl_reg
set_pl310_ctrl_reg:
ENTRY(set_pl310_ctrl_reg)
PUSH {r4-r11, lr} @ save registers - ROM code may pollute
@ our registers
LDR r12, =0x102 @ Set PL310 control register - value in R0
.word 0xe1600070 @ SMC #0 - hand assembled because -march=armv5
@ call ROM Code API to set control register
POP {r4-r11, pc}
ENDPROC(set_pl310_ctrl_reg)

View File

@ -0,0 +1,36 @@
/*
*
* Common layer for reset related functionality of OMAP based socs.
*
* (C) Copyright 2012
* Texas Instruments, <www.ti.com>
*
* Sricharan R <r.sricharan@ti.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <config.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <linux/compiler.h>
void __weak reset_cpu(unsigned long ignored)
{
writel(PRM_RSTCTRL_RESET, PRM_RSTCTRL);
}

View File

@ -162,6 +162,7 @@ void board_init_r(gd_t *id, ulong dummy)
#ifdef CONFIG_SPL_MMC_SUPPORT
case BOOT_DEVICE_MMC1:
case BOOT_DEVICE_MMC2:
case BOOT_DEVICE_MMC2_2:
spl_mmc_load_image();
break;
#endif

View File

@ -39,10 +39,11 @@ int board_mmc_init(bd_t *bis)
{
switch (omap_boot_device()) {
case BOOT_DEVICE_MMC1:
omap_mmc_init(0);
omap_mmc_init(0, 0, 0);
break;
case BOOT_DEVICE_MMC2:
omap_mmc_init(1);
case BOOT_DEVICE_MMC2_2:
omap_mmc_init(1, 0, 0);
break;
}
return 0;

View File

@ -54,7 +54,7 @@ void spl_nand_load_image(void)
* load parameter image
* load to temp position since nand_spl_load_image reads
* a whole block which is typically larger than
* CONFIG_CMD_SAVEBP_WRITE_SIZE therefore may overwrite
* CONFIG_CMD_SPL_WRITE_SIZE therefore may overwrite
* following sections like BSS
*/
nand_spl_load_image(CONFIG_CMD_SPL_NAND_OFS,

View File

@ -0,0 +1,138 @@
/*
* Voltage Controller implementation for OMAP
*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
* Nishanth Menon
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <common.h>
#include <asm/omap_common.h>
#include <asm/arch/sys_proto.h>
/*
* Define Master code if there are multiple masters on the I2C_SR bus.
* Normally not required
*/
#ifndef CONFIG_OMAP_VC_I2C_HS_MCODE
#define CONFIG_OMAP_VC_I2C_HS_MCODE 0x0
#endif
/* Register defines and masks for VC IP Block */
/* PRM_VC_CFG_I2C_MODE */
#define PRM_VC_CFG_I2C_MODE_DFILTEREN_BIT (0x1 << 6)
#define PRM_VC_CFG_I2C_MODE_SRMODEEN_BIT (0x1 << 4)
#define PRM_VC_CFG_I2C_MODE_HSMODEEN_BIT (0x1 << 3)
#define PRM_VC_CFG_I2C_MODE_HSMCODE_SHIFT 0x0
#define PRM_VC_CFG_I2C_MODE_HSMCODE_MASK 0x3
/* PRM_VC_CFG_I2C_CLK */
#define PRM_VC_CFG_I2C_CLK_HSCLL_SHIFT 24
#define PRM_VC_CFG_I2C_CLK_HSCLL_MASK 0xFF
#define PRM_VC_CFG_I2C_CLK_HSCLH_SHIFT 16
#define PRM_VC_CFG_I2C_CLK_HSCLH_MASK 0xFF
#define PRM_VC_CFG_I2C_CLK_SCLH_SHIFT 0
#define PRM_VC_CFG_I2C_CLK_SCLH_MASK 0xFF
#define PRM_VC_CFG_I2C_CLK_SCLL_SHIFT 8
#define PRM_VC_CFG_I2C_CLK_SCLL_MASK (0xFF << 8)
/* PRM_VC_VAL_BYPASS */
#define PRM_VC_VAL_BYPASS_VALID_BIT (0x1 << 24)
#define PRM_VC_VAL_BYPASS_SLAVEADDR_SHIFT 0
#define PRM_VC_VAL_BYPASS_SLAVEADDR_MASK 0x7F
#define PRM_VC_VAL_BYPASS_REGADDR_SHIFT 8
#define PRM_VC_VAL_BYPASS_REGADDR_MASK 0xFF
#define PRM_VC_VAL_BYPASS_DATA_SHIFT 16
#define PRM_VC_VAL_BYPASS_DATA_MASK 0xFF
/**
* omap_vc_init() - Initialization for Voltage controller
* @speed_khz: I2C buspeed in KHz
*/
void omap_vc_init(u16 speed_khz)
{
u32 val;
u32 sys_clk_khz, cycles_hi, cycles_low;
sys_clk_khz = get_sys_clk_freq() / 1000;
if (speed_khz > 400) {
puts("higher speed requested - throttle to 400Khz\n");
speed_khz = 400;
}
/*
* Setup the dedicated I2C controller for Voltage Control
* I2C clk - high period 40% low period 60%
*/
speed_khz /= 10;
cycles_hi = sys_clk_khz * 4 / speed_khz;
cycles_low = sys_clk_khz * 6 / speed_khz;
/* values to be set in register - less by 5 & 7 respectively */
cycles_hi -= 5;
cycles_low -= 7;
val = (cycles_hi << PRM_VC_CFG_I2C_CLK_SCLH_SHIFT) |
(cycles_low << PRM_VC_CFG_I2C_CLK_SCLL_SHIFT);
writel(val, &prcm->prm_vc_cfg_i2c_clk);
val = CONFIG_OMAP_VC_I2C_HS_MCODE <<
PRM_VC_CFG_I2C_MODE_HSMCODE_SHIFT;
/* No HS mode for now */
val &= ~PRM_VC_CFG_I2C_MODE_HSMODEEN_BIT;
writel(val, &prcm->prm_vc_cfg_i2c_mode);
}
/**
* omap_vc_bypass_send_value() - Send a data using VC Bypass command
* @sa: 7 bit I2C slave address of the PMIC
* @reg_addr: I2C register address(8 bit) address in PMIC
* @reg_data: what 8 bit data to write
*/
int omap_vc_bypass_send_value(u8 sa, u8 reg_addr, u8 reg_data)
{
/*
* Unfortunately we need to loop here instead of a defined time
* use arbitary large value
*/
u32 timeout = 0xFFFF;
u32 reg_val;
sa &= PRM_VC_VAL_BYPASS_SLAVEADDR_MASK;
reg_addr &= PRM_VC_VAL_BYPASS_REGADDR_MASK;
reg_data &= PRM_VC_VAL_BYPASS_DATA_MASK;
/* program VC to send data */
reg_val = sa << PRM_VC_VAL_BYPASS_SLAVEADDR_SHIFT |
reg_addr << PRM_VC_VAL_BYPASS_REGADDR_SHIFT |
reg_data << PRM_VC_VAL_BYPASS_DATA_SHIFT;
writel(reg_val, &prcm->prm_vc_val_bypass);
/* Signal VC to send data */
writel(reg_val | PRM_VC_VAL_BYPASS_VALID_BIT, &prcm->prm_vc_val_bypass);
/* Wait on VC to complete transmission */
do {
reg_val = readl(&prcm->prm_vc_val_bypass) &
PRM_VC_VAL_BYPASS_VALID_BIT;
if (!reg_val)
break;
sdelay(100);
} while (--timeout);
/* Optional: cleanup PRM_IRQSTATUS_Ax */
/* In case we can do something about it in future.. */
if (!timeout)
return -1;
/* All good.. */
return 0;
}

View File

@ -41,6 +41,7 @@
#include <asm/arch/gpio.h>
#include <asm/omap_common.h>
#include <i2c.h>
#include <linux/compiler.h>
/* Declarations */
extern omap3_sysinfo sysinfo;
@ -244,6 +245,17 @@ void s_init(void)
mem_init();
}
/*
* Routine: misc_init_r
* Description: A basic misc_init_r that just displays the die ID
*/
int __weak misc_init_r(void)
{
dieid_num_r();
return 0;
}
/******************************************************************************
* Routine: wait_for_command_complete
* Description: Wait for posting to finish on watchdog

View File

@ -572,6 +572,22 @@ void prcm_init(void)
}
if (get_cpu_family() == CPU_OMAP36XX) {
/*
* In warm reset conditions on OMAP36xx/AM/DM37xx
* the rom code incorrectly sets the DPLL4 clock
* input divider to /6.5. Section 3.5.3.3.3.2.1 of
* the AM/DM37x TRM explains that the /6.5 divider
* is used only when the input clock is 13MHz.
*
* If the part is in this cpu family *and* the input
* clock *is not* 13 MHz, then reset the DPLL4 clock
* input divider to /1 as it should never set to /6.5
* in this case.
*/
if (sys_clkin_sel != 1) /* 13 MHz */
/* Bit 8: DPLL4_CLKINP_DIV */
sr32(&prm_base->clksrc_ctrl, 8, 1, 0);
/* Unlock MPU DPLL (slows things down, and needed later) */
sr32(&prcm_base->clken_pll_mpu, 0, 3, PLL_LOW_POWER_BYPASS);
wait_on_value(ST_MPU_CLK, 0, &prcm_base->idlest_pll_mpu,

View File

@ -31,22 +31,22 @@
#include <version.h>
#include <asm/arch/mem.h>
#include <asm/arch/clocks_omap3.h>
#include <linux/linkage.h>
_TEXT_BASE:
.word CONFIG_SYS_TEXT_BASE /* sdram load addr from config.mk */
#ifdef CONFIG_SPL_BUILD
.global save_boot_params
save_boot_params:
ENTRY(save_boot_params)
ldr r4, =omap3_boot_device
ldr r5, [r0, #0x4]
and r5, r5, #0xff
str r5, [r4]
bx lr
ENDPROC(save_boot_params)
#endif
.global omap3_gp_romcode_call
omap3_gp_romcode_call:
ENTRY(omap3_gp_romcode_call)
PUSH {r4-r12, lr} @ Save all registers from ROM code!
MOV r12, r0 @ Copy the Service ID in R12
MOV r0, r1 @ Copy parameter to R0
@ -55,6 +55,7 @@ omap3_gp_romcode_call:
.word 0xe1600070 @ SMC #0 to enter monitor - hand assembled
@ because we use -march=armv5
POP {r4-r12, pc}
ENDPROC(omap3_gp_romcode_call)
/*
* Funtion for making PPA HAL API calls in secure devices
@ -62,8 +63,7 @@ omap3_gp_romcode_call:
* R0 - Service ID
* R1 - paramer list
*/
.global do_omap3_emu_romcode_call
do_omap3_emu_romcode_call:
ENTRY(do_omap3_emu_romcode_call)
PUSH {r4-r12, lr} @ Save all registers from ROM code!
MOV r12, r0 @ Copy the Secure Service ID in R12
MOV r3, r1 @ Copy the pointer to va_list in R3
@ -76,14 +76,14 @@ do_omap3_emu_romcode_call:
.word 0xe1600071 @ SMC #1 to call PPA service - hand assembled
@ because we use -march=armv5
POP {r4-r12, pc}
ENDPROC(do_omap3_emu_romcode_call)
#if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_NAND_BOOT)
/**************************************************************************
* cpy_clk_code: relocates clock code into SRAM where its safer to execute
* R1 = SRAM destination address.
*************************************************************************/
.global cpy_clk_code
cpy_clk_code:
ENTRY(cpy_clk_code)
/* Copy DPLL code into SRAM */
adr r0, go_to_speed /* get addr of clock setting code */
mov r2, #384 /* r2 size to copy (div by 32 bytes) */
@ -95,6 +95,7 @@ next2:
cmp r0, r2 /* until source end address [r2] */
bne next2
mov pc, lr /* back to caller */
ENDPROC(cpy_clk_code)
/* ***************************************************************************
* go_to_speed: -Moves to bypass, -Commits clock dividers, -puts dpll at speed
@ -109,8 +110,7 @@ next2:
* L3 when its not in self refresh seems bad for it. Normally, this
* code runs from flash before SDR is init so that should be ok.
****************************************************************************/
.global go_to_speed
go_to_speed:
ENTRY(go_to_speed)
stmfd sp!, {r4 - r6}
/* move into fast relock bypass */
@ -171,6 +171,7 @@ wait2:
nop
ldmfd sp!, {r4 - r6}
mov pc, lr /* back to caller, locked */
ENDPROC(go_to_speed)
_go_to_speed: .word go_to_speed
@ -211,8 +212,7 @@ pll_div_val5:
#endif
.globl lowlevel_init
lowlevel_init:
ENTRY(lowlevel_init)
ldr sp, SRAM_STACK
str ip, [sp] /* stash old link register */
mov ip, lr /* save link reg across call */
@ -230,6 +230,7 @@ lowlevel_init:
/* back to arch calling code */
mov pc, lr
ENDPROC(lowlevel_init)
/* the literal pools origin */
.ltorg
@ -480,22 +481,22 @@ per_36x_dpll_param:
.word 26000, 432, 12, 9, 16, 9, 4, 3, 1
.word 38400, 360, 15, 9, 16, 5, 4, 3, 1
.globl get_36x_mpu_dpll_param
get_36x_mpu_dpll_param:
ENTRY(get_36x_mpu_dpll_param)
adr r0, mpu_36x_dpll_param
mov pc, lr
ENDPROC(get_36x_mpu_dpll_param)
.globl get_36x_iva_dpll_param
get_36x_iva_dpll_param:
ENTRY(get_36x_iva_dpll_param)
adr r0, iva_36x_dpll_param
mov pc, lr
ENDPROC(get_36x_iva_dpll_param)
.globl get_36x_core_dpll_param
get_36x_core_dpll_param:
ENTRY(get_36x_core_dpll_param)
adr r0, core_36x_dpll_param
mov pc, lr
ENDPROC(get_36x_core_dpll_param)
.globl get_36x_per_dpll_param
get_36x_per_dpll_param:
ENTRY(get_36x_per_dpll_param)
adr r0, per_36x_dpll_param
mov pc, lr
ENDPROC(get_36x_per_dpll_param)

View File

@ -46,8 +46,6 @@
#define puts(s)
#endif
#define abs(x) (((x) < 0) ? ((x)*-1) : (x))
struct omap4_prcm_regs *const prcm = (struct omap4_prcm_regs *)0x4A004100;
const u32 sys_clk_array[8] = {
@ -275,49 +273,72 @@ void scale_vcores(void)
{
u32 volt, omap_rev;
setup_sri2c();
omap_vc_init(PRM_VC_I2C_CHANNEL_FREQ_KHZ);
omap_rev = omap_revision();
/* TPS - supplies vdd_mpu on 4460 */
if (omap_rev >= OMAP4460_ES1_0) {
volt = 1203;
do_scale_tps62361(TPS62361_REG_ADDR_SET1, volt);
}
/*
* VCORE 1
*
* 4430 : supplies vdd_mpu
* Setting a high voltage for Nitro mode as smart reflex is not enabled.
* We use the maximum possible value in the AVS range because the next
* higher voltage in the discrete range (code >= 0b111010) is way too
* high
*
* 4460 : supplies vdd_core
*/
if (omap_rev < OMAP4460_ES1_0) {
volt = 1325;
do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt);
} else {
volt = 1200;
do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt);
}
/* VCORE 2 - supplies vdd_iva */
volt = 1200;
do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt);
/*
* VCORE 3
* 4430 : supplies vdd_core
* 4460 : not connected
* Scale Voltage rails:
* 1. VDD_CORE
* 3. VDD_MPU
* 3. VDD_IVA
*/
if (omap_rev < OMAP4460_ES1_0) {
/*
* OMAP4430:
* VDD_CORE = TWL6030 VCORE3
* VDD_MPU = TWL6030 VCORE1
* VDD_IVA = TWL6030 VCORE2
*/
volt = 1200;
do_scale_vcore(SMPS_REG_ADDR_VCORE3, volt);
/*
* note on VDD_MPU:
* Setting a high voltage for Nitro mode as smart reflex is not
* enabled. We use the maximum possible value in the AVS range
* because the next higher voltage in the discrete range
* (code >= 0b111010) is way too high.
*/
volt = 1325;
do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt);
volt = 1200;
do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt);
} else {
/*
* OMAP4460:
* VDD_CORE = TWL6030 VCORE1
* VDD_MPU = TPS62361
* VDD_IVA = TWL6030 VCORE2
*/
volt = 1200;
do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt);
/* TPS62361 */
volt = 1203;
do_scale_tps62361(TPS62361_VSEL0_GPIO,
TPS62361_REG_ADDR_SET1, volt);
/* VCORE 2 - supplies vdd_iva */
volt = 1200;
do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt);
}
}
u32 get_offset_code(u32 offset)
{
u32 offset_code, step = 12660; /* 12.66 mV represented in uV */
if (omap_revision() == OMAP4430_ES1_0)
offset -= PHOENIX_SMPS_BASE_VOLT_STD_MODE_UV;
else
offset -= PHOENIX_SMPS_BASE_VOLT_STD_MODE_WITH_OFFSET_UV;
offset_code = (offset + step - 1) / step;
/* The code starts at 1 not 0 */
return ++offset_code;
}
/*
* Enable essential clock domains, modules and
* do some additional special settings needed
@ -355,7 +376,6 @@ void enable_basic_clocks(void)
&prcm->cm_l4per_gptimer2_clkctrl,
&prcm->cm_wkup_wdtimer2_clkctrl,
&prcm->cm_l4per_uart3_clkctrl,
&prcm->cm_l3init_fsusb_clkctrl,
&prcm->cm_l3init_hsusbhost_clkctrl,
0
};
@ -432,10 +452,6 @@ void enable_non_essential_clocks(void)
};
u32 *const clk_modules_hw_auto_non_essential[] = {
&prcm->cm_mpu_m3_mpu_m3_clkctrl,
&prcm->cm_ivahd_ivahd_clkctrl,
&prcm->cm_ivahd_sl2_clkctrl,
&prcm->cm_dsp_dsp_clkctrl,
&prcm->cm_l3_2_gpmc_clkctrl,
&prcm->cm_l3instr_l3_3_clkctrl,
&prcm->cm_l3instr_l3_instr_clkctrl,
@ -482,7 +498,6 @@ void enable_non_essential_clocks(void)
&prcm->cm_dss_dss_clkctrl,
&prcm->cm_sgx_sgx_clkctrl,
&prcm->cm_l3init_hsusbhost_clkctrl,
&prcm->cm_l3init_fsusb_clkctrl,
0
};

View File

@ -37,7 +37,7 @@
DECLARE_GLOBAL_DATA_PTR;
u32 *const omap4_revision = (u32 *)OMAP4_SRAM_SCRATCH_OMAP4_REV;
u32 *const omap_si_rev = (u32 *)OMAP4_SRAM_SCRATCH_OMAP4_REV;
static const struct gpio_bank gpio_bank_44xx[6] = {
{ (void *)OMAP44XX_GPIO1_BASE, METHOD_GPIO_24XX },
@ -59,8 +59,8 @@ void do_io_settings(void)
u32 lpddr2io;
struct control_lpddr2io_regs *lpddr2io_regs =
(struct control_lpddr2io_regs *)LPDDR2_IO_REGS_BASE;
struct omap4_sys_ctrl_regs *const ctrl =
(struct omap4_sys_ctrl_regs *)SYSCTRL_GENERAL_CORE_BASE;
struct omap_sys_ctrl_regs *const ctrl =
(struct omap_sys_ctrl_regs *)SYSCTRL_GENERAL_CORE_BASE;
u32 omap4_rev = omap_revision();
@ -129,40 +129,40 @@ void init_omap_revision(void)
switch (arm_rev) {
case MIDR_CORTEX_A9_R0P1:
*omap4_revision = OMAP4430_ES1_0;
*omap_si_rev = OMAP4430_ES1_0;
break;
case MIDR_CORTEX_A9_R1P2:
switch (readl(CONTROL_ID_CODE)) {
case OMAP4_CONTROL_ID_CODE_ES2_0:
*omap4_revision = OMAP4430_ES2_0;
*omap_si_rev = OMAP4430_ES2_0;
break;
case OMAP4_CONTROL_ID_CODE_ES2_1:
*omap4_revision = OMAP4430_ES2_1;
*omap_si_rev = OMAP4430_ES2_1;
break;
case OMAP4_CONTROL_ID_CODE_ES2_2:
*omap4_revision = OMAP4430_ES2_2;
*omap_si_rev = OMAP4430_ES2_2;
break;
default:
*omap4_revision = OMAP4430_ES2_0;
*omap_si_rev = OMAP4430_ES2_0;
break;
}
break;
case MIDR_CORTEX_A9_R1P3:
*omap4_revision = OMAP4430_ES2_3;
*omap_si_rev = OMAP4430_ES2_3;
break;
case MIDR_CORTEX_A9_R2P10:
switch (readl(CONTROL_ID_CODE)) {
case OMAP4460_CONTROL_ID_CODE_ES1_1:
*omap4_revision = OMAP4460_ES1_1;
*omap_si_rev = OMAP4460_ES1_1;
break;
case OMAP4460_CONTROL_ID_CODE_ES1_0:
default:
*omap4_revision = OMAP4460_ES1_0;
*omap_si_rev = OMAP4460_ES1_0;
break;
}
break;
default:
*omap4_revision = OMAP4430_SILICON_ID_INVALID;
*omap_si_rev = OMAP4430_SILICON_ID_INVALID;
break;
}
}

View File

@ -89,6 +89,10 @@ const struct emif_regs emif_regs_elpida_400_mhz_2cs = {
.emif_ddr_phy_ctlr_1_init = 0x049ffff5,
.emif_ddr_phy_ctlr_1 = 0x049ff418
};
/* Dummy registers for OMAP44xx */
const u32 ext_phy_ctrl_const_base[EMIF_EXT_PHY_CTRL_CONST_REG];
const struct dmm_lisa_map_regs lisa_map_2G_x_1_x_2 = {
.dmm_lisa_map_0 = 0xFF020100,
.dmm_lisa_map_1 = 0,

View File

@ -28,7 +28,7 @@ LIB = $(obj)lib$(SOC).o
COBJS += hwinit.o
COBJS += clocks.o
COBJS += emif.o
COBJS += sdram_elpida.o
COBJS += sdram.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS))

View File

@ -88,6 +88,26 @@ static const struct dpll_params mpu_dpll_params_1100mhz[NUM_SYS_CLKS] = {
{1375, 47, 1, -1, -1, -1, -1, -1, -1, -1} /* 38.4 MHz */
};
static const struct dpll_params mpu_dpll_params_800mhz[NUM_SYS_CLKS] = {
{200, 2, 1, -1, -1, -1, -1, -1, -1, -1}, /* 12 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 13 MHz */
{1000, 20, 1, -1, -1, -1, -1, -1, -1, -1}, /* 16.8 MHz */
{375, 8, 1, -1, -1, -1, -1, -1, -1, -1}, /* 19.2 MHz */
{400, 12, 1, -1, -1, -1, -1, -1, -1, -1}, /* 26 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 27 MHz */
{375, 17, 1, -1, -1, -1, -1, -1, -1, -1} /* 38.4 MHz */
};
static const struct dpll_params mpu_dpll_params_400mhz[NUM_SYS_CLKS] = {
{200, 2, 2, -1, -1, -1, -1, -1, -1, -1}, /* 12 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 13 MHz */
{1000, 20, 2, -1, -1, -1, -1, -1, -1, -1}, /* 16.8 MHz */
{375, 8, 2, -1, -1, -1, -1, -1, -1, -1}, /* 19.2 MHz */
{400, 12, 2, -1, -1, -1, -1, -1, -1, -1}, /* 26 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 27 MHz */
{375, 17, 2, -1, -1, -1, -1, -1, -1, -1} /* 38.4 MHz */
};
static const struct dpll_params mpu_dpll_params_550mhz[NUM_SYS_CLKS] = {
{275, 2, 2, -1, -1, -1, -1, -1, -1, -1}, /* 12 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 13 MHz */
@ -100,17 +120,6 @@ static const struct dpll_params mpu_dpll_params_550mhz[NUM_SYS_CLKS] = {
static const struct dpll_params
core_dpll_params_2128mhz_ddr532[NUM_SYS_CLKS] = {
{266, 2, 1, 5, 8, 4, 62, 5, 5, 7}, /* 12 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 13 MHz */
{570, 8, 1, 5, 8, 4, 62, 5, 5, 7}, /* 16.8 MHz */
{665, 11, 1, 5, 8, 4, 62, 5, 5, 7}, /* 19.2 MHz */
{532, 12, 1, 5, 8, 4, 62, 5, 5, 7}, /* 26 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 27 MHz */
{665, 23, 1, 5, 8, 4, 62, 5, 5, 7} /* 38.4 MHz */
};
static const struct dpll_params
core_dpll_params_2128mhz_ddr266[NUM_SYS_CLKS] = {
{266, 2, 2, 5, 8, 4, 62, 5, 5, 7}, /* 12 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 13 MHz */
{570, 8, 2, 5, 8, 4, 62, 5, 5, 7}, /* 16.8 MHz */
@ -120,6 +129,17 @@ static const struct dpll_params
{665, 23, 2, 5, 8, 4, 62, 5, 5, 7} /* 38.4 MHz */
};
static const struct dpll_params
core_dpll_params_2128mhz_ddr266[NUM_SYS_CLKS] = {
{266, 2, 4, 5, 8, 8, 62, 10, 10, 14}, /* 12 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 13 MHz */
{570, 8, 4, 5, 8, 8, 62, 10, 10, 14}, /* 16.8 MHz */
{665, 11, 4, 5, 8, 8, 62, 10, 10, 14}, /* 19.2 MHz */
{532, 12, 4, 8, 8, 8, 62, 10, 10, 14}, /* 26 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 27 MHz */
{665, 23, 4, 8, 8, 8, 62, 10, 10, 14} /* 38.4 MHz */
};
static const struct dpll_params per_dpll_params_768mhz[NUM_SYS_CLKS] = {
{32, 0, 4, 3, 6, 4, -1, 2, -1, -1}, /* 12 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 13 MHz */
@ -131,40 +151,40 @@ static const struct dpll_params per_dpll_params_768mhz[NUM_SYS_CLKS] = {
};
static const struct dpll_params iva_dpll_params_2330mhz[NUM_SYS_CLKS] = {
{931, 11, -1, -1, 4, 7, -1, -1}, /* 12 MHz */
{931, 12, -1, -1, 4, 7, -1, -1}, /* 13 MHz */
{665, 11, -1, -1, 4, 7, -1, -1}, /* 16.8 MHz */
{727, 14, -1, -1, 4, 7, -1, -1}, /* 19.2 MHz */
{931, 25, -1, -1, 4, 7, -1, -1}, /* 26 MHz */
{931, 26, -1, -1, 4, 7, -1, -1}, /* 27 MHz */
{412, 16, -1, -1, 4, 7, -1, -1} /* 38.4 MHz */
{1165, 11, -1, -1, 5, 6, -1, -1, -1, -1}, /* 12 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 13 MHz */
{2011, 28, -1, -1, 5, 6, -1, -1, -1, -1}, /* 16.8 MHz */
{1881, 30, -1, -1, 5, 6, -1, -1, -1, -1}, /* 19.2 MHz */
{1165, 25, -1, -1, 5, 6, -1, -1, -1, -1}, /* 26 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 27 MHz */
{1972, 64, -1, -1, 5, 6, -1, -1, -1, -1} /* 38.4 MHz */
};
/* ABE M & N values with sys_clk as source */
static const struct dpll_params
abe_dpll_params_sysclk_196608khz[NUM_SYS_CLKS] = {
{49, 5, 1, 1, -1, -1, -1, -1}, /* 12 MHz */
{68, 8, 1, 1, -1, -1, -1, -1}, /* 13 MHz */
{35, 5, 1, 1, -1, -1, -1, -1}, /* 16.8 MHz */
{46, 8, 1, 1, -1, -1, -1, -1}, /* 19.2 MHz */
{34, 8, 1, 1, -1, -1, -1, -1}, /* 26 MHz */
{29, 7, 1, 1, -1, -1, -1, -1}, /* 27 MHz */
{64, 24, 1, 1, -1, -1, -1, -1} /* 38.4 MHz */
{49, 5, 1, -1, -1, -1, -1, -1, -1, -1}, /* 12 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 13 MHz */
{35, 5, 1, 1, -1, -1, -1, -1, -1, -1}, /* 16.8 MHz */
{46, 8, 1, 1, -1, -1, -1, -1, -1, -1}, /* 19.2 MHz */
{34, 8, 1, 1, -1, -1, -1, -1, -1, -1}, /* 26 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 27 MHz */
{64, 24, 1, 1, -1, -1, -1, -1, -1, -1} /* 38.4 MHz */
};
/* ABE M & N values with 32K clock as source */
static const struct dpll_params abe_dpll_params_32k_196608khz = {
750, 0, 1, 1, -1, -1, -1, -1
750, 0, 1, 1, -1, -1, -1, -1, -1, -1
};
static const struct dpll_params usb_dpll_params_1920mhz[NUM_SYS_CLKS] = {
{80, 0, 2, -1, -1, -1, -1, -1}, /* 12 MHz */
{960, 12, 2, -1, -1, -1, -1, -1}, /* 13 MHz */
{400, 6, 2, -1, -1, -1, -1, -1}, /* 16.8 MHz */
{50, 0, 2, -1, -1, -1, -1, -1}, /* 19.2 MHz */
{480, 12, 2, -1, -1, -1, -1, -1}, /* 26 MHz */
{320, 8, 2, -1, -1, -1, -1, -1}, /* 27 MHz */
{25, 0, 2, -1, -1, -1, -1, -1} /* 38.4 MHz */
{400, 4, 2, -1, -1, -1, -1, -1, -1, -1}, /* 12 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 13 MHz */
{400, 6, 2, -1, -1, -1, -1, -1, -1, -1}, /* 16.8 MHz */
{400, 7, 2, -1, -1, -1, -1, -1, -1, -1}, /* 19.2 MHz */
{480, 12, 2, -1, -1, -1, -1, -1, -1, -1}, /* 26 MHz */
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 27 MHz */
{400, 15, 2, -1, -1, -1, -1, -1, -1, -1} /* 38.4 MHz */
};
void setup_post_dividers(u32 *const base, const struct dpll_params *params)
@ -193,7 +213,7 @@ void setup_post_dividers(u32 *const base, const struct dpll_params *params)
const struct dpll_params *get_mpu_dpll_params(void)
{
u32 sysclk_ind = get_sys_clk_index();
return &mpu_dpll_params_1100mhz[sysclk_ind];
return &mpu_dpll_params_800mhz[sysclk_ind];
}
const struct dpll_params *get_core_dpll_params(void)
@ -201,8 +221,7 @@ const struct dpll_params *get_core_dpll_params(void)
u32 sysclk_ind = get_sys_clk_index();
/* Configuring the DDR to be at 532mhz */
return &core_dpll_params_2128mhz_ddr266[sysclk_ind];
return &core_dpll_params_2128mhz_ddr532[sysclk_ind];
}
const struct dpll_params *get_per_dpll_params(void)
@ -243,19 +262,33 @@ void scale_vcores(void)
{
u32 volt;
setup_sri2c();
omap_vc_init(PRM_VC_I2C_CHANNEL_FREQ_KHZ);
/* Enable 1.22V from TPS for vdd_mpu */
volt = 1220;
do_scale_tps62361(TPS62361_REG_ADDR_SET1, volt);
/* Palmas settings */
volt = VDD_CORE;
do_scale_vcore(SMPS_REG_ADDR_8_CORE, volt);
/* VCORE 1 - for vdd_core */
volt = 1000;
do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt);
volt = VDD_MPU;
do_scale_vcore(SMPS_REG_ADDR_12_MPU, volt);
/* VCORE 2 - for vdd_MM */
volt = 1125;
do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt);
volt = VDD_MM;
do_scale_vcore(SMPS_REG_ADDR_45_IVA, volt);
}
u32 get_offset_code(u32 volt_offset)
{
u32 offset_code, step = 10000; /* 10 mV represented in uV */
volt_offset -= PALMAS_SMPS_BASE_VOLT_UV;
offset_code = (volt_offset + step - 1) / step;
/*
* Offset codes 1-6 all give the base voltage in Palmas
* Offset code 0 switches OFF the SMPS
*/
return offset_code + 6;
}
/*
@ -306,6 +339,12 @@ void enable_basic_clocks(void)
setbits_le32(&prcm->cm_l3init_hsmmc2_clkctrl,
HSMMC_CLKCTRL_CLKSEL_MASK);
/* Set the correct clock dividers for mmc */
setbits_le32(&prcm->cm_l3init_hsmmc1_clkctrl,
HSMMC_CLKCTRL_CLKSEL_DIV_MASK);
setbits_le32(&prcm->cm_l3init_hsmmc2_clkctrl,
HSMMC_CLKCTRL_CLKSEL_DIV_MASK);
/* Select 32KHz clock as the source of GPTIMER1 */
setbits_le32(&prcm->cm_wkup_gptimer1_clkctrl,
GPTIMER1_CLKCTRL_CLKSEL_MASK);
@ -314,6 +353,18 @@ void enable_basic_clocks(void)
clk_modules_hw_auto_essential,
clk_modules_explicit_en_essential,
1);
/* Select 384Mhz for GPU as its the POR for ES1.0 */
setbits_le32(&prcm->cm_sgx_sgx_clkctrl,
CLKSEL_GPU_HYD_GCLK_MASK);
setbits_le32(&prcm->cm_sgx_sgx_clkctrl,
CLKSEL_GPU_CORE_GCLK_MASK);
/* Enable SCRM OPT clocks for PER and CORE dpll */
setbits_le32(&prcm->cm_wkupaon_scrm_clkctrl,
OPTFCLKEN_SCRM_PER_MASK);
setbits_le32(&prcm->cm_wkupaon_scrm_clkctrl,
OPTFCLKEN_SCRM_CORE_MASK);
}
void enable_basic_uboot_clocks(void)
@ -371,6 +422,7 @@ void enable_non_essential_clocks(void)
&prcm->cm_l3instr_intrconn_wp1_clkctrl,
&prcm->cm_l3init_hsi_clkctrl,
&prcm->cm_l3init_hsusbtll_clkctrl,
&prcm->cm_l4per_hdq1w_clkctrl,
0
};
@ -393,7 +445,6 @@ void enable_non_essential_clocks(void)
&prcm->cm_l4per_gptimer11_clkctrl,
&prcm->cm_l4per_gptimer3_clkctrl,
&prcm->cm_l4per_gptimer4_clkctrl,
&prcm->cm_l4per_hdq1w_clkctrl,
&prcm->cm_l4per_mcspi2_clkctrl,
&prcm->cm_l4per_mcspi3_clkctrl,
&prcm->cm_l4per_mcspi4_clkctrl,

View File

@ -38,7 +38,7 @@
DECLARE_GLOBAL_DATA_PTR;
u32 *const omap5_revision = (u32 *)OMAP5_SRAM_SCRATCH_OMAP5_REV;
u32 *const omap_si_rev = (u32 *)OMAP5_SRAM_SCRATCH_OMAP5_REV;
static struct gpio_bank gpio_bank_54xx[6] = {
{ (void *)OMAP54XX_GPIO1_BASE, METHOD_GPIO_24XX },
@ -57,6 +57,89 @@ const struct gpio_bank *const omap_gpio_bank = gpio_bank_54xx;
*/
void do_io_settings(void)
{
u32 io_settings = 0, mask = 0;
struct omap_sys_ctrl_regs *ioregs_base =
(struct omap_sys_ctrl_regs *) SYSCTRL_GENERAL_CORE_BASE;
/* Impedance settings EMMC, C2C 1,2, hsi2 */
mask = (ds_mask << 2) | (ds_mask << 8) |
(ds_mask << 16) | (ds_mask << 18);
io_settings = readl(&(ioregs_base->control_smart1io_padconf_0)) &
(~mask);
io_settings |= (ds_60_ohm << 8) | (ds_45_ohm << 16) |
(ds_45_ohm << 18) | (ds_60_ohm << 2);
writel(io_settings, &(ioregs_base->control_smart1io_padconf_0));
/* Impedance settings Mcspi2 */
mask = (ds_mask << 30);
io_settings = readl(&(ioregs_base->control_smart1io_padconf_1)) &
(~mask);
io_settings |= (ds_60_ohm << 30);
writel(io_settings, &(ioregs_base->control_smart1io_padconf_1));
/* Impedance settings C2C 3,4 */
mask = (ds_mask << 14) | (ds_mask << 16);
io_settings = readl(&(ioregs_base->control_smart1io_padconf_2)) &
(~mask);
io_settings |= (ds_45_ohm << 14) | (ds_45_ohm << 16);
writel(io_settings, &(ioregs_base->control_smart1io_padconf_2));
/* Slew rate settings EMMC, C2C 1,2 */
mask = (sc_mask << 8) | (sc_mask << 16) | (sc_mask << 18);
io_settings = readl(&(ioregs_base->control_smart2io_padconf_0)) &
(~mask);
io_settings |= (sc_fast << 8) | (sc_na << 16) | (sc_na << 18);
writel(io_settings, &(ioregs_base->control_smart2io_padconf_0));
/* Slew rate settings hsi2, Mcspi2 */
mask = (sc_mask << 24) | (sc_mask << 28);
io_settings = readl(&(ioregs_base->control_smart2io_padconf_1)) &
(~mask);
io_settings |= (sc_fast << 28) | (sc_fast << 24);
writel(io_settings, &(ioregs_base->control_smart2io_padconf_1));
/* Slew rate settings C2C 3,4 */
mask = (sc_mask << 16) | (sc_mask << 18);
io_settings = readl(&(ioregs_base->control_smart2io_padconf_2)) &
(~mask);
io_settings |= (sc_na << 16) | (sc_na << 18);
writel(io_settings, &(ioregs_base->control_smart2io_padconf_2));
/* impedance and slew rate settings for usb */
mask = (usb_i_mask << 29) | (usb_i_mask << 26) | (usb_i_mask << 23) |
(usb_i_mask << 20) | (usb_i_mask << 17) | (usb_i_mask << 14);
io_settings = readl(&(ioregs_base->control_smart3io_padconf_1)) &
(~mask);
io_settings |= (ds_60_ohm << 29) | (ds_60_ohm << 26) |
(ds_60_ohm << 23) | (sc_fast << 20) |
(sc_fast << 17) | (sc_fast << 14);
writel(io_settings, &(ioregs_base->control_smart3io_padconf_1));
/* LPDDR2 io settings */
writel(DDR_IO_I_34OHM_SR_FASTEST_WD_DQ_NO_PULL_DQS_PULL_DOWN,
&(ioregs_base->control_ddrch1_0));
writel(DDR_IO_I_34OHM_SR_FASTEST_WD_DQ_NO_PULL_DQS_PULL_DOWN,
&(ioregs_base->control_ddrch1_1));
writel(DDR_IO_I_34OHM_SR_FASTEST_WD_DQ_NO_PULL_DQS_PULL_DOWN,
&(ioregs_base->control_ddrch2_0));
writel(DDR_IO_I_34OHM_SR_FASTEST_WD_DQ_NO_PULL_DQS_PULL_DOWN,
&(ioregs_base->control_ddrch2_1));
writel(DDR_IO_I_34OHM_SR_FASTEST_WD_CK_CKE_NCS_CA_PULL_DOWN,
&(ioregs_base->control_lpddr2ch1_0));
writel(DDR_IO_I_34OHM_SR_FASTEST_WD_CK_CKE_NCS_CA_PULL_DOWN,
&(ioregs_base->control_lpddr2ch1_1));
writel(DDR_IO_0_DDR2_DQ_INT_EN_ALL_DDR3_CA_DIS_ALL,
&(ioregs_base->control_ddrio_0));
writel(DDR_IO_1_DQ_OUT_EN_ALL_DQ_INT_EN_ALL,
&(ioregs_base->control_ddrio_1));
writel(DDR_IO_2_CA_OUT_EN_ALL_CA_INT_EN_ALL,
&(ioregs_base->control_ddrio_2));
/* Efuse settings */
writel(EFUSE_1, &(ioregs_base->control_efuse_1));
writel(EFUSE_2, &(ioregs_base->control_efuse_2));
writel(EFUSE_3, &(ioregs_base->control_efuse_3));
writel(EFUSE_4, &(ioregs_base->control_efuse_4));
}
#endif
@ -71,8 +154,23 @@ void init_omap_revision(void)
switch (rev) {
case MIDR_CORTEX_A15_R0P0:
*omap5_revision = OMAP5430_ES1_0;
*omap_si_rev = OMAP5430_ES1_0;
break;
default:
*omap5_revision = OMAP5430_SILICON_ID_INVALID;
*omap_si_rev = OMAP5430_SILICON_ID_INVALID;
}
}
void reset_cpu(ulong ignored)
{
u32 omap_rev = omap_revision();
/*
* WARM reset is not functional in case of OMAP5430 ES1.0 soc.
* So use cold reset in case instead.
*/
if (omap_rev == OMAP5430_ES1_0)
writel(PRM_RSTCTRL_RESET << 0x1, PRM_RSTCTRL);
else
writel(PRM_RSTCTRL_RESET, PRM_RSTCTRL);
}

View File

@ -0,0 +1,221 @@
/*
* Timing and Organization details of the ddr device parts used in OMAP5
* EVM
*
* (C) Copyright 2010
* Texas Instruments, <www.ti.com>
*
* Aneesh V <aneesh@ti.com>
* Sricharan R <r.sricharan@ti.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <asm/emif.h>
#include <asm/arch/sys_proto.h>
/*
* This file provides details of the LPDDR2 SDRAM parts used on OMAP5
* EVM. Since the parts used and geometry are identical for
* evm for a given OMAP5 revision, this information is kept
* here instead of being in board directory. However the key functions
* exported are weakly linked so that they can be over-ridden in the board
* directory if there is a OMAP5 board in the future that uses a different
* memory device or geometry.
*
* For any new board with different memory devices over-ride one or more
* of the following functions as per the CONFIG flags you intend to enable:
* - emif_get_reg_dump()
* - emif_get_dmm_regs()
* - emif_get_device_details()
* - emif_get_device_timings()
*/
#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS
const struct emif_regs emif_regs_532_mhz_2cs = {
.sdram_config_init = 0x80800EBA,
.sdram_config = 0x808022BA,
.ref_ctrl = 0x0000081A,
.sdram_tim1 = 0x772F6873,
.sdram_tim2 = 0x304a129a,
.sdram_tim3 = 0x02f7e45f,
.read_idle_ctrl = 0x00050000,
.zq_config = 0x000b3215,
.temp_alert_config = 0x08000a05,
.emif_ddr_phy_ctlr_1_init = 0x0E28420d,
.emif_ddr_phy_ctlr_1 = 0x0E28420d,
.emif_ddr_ext_phy_ctrl_1 = 0x04020080,
.emif_ddr_ext_phy_ctrl_2 = 0x28C518A3,
.emif_ddr_ext_phy_ctrl_3 = 0x518A3146,
.emif_ddr_ext_phy_ctrl_4 = 0x0014628C,
.emif_ddr_ext_phy_ctrl_5 = 0x04010040
};
const struct emif_regs emif_regs_266_mhz_2cs = {
.sdram_config_init = 0x80800EBA,
.sdram_config = 0x808022BA,
.ref_ctrl = 0x0000040D,
.sdram_tim1 = 0x2A86B419,
.sdram_tim2 = 0x1025094A,
.sdram_tim3 = 0x026BA22F,
.read_idle_ctrl = 0x00050000,
.zq_config = 0x000b3215,
.temp_alert_config = 0x08000a05,
.emif_ddr_phy_ctlr_1_init = 0x0E28420d,
.emif_ddr_phy_ctlr_1 = 0x0E28420d,
.emif_ddr_ext_phy_ctrl_1 = 0x04020080,
.emif_ddr_ext_phy_ctrl_2 = 0x0A414829,
.emif_ddr_ext_phy_ctrl_3 = 0x14829052,
.emif_ddr_ext_phy_ctrl_4 = 0x000520A4,
.emif_ddr_ext_phy_ctrl_5 = 0x04010040
};
const struct dmm_lisa_map_regs lisa_map_4G_x_2_x_2 = {
.dmm_lisa_map_0 = 0x0,
.dmm_lisa_map_1 = 0,
.dmm_lisa_map_2 = 0,
.dmm_lisa_map_3 = 0x80740300
};
const u32 ext_phy_ctrl_const_base[EMIF_EXT_PHY_CTRL_CONST_REG] = {
0x01004010,
0x00001004,
0x04010040,
0x01004010,
0x00001004,
0x00000000,
0x00000000,
0x00000000,
0x80080080,
0x00800800,
0x08102040,
0x00000001,
0x540A8150,
0xA81502a0,
0x002A0540,
0x00000000,
0x00000000,
0x00000000,
0x00000077
};
static void emif_get_reg_dump_sdp(u32 emif_nr, const struct emif_regs **regs)
{
*regs = &emif_regs_532_mhz_2cs;
}
void emif_get_reg_dump(u32 emif_nr, const struct emif_regs **regs)
__attribute__((weak, alias("emif_get_reg_dump_sdp")));
static void emif_get_dmm_regs_sdp(const struct dmm_lisa_map_regs
**dmm_lisa_regs)
{
*dmm_lisa_regs = &lisa_map_4G_x_2_x_2;
}
void emif_get_dmm_regs(const struct dmm_lisa_map_regs **dmm_lisa_regs)
__attribute__((weak, alias("emif_get_dmm_regs_sdp")));
#else
static const struct lpddr2_device_details dev_4G_S4_details = {
.type = LPDDR2_TYPE_S4,
.density = LPDDR2_DENSITY_4Gb,
.io_width = LPDDR2_IO_WIDTH_32,
.manufacturer = LPDDR2_MANUFACTURER_SAMSUNG
};
static void emif_get_device_details_sdp(u32 emif_nr,
struct lpddr2_device_details *cs0_device_details,
struct lpddr2_device_details *cs1_device_details)
{
/* EMIF1 & EMIF2 have identical configuration */
*cs0_device_details = dev_4G_S4_details;
*cs1_device_details = dev_4G_S4_details;
}
void emif_get_device_details(u32 emif_nr,
struct lpddr2_device_details *cs0_device_details,
struct lpddr2_device_details *cs1_device_details)
__attribute__((weak, alias("emif_get_device_details_sdp")));
#endif /* CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS */
#ifndef CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS
static const struct lpddr2_ac_timings timings_jedec_532_mhz = {
.max_freq = 532000000,
.RL = 8,
.tRPab = 21,
.tRCD = 18,
.tWR = 15,
.tRASmin = 42,
.tRRD = 10,
.tWTRx2 = 15,
.tXSR = 140,
.tXPx2 = 15,
.tRFCab = 130,
.tRTPx2 = 15,
.tCKE = 3,
.tCKESR = 15,
.tZQCS = 90,
.tZQCL = 360,
.tZQINIT = 1000,
.tDQSCKMAXx2 = 11,
.tRASmax = 70,
.tFAW = 50
};
static const struct lpddr2_min_tck min_tck = {
.tRL = 3,
.tRP_AB = 3,
.tRCD = 3,
.tWR = 3,
.tRAS_MIN = 3,
.tRRD = 2,
.tWTR = 2,
.tXP = 2,
.tRTP = 2,
.tCKE = 3,
.tCKESR = 3,
.tFAW = 8
};
static const struct lpddr2_ac_timings *ac_timings[MAX_NUM_SPEEDBINS] = {
&timings_jedec_532_mhz
};
static const struct lpddr2_device_timings dev_4G_S4_timings = {
.ac_timings = ac_timings,
.min_tck = &min_tck,
};
void emif_get_device_timings_sdp(u32 emif_nr,
const struct lpddr2_device_timings **cs0_device_timings,
const struct lpddr2_device_timings **cs1_device_timings)
{
/* Identical devices on EMIF1 & EMIF2 */
*cs0_device_timings = &dev_4G_S4_timings;
*cs1_device_timings = &dev_4G_S4_timings;
}
void emif_get_device_timings(u32 emif_nr,
const struct lpddr2_device_timings **cs0_device_timings,
const struct lpddr2_device_timings **cs1_device_timings)
__attribute__((weak, alias("emif_get_device_timings_sdp")));
#endif /* CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS */

View File

@ -0,0 +1,62 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
#
# See file CREDITS for list of people who contributed to this
# project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA
#
include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).o
COBJS-y += timer.o serial.o ifc.o cpu.o rda_sys.o ispi.o
COBJS-$(CONFIG_SPL_SIGNATURE_CHECK_IMAGE) += rda_crypto.o rda_romapi.o
ifdef CONFIG_SPL_BUILD
COBJS-y += spl.o
COBJS-$(CONFIG_SPL_XMODEM_LOAD) += xmodem_boot.o
else
ifdef CONFIG_MDCOM
COBJS-y += mdcom.o
endif
endif
ifndef CONFIG_SKIP_LOWLEVEL_INIT
SOBJS += lowlevel_init.o
endif
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS-y) $(SOBJS))
START := $(addprefix $(obj),$(START))
all: $(obj).depend $(LIB)
$(LIB): $(OBJS)
$(call cmd_link_o_target, $(OBJS))
#########################################################################
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################

View File

@ -0,0 +1,95 @@
#
# (C) Copyright 2002
# Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
#
# See file CREDITS for list of people who contributed to this
# project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA
#
include $(TOPDIR)/slt.mk
include $(TOPDIR)/customer.mk
include $(TOPDIR)/board/$(SOC)/$(BOARD)/config.mk
image_flags :=
ifneq ($(TARGET_SYSTEMIMAGE_USE_UBIFS),)
image_flags += -DUBIFS_SYSTEM_IMAGE
endif
ifneq ($(TARGET_USERIMAGES_USE_UBIFS),)
image_flags += -DUBIFS_USER_IMAGES
endif
ifneq ($(TARGET_SYSTEMIMAGE_USE_EXT4),)
image_flags += -DEXTFS_SYSTEM_IMAGE
endif
ifneq ($(TARGET_USERIMAGES_USE_EXT4),)
image_flags += -DEXTFS_USER_IMAGES
endif
image_flags += -DSPL_APPENDING_TO=$(SPL_APPENDING_TO)
pdl_flags :=
ifeq ($(pdl), 1)
pdl_flags += -DCONFIG_RDA_PDL
endif
nand_flags :=
ifneq ($(BOARD_NAND_PAGE_SIZE),)
nand_flags += -DNAND_PAGE_SIZE=$(BOARD_NAND_PAGE_SIZE)
else
nand_flags += -DNAND_PAGE_SIZE=4096
endif
ifneq ($(BOARD_FLASH_BLOCK_SIZE),)
nand_flags += -DNAND_BLOCK_SIZE=$(BOARD_FLASH_BLOCK_SIZE)
else
nand_flags += -DNAND_BLOCK_SIZE=262144
endif
ifneq ($(BOARD_NAND_SPARE_SIZE),)
nand_flags += -DNAND_SPARE_SIZE=$(BOARD_NAND_SPARE_SIZE)
else
nand_flags += -DNAND_SPARE_SIZE=218
endif
ifneq ($(BOARD_NAND_ECCMSGLEN),)
nand_flags += -DNAND_ECCMSGLEN=$(BOARD_NAND_ECCMSGLEN)
else
nand_flags += -DNAND_ECCMSGLEN=1024
endif
ifneq ($(BOARD_NAND_ECCBITS),)
nand_flags += -DNAND_ECCBITS=$(BOARD_NAND_ECCBITS)
else
nand_flags += -DNAND_ECCBITS=24
endif
ifneq ($(BOARD_NAND_OOB_SIZE),)
nand_flags += -DNAND_OOBSIZE=$(BOARD_NAND_OOB_SIZE)
else
nand_flags += -DNAND_OOBSIZE=32
endif
build_variant_flags :=
ifneq ($(UBOOT_VARIANT), user)
build_variant_flags += -DCONFIG_UBOOT_VARIANT_DEBUG
endif
ifneq ($(BUILD_DISPLAY_ID),)
build_variant_flags += -DBUILD_DISPLAY_ID="\"$(BUILD_DISPLAY_ID)\""
endif
PLATFORM_CPPFLAGS += $(image_flags) $(pdl_flags) $(build_variant_flags) $(nand_flags)

View File

@ -0,0 +1,87 @@
#include <common.h>
#include <asm/arch/hardware.h>
void enable_neon(void)
{
/* enable cp10 and cp11 */
uint32_t val;
__asm__ volatile("mrc p15, 0, %0, c1, c1, 2" : "=r" (val));
printf("CPU: p15-c1-c1 (NSACR): 0x%08x", val);
val |= (3<<10);
val &= ~(3<<14);
__asm__ volatile("mcr p15, 0, %0, c1, c1, 2" :: "r" (val));
printf(" -> 0x%08x\n", val);
__asm__ volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (val));
printf("CPU: p15-c1-c0 (CPACR): 0x%08x", val);
val |= (3<<22)|(3<<20);
__asm__ volatile("mcr p15, 0, %0, c1, c0, 2" :: "r" (val));
printf(" -> 0x%08x\n", val);
/* set enable bit in fpexc */
val = (1<<30);
__asm__ volatile("mcr p10, 7, %0, c8, c0, 0" :: "r" (val));
}
#if (defined(CONFIG_MACH_RDA8810E) \
||defined(CONFIG_MACH_RDA8820) \
||defined(CONFIG_MACH_RDA8810H) \
||defined(CONFIG_MACH_RDA8850E))
/* SMP MACHs */
void smp_setup(void)
{
asm volatile(
"mrc p15, 0, r0, c1, c0, 1\n"
"orr r0, r0, #0x40\n"
"mcr p15, 0, r0, c1, c0, 1\n");
}
#endif
void enable_caches(void)
{
#if (defined(CONFIG_MACH_RDA8810E) \
||defined(CONFIG_MACH_RDA8820) \
||defined(CONFIG_MACH_RDA8810H) \
||defined(CONFIG_MACH_RDA8850E))
printf("CPU: enable smp\n");
smp_setup();
#endif
#ifndef CONFIG_SYS_ICACHE_OFF
printf("CPU: enable instruction caches\n");
icache_enable();
#endif
#ifndef CONFIG_SYS_DCACHE_OFF
printf("CPU: enable data caches\n");
dcache_enable();
#endif
#ifndef CONFIG_SYS_NEON_OFF
printf("CPU: enable neon\n");
enable_neon();
#endif
}
#ifdef CONFIG_DISPLAY_CPUINFO
/* Print CPU information */
int print_cpuinfo(void)
{
#if defined(CONFIG_MACH_RDAARM926EJS)
printf("RDAARM926EJS FPGA\n");
#elif defined(CONFIG_MACH_RDA8810)
printf("RDA8810 SoC\n");
#elif defined(CONFIG_MACH_RDA8810E)
printf("RDA8810E SoC\n");
#elif defined(CONFIG_MACH_RDA8820)
printf("RDA8820 SoC\n");
#elif defined(CONFIG_MACH_RDA8850)
printf("RDA8850 SoC\n");
#elif defined(CONFIG_MACH_RDA8850E)
printf("RDA8850E SoC\n");
#elif defined(CONFIG_MACH_RDA8810H)
printf("RDA8810H SoC\n");
#else
#error "Unknown RDA CPU"
#endif
return 0;
}
#endif /* CONFIG_DISPLAY_CPUINFO */

View File

@ -0,0 +1,172 @@
#include "common.h"
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/reg_ifc.h>
#include <asm/arch/ifc.h>
#undef assert
#ifdef DEBUG
#include <assert.h>
#else
#define assert(...)
#endif
#define HAL_TRACE(...)
HAL_IFC_REQUEST_ID_T g_halModuleIfcChannelOwner[SYS_IFC_STD_CHAN_NB];
void hal_IfcOpen(void)
{
u8 channel;
// Initialize the channel table with unknown requests.
for (channel = 0; channel < SYS_IFC_STD_CHAN_NB; channel++)
{
g_halModuleIfcChannelOwner[channel] = HAL_IFC_NO_REQWEST;
}
}
HAL_IFC_REQUEST_ID_T hal_IfcGetOwner(u8 channel)
{
// Here, we consider the transfer as previously finished.
if (channel == HAL_UNKNOWN_CHANNEL) return HAL_IFC_NO_REQWEST;
// Channel number too big.
assert(channel < SYS_IFC_STD_CHAN_NB, channel);
return g_halModuleIfcChannelOwner[channel];
}
void hal_IfcChannelRelease(HAL_IFC_REQUEST_ID_T requestId, u8 channel)
{
//u32 status;
// Here, we consider the transfer as previously finished.
if (channel == HAL_UNKNOWN_CHANNEL) return;
// Channel number too big.
assert(channel < SYS_IFC_STD_CHAN_NB, channel);
//status = hal_SysEnterCriticalSection();
if (g_halModuleIfcChannelOwner[channel] == requestId)
{
// disable this channel
hwp_sysIfc->std_ch[channel].control = (SYS_IFC_REQ_SRC(requestId)
| SYS_IFC_CH_RD_HW_EXCH
| SYS_IFC_DISABLE);
// read the status of this channel
if (hwp_sysIfc->std_ch[channel].status & SYS_IFC_ENABLE)
{
HAL_TRACE(_HAL | TSTDOUT,0," Strange, the released channel not disabled yet");
}
// Write the TC to 0 for next time the channel is re-enabled
hwp_sysIfc->std_ch[channel].tc = 0;
}
//hal_SysExitCriticalSection(status);
}
void hal_IfcChannelFlush(HAL_IFC_REQUEST_ID_T requestId, u8 channel)
{
//u32 status;
// Here, we consider the transfer as previously finished.
if (channel == HAL_UNKNOWN_CHANNEL) return;
// Channel number too big.
assert(channel < SYS_IFC_STD_CHAN_NB, channel);
// Check that the channel is really owned by the peripheral
// which is doing the request, it could have been release
// automatically or by an IRQ handler.
//status = hal_SysEnterCriticalSection();
if (g_halModuleIfcChannelOwner[channel] == requestId)
{
// If fifo not empty, flush it.
if ( !(hwp_sysIfc->std_ch[channel].status & SYS_IFC_FIFO_EMPTY) )
{
hwp_sysIfc->std_ch[channel].control =
hwp_sysIfc->std_ch[channel].control | SYS_IFC_FLUSH;
}
}
//hal_SysExitCriticalSection(status);
}
BOOL hal_IfcChannelIsFifoEmpty(HAL_IFC_REQUEST_ID_T requestId, u8 channel)
{
//u32 status;
BOOL fifoIsEmpty = TRUE;
// Here, we consider the transfer as previously finished.
if (channel == HAL_UNKNOWN_CHANNEL) return fifoIsEmpty;
// Channel number too big.
assert(channel < SYS_IFC_STD_CHAN_NB, channel);
// Check that the channel is really owned by the peripheral
// which is doing the request, it could have been release
// automatically or by an IRQ handler.
//status = hal_SysEnterCriticalSection();
if (g_halModuleIfcChannelOwner[channel] == requestId)
{
fifoIsEmpty =
(FALSE != (hwp_sysIfc->std_ch[channel].status & SYS_IFC_FIFO_EMPTY));
}
//hal_SysExitCriticalSection(status);
return fifoIsEmpty;
}
u8 hal_IfcTransferStart(HAL_IFC_REQUEST_ID_T requestId, u8* memStartAddr, u32 xferSize, HAL_IFC_MODE_T ifcMode)
{
//u32 status = hal_SysEnterCriticalSection();
u8 channel;
u8 i;
// Check buffer alignment depending on the mode
if (ifcMode != HAL_IFC_SIZE_8_MODE_MANUAL && ifcMode != HAL_IFC_SIZE_8_MODE_AUTO)
{
// Then ifcMode == HAL_IFC_SIZE_32, check word alignment
assert(((u32)memStartAddr%4) == 0,
"HAL IFC: 32 bits transfer misaligned 0x@%08X", memStartAddr);
}
else
{
// ifcMode == HAL_IFC_SIZE_8, nothing to check
}
// Check the requested id is not currently already used.
for (i = 0; i < SYS_IFC_STD_CHAN_NB ; i++)
{
if (GET_BITFIELD(hwp_sysIfc->std_ch[i].control, SYS_IFC_REQ_SRC) == requestId)
{
// This channel is or was used for the requestId request.
// Check it is still in use.
assert((hwp_sysIfc->std_ch[i].status & SYS_IFC_ENABLE) == 0,
"HAL: Attempt to use the IFC to deal with a %d"
" request still active on channel %d", requestId, i);
}
}
channel = SYS_IFC_CH_TO_USE(hwp_sysIfc->get_ch) ;
if (channel >= SYS_IFC_STD_CHAN_NB)
{
serial_puts("HAL_UNKNOWN_CHANNEL\n");
//hal_SysExitCriticalSection(status);
return HAL_UNKNOWN_CHANNEL;
}
g_halModuleIfcChannelOwner[channel] = requestId;
hwp_sysIfc->std_ch[channel].start_addr = (u32) memStartAddr;
hwp_sysIfc->std_ch[channel].tc = xferSize;
hwp_sysIfc->std_ch[channel].control = (SYS_IFC_REQ_SRC(requestId)
| ifcMode
| SYS_IFC_CH_RD_HW_EXCH
| SYS_IFC_ENABLE);
//hal_SysExitCriticalSection(status);
return channel;
}

View File

@ -0,0 +1,314 @@
/*
* (C) Copyright 2013
* RDA Microelectronics Inc.
*
* Derived from drivers/spi/rda_ispi.c
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <common.h>
#include <linux/types.h>
#include <asm/arch/reg_spi.h>
#include <asm/arch/ispi.h>
#ifdef CONFIG_MACH_RDA8850E
#include <asm/arch/reg_rf_spi.h>
#define RDA6220_ADDR_MASK 0xFF
#define RDA6220_ADDR_OFFSET 23
#define RDA6220_DATA_MASK 0xFFFF
#define RDA6220_DATA_OFFSET 7
#define RDA6220_WRITE_FMT(addr, data) (((addr & RDA6220_ADDR_MASK) << RDA6220_ADDR_OFFSET) |\
((data & RDA6220_DATA_MASK) << RDA6220_DATA_OFFSET))
#define RDA6220_READ_FMT(addr, data) ( ((addr & RDA6220_ADDR_MASK) << RDA6220_ADDR_OFFSET)|\
((data & RDA6220_DATA_MASK) << RDA6220_DATA_OFFSET)|\
1<<31);
void modem_RfspiOpen(void)
{
// Setter
hwp_rfSpi->Ctrl = 0x8fd82e45;
// To remove the "FORCE ZERO" in case of low-active CS
hwp_rfSpi->Command = 0;
hwp_rfSpi->Divider = RF_SPI_DIVIDER(23);
}
void modem_rf_spiWrite(const u8 *Cmd, u32 CmdSize)
{
u32 loop=0;
// Flush the Tx fifo
hwp_rfSpi->Command = RF_SPI_FLUSH_CMD_FIFO | RF_SPI_FLUSH_RX_FIFO;
for (loop=0; loop<CmdSize; loop++)
{
hwp_rfSpi->Cmd_Data = Cmd[loop];
}
// Set the cmd size
hwp_rfSpi->Cmd_Size = RF_SPI_CMD_SIZE(CmdSize);
// And send the command
hwp_rfSpi->Command = RF_SPI_SEND_CMD;
// Wait for the SPI to start - at least one byte has been sent
while(GET_BITFIELD(hwp_rfSpi->Status, RF_SPI_CMD_DATA_LEVEL) >= CmdSize);
// Wait for the SPI to finish
while((hwp_rfSpi->Status & RF_SPI_ACTIVE_STATUS) != 0);
}
void modem_RfspiWrite(const u8 addr, u32 data)
{
u8 cmd[4] = {0};
u32 cmd_word = RDA6220_WRITE_FMT(addr, data);
cmd[0] = (cmd_word >> 24) & 0xff;
cmd[1] = (cmd_word >>16) & 0xff;
cmd[2] = (cmd_word >> 8) & 0xff;
cmd[3] = (cmd_word >> 0) & 0xff;
modem_rf_spiWrite(cmd, 4);
}
void modem_RfspiInit_624M(void)
{
modem_RfspiOpen();
modem_RfspiWrite(0x30, 0x5182);
mdelay(10); // delay 10 ms
modem_RfspiWrite(0x30, 0x5187);
mdelay(10); // delay 10 ms
// xtal setting
modem_RfspiWrite(0xb0, 0xe404);
modem_RfspiWrite(0xb8, 0x1800);
modem_RfspiWrite(0xba, 0x0401);
modem_RfspiWrite(0xc0, 0x0008);
modem_RfspiWrite(0xfe, 0x4000);
modem_RfspiWrite(0x10, 0x0880);
modem_RfspiWrite(0x20, 0x03e4);
modem_RfspiWrite(0x22, 0x0488);
modem_RfspiWrite(0xe8, 0x1000);
modem_RfspiWrite(0xe6, 0x0000);
modem_RfspiWrite(0xe4, 0x0c00);
modem_RfspiWrite(0xe4, 0x8c00);
modem_RfspiWrite(0xfe, 0x0000);
modem_RfspiWrite(0x4e, 0xe538);
modem_RfspiWrite(0x4c, 0x04b9);
modem_RfspiWrite(0x4c, 0x84b9);
}
void modem_8850eeco2_RfspiInit_624M(void)
{
modem_RfspiOpen();
modem_RfspiWrite(0x30, 0x5182);
mdelay(10); // delay 10 ms
modem_RfspiWrite(0x30, 0x5187);
mdelay(10); // delay 10 ms
// xtal setting
modem_RfspiWrite(0xfe, 0x4000);
modem_RfspiWrite(0x10, 0x0880);
modem_RfspiWrite(0xfe, 0x0000);
}
#endif
static HWP_SPI_T *hwp_ispi = hwp_spi3;
void ispi_open(int modemSpi)
{
u32 cfgReg = 0;
u32 ctrlReg = 0;
// spi_clk_freq = APB2 / ((div+1)*2)
// the maximum clock frequency is 7MHz~8MHz
// the spi clock frequency is 5MHz when div is 0x13
cfgReg = 0x130003;
ctrlReg = 0x2019d821;
if (modemSpi)
hwp_ispi = hwp_mspi2;
else
hwp_ispi = hwp_spi3;
// Activate the ISPI.
hwp_ispi->cfg = cfgReg;
hwp_ispi->ctrl = ctrlReg;
// No IRQ.
hwp_ispi->irq = 0;
}
static u8 ispi_tx_fifo_avail(void)
{
u8 freeRoom;
// Get avail level.
freeRoom = GET_BITFIELD(hwp_ispi->status, SPI_TX_SPACE);
return freeRoom;
}
static int ispi_tx_finished(void)
{
u32 spiStatus;
spiStatus = hwp_ispi->status;
// If ISPI FSM is active and the TX Fifo is empty
// (ie available space == Fifo size), the tf is not done
if ((!(hwp_ispi->status & SPI_ACTIVE_STATUS))
&& (SPI_TX_FIFO_SIZE == GET_BITFIELD(spiStatus, SPI_TX_SPACE))) {
return TRUE;
} else {
return FALSE;
}
}
static u32 ispi_send_data(u32 csId, u32 data, int read)
{
u32 freeRoom;
// Clear data upper bit to only keep the data frame.
u32 reg = data & ~(SPI_CS_MASK | SPI_READ_ENA_MASK);
// Add CS and read mode bit
reg |= SPI_CS(csId) | (read ? SPI_READ_ENA : 0);
// Enter critical section.
//u32 status = hwp_sysIrq->SC;
// Check FIFO availability.
freeRoom = GET_BITFIELD(hwp_ispi->status, SPI_TX_SPACE);
if (freeRoom > 0) {
// Write data.
hwp_ispi->rxtx_buffer = reg;
// Exit critical section.
//hwp_sysIrq->SC = status;
return 1;
} else {
// Exit critical section.
//hwp_sysIrq->SC = status;
return 0;
}
}
static u32 ispi_get_data(u32 * recData)
{
u32 nbAvailable;
// Enter critical section.
//u32 status = hwp_sysIrq->SC;
nbAvailable = GET_BITFIELD(hwp_ispi->status, SPI_RX_LEVEL);
if (nbAvailable > 0) {
*recData = hwp_ispi->rxtx_buffer;
// Exit critical section.
//hwp_sysIrq->SC = status;
return 1;
} else {
// Exit critical section.
//hwp_sysIrq->SC = status;
return 0;
}
}
void ispi_reg_write(u32 regIdx, u32 value)
{
u32 wrData;
wrData = (0 << 25) | ((regIdx & 0x1ff) << 16) | (value & 0xffff);
while (ispi_tx_fifo_avail() < 1 ||
ispi_send_data(0, wrData, FALSE) == 0) ;
//wait until any previous transfers have ended
while (!ispi_tx_finished()) ;
}
u32 ispi_reg_read(u32 regIdx)
{
u32 wrData, rdData = 0;
u32 count;
wrData = (1 << 25) | ((regIdx & 0x1ff) << 16) | 0;
while (ispi_tx_fifo_avail() < 1 ||
ispi_send_data(0, wrData, TRUE) == 0) ;
//wait until any previous transfers have ended
while (!ispi_tx_finished()) ;
count = ispi_get_data(&rdData);
if (1 != count)
serial_puts("ABB ISPI count err!");
rdData &= 0xffff;
return rdData;
}
u16 rda_read_efuse(int page_index)
{
u16 rvalue, wvalue;
ispi_open(1);
wvalue = 0x2e0 | page_index;
pmu_reg_write(0x51, wvalue);
udelay(2000);
wvalue = 0x2f0 | page_index;
pmu_reg_write(0x51, wvalue);
rvalue = pmu_reg_read(0x52);
pmu_reg_write(0x51, 0x0200);
ispi_open(0);
return rvalue;
}
#ifdef EFUSE_DUMP
void dump_efuse(void)
{
u16 rvalue,wvalue;
int i;
ispi_open(1);
for(i = 0;i<16;i++){
wvalue = 0x2e0 | i;
pmu_reg_write(0x51, wvalue);
udelay(2000);
wvalue = 0x2f0 | i;
pmu_reg_write(0x51, wvalue);
rvalue = pmu_reg_read(0x52);
pmu_reg_write(0x51, 0x0200);
printf("page%d = %d \n", i, rvalue);
}
ispi_open(0);
}
#endif

View File

@ -0,0 +1,877 @@
#include "common.h"
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/reg_sysctrl.h>
#include <asm/arch/reg_mdcom.h>
#include <asm/arch/reg_xcpu.h>
#include <asm/arch/defs_mdcom.h>
#include <asm/arch/mdcom.h>
#include <asm/arch/factory.h>
#include <asm/arch/rda_iomap.h>
#include <asm/arch/reg_cfg_regs.h>
static u32 modem_logic_base_addr = 0x02000000;
void rda_mdcom_set_logic_base_addr(u32 base)
{
modem_logic_base_addr = base & 0xffff0000;
printf("## Set modem logic base address %#x\n", modem_logic_base_addr);
}
#define RDA_MODEM_IN_DDR(addr, modem_logic_base_addr) \
(((u32)(addr) & 0x0F000000) == (modem_logic_base_addr & 0x0F000000))
/*
* Convert a modem address to an AP address
*/
u32 rda_mdcom_address_modem2ap(u32 addr)
{
#if defined(_TGT_MODEM_MEM_SIZE) && (_TGT_MODEM_MEM_SIZE > 0)
if (RDA_MODEM_IN_DDR(addr, modem_logic_base_addr))
return (RDA_MODEM_RAM_BASE - modem_logic_base_addr + addr);
else
return RDA_ADD_M2A(addr);
#else
return RDA_ADD_M2A(addr);
#endif
}
/*
* Setup modem running env
*/
int rda_mdcom_setup_run_env(u32 pc, u32 param)
{
RDA_BOOT_HST_MONITOR_X_CTX_T *ctx =
(RDA_BOOT_HST_MONITOR_X_CTX_T *)RDA_BOOT_CTX_ADD;
ctx->cmdType = 0xFF;
ctx->pc = pc;
ctx->sp = 0;
ctx->param = (void *)param;
ctx->returnedValue = (void *)0;
#if defined(_TGT_MODEM_MEM_SIZE) && (_TGT_MODEM_MEM_SIZE > 0)
// Set DDR access offset
if (RDA_MODEM_IN_DDR(pc, modem_logic_base_addr)) {
#ifdef CONFIG_MACH_RDA8850E
u32 offs = RDA_MODEM_RAM_BASE - modem_logic_base_addr;
/* 0x1000000 alignment */
if(offs & 0xffffff) {
printf("\nERROR: modem memory map offset %#x is not aligned to 0x1000000.\n", offs);
printf("ERROR: modem cannot work, abort.\n");
return -1;
}
hwp_configRegs->Mem_mode_Sel = 0;
hwp_configRegs->H2X_DDR_Offset = offs;
hwp_configRegs->H2X_WD_DDR_Offset = offs;
#else
u32 offs = CFG_REGS_H2X_DDR_OFFSET((RDA_MODEM_RAM_BASE - modem_logic_base_addr) >> 24);
hwp_configRegs->H2X_DDR_Offset = offs;
#endif
};
#endif
return 0;
}
/*
* Modem calibration data section address
*/
void rda_mdcom_get_calib_section(u32 *addr, u32 *len)
{
if (addr)
*addr = RDA_MODEM_CAL_ADDR;
if (len)
*len = RDA_MODEM_CAL_LEN;
}
/*
* Modem extended calibration data section address
*/
void rda_mdcom_get_ext_calib_section(u32 *addr, u32 *len)
{
if (addr)
*addr = RDA_MODEM_EXT_CAL_ADDR;
if (len)
*len = RDA_MODEM_EXT_CAL_LEN;
}
/*
* Modem factory section address
*/
void rda_mdcom_get_factory_section(u32 *addr, u32 *len)
{
if (addr)
*addr = RDA_MODEM_FACT_ADDR;
if (len)
*len = RDA_MODEM_FACT_LEN;
}
/*
* AP factory section address
*/
void rda_mdcom_get_ap_factory_section(u32 *addr, u32 *len)
{
if (addr)
*addr = RDA_AP_FACT_ADDR;
if (len)
*len = RDA_AP_FACT_LEN;
}
/*
* Reset cause
*/
u32 rda_mdcom_get_reset_cause(void)
{
return ((RDA_AP_MBX_HEARTBEAT_T *)RDA_AP_MBX_HEARTBEAT_ADD)->resetCause;
}
/*
* Interface version
*/
u32 rda_mdcom_get_interface_version(void)
{
return ((RDA_AP_MBX_HEARTBEAT_T *)RDA_AP_MBX_HEARTBEAT_ADD)->version;
}
/*
* Magic number
*/
int rda_mdcom_system_started_before(void)
{
RDA_AP_MBX_MAGIC_NUMBER_T *magic =
(RDA_AP_MBX_MAGIC_NUMBER_T *)RDA_AP_MBX_MAGIC_NUMBER_ADD;
return magic->sysStarted == RDA_MAGIC_SYSTEM_STARTED_FLAG;
}
void rda_mdcom_set_system_started_flag(void)
{
RDA_AP_MBX_MAGIC_NUMBER_T *magic =
(RDA_AP_MBX_MAGIC_NUMBER_T *)RDA_AP_MBX_MAGIC_NUMBER_ADD;
magic->sysStarted = RDA_MAGIC_SYSTEM_STARTED_FLAG;
}
int rda_mdcom_modem_crashed_before(void)
{
RDA_AP_MBX_MAGIC_NUMBER_T *magic =
(RDA_AP_MBX_MAGIC_NUMBER_T *)RDA_AP_MBX_MAGIC_NUMBER_ADD;
return magic->modemCrashed == RDA_MAGIC_MODEM_CRASH_FLAG;
}
int rda_mdcom_calib_update_cmd_valid(void)
{
RDA_AP_MBX_MAGIC_NUMBER_T *magic =
(RDA_AP_MBX_MAGIC_NUMBER_T *)RDA_AP_MBX_MAGIC_NUMBER_ADD;
if (magic->factUpdateCmd == RDA_MAGIC_FACT_UPD_CMD_FLAG &&
(magic->factUpdateType &
RDA_MAGIC_FACT_UPD_TYPE_FLAG_MASK) ==
RDA_MAGIC_FACT_UPD_TYPE_FLAG &&
(magic->factUpdateType & RDA_MAGIC_FACT_UPD_TYPE_CALIB))
return 1;
else
return 0;
}
int rda_mdcom_factory_update_cmd_valid(void)
{
RDA_AP_MBX_MAGIC_NUMBER_T *magic =
(RDA_AP_MBX_MAGIC_NUMBER_T *)RDA_AP_MBX_MAGIC_NUMBER_ADD;
if (magic->factUpdateCmd == RDA_MAGIC_FACT_UPD_CMD_FLAG &&
(magic->factUpdateType &
RDA_MAGIC_FACT_UPD_TYPE_FLAG_MASK) ==
RDA_MAGIC_FACT_UPD_TYPE_FLAG &&
(magic->factUpdateType & RDA_MAGIC_FACT_UPD_TYPE_FACT))
return 1;
else
return 0;
}
int rda_mdcom_ap_factory_update_cmd_valid(void)
{
RDA_AP_MBX_MAGIC_NUMBER_T *magic =
(RDA_AP_MBX_MAGIC_NUMBER_T *)RDA_AP_MBX_MAGIC_NUMBER_ADD;
if (magic->factUpdateCmd == RDA_MAGIC_FACT_UPD_CMD_FLAG &&
(magic->factUpdateType &
RDA_MAGIC_FACT_UPD_TYPE_FLAG_MASK) ==
RDA_MAGIC_FACT_UPD_TYPE_FLAG &&
(magic->factUpdateType & RDA_MAGIC_FACT_UPD_TYPE_AP_FACT))
return 1;
else
return 0;
}
/*
* Modem log info
*/
static int rda_mdcom_modem_address_valid(u32 addr)
{
if ((addr >= RDA_MODEM_INTSRAM_BASE &&
addr < RDA_MODEM_INTSRAM_END) ||
(addr >= RDA_MODEM_RAM_BASE &&
addr < RDA_MODEM_RAM_END)) {
return 1;
}
return 0;
}
void rda_mdcom_init_all_log_info(void)
{
/* Init log info */
RDA_AP_MBX_LOG_BUF_INFO_T *log =
(RDA_AP_MBX_LOG_BUF_INFO_T *)RDA_AP_MBX_LOG_BUF_INFO_ADD;
memset(log, 0, sizeof(*log));
/* Init modem crash flag */
RDA_AP_MBX_MAGIC_NUMBER_T *magic =
(RDA_AP_MBX_MAGIC_NUMBER_T *)RDA_AP_MBX_MAGIC_NUMBER_ADD;
magic->modemCrashed = 0;
magic->factUpdateCmd = 0;
magic->factUpdateType = 0;
/* Init heartbeat structure members */
memset((RDA_AP_MBX_HEARTBEAT_T *)RDA_AP_MBX_HEARTBEAT_ADD, 0,
sizeof(RDA_AP_MBX_HEARTBEAT_T));
}
void rda_mdcom_get_modem_log_info(u32 *addr, u32 *len)
{
RDA_AP_MBX_LOG_BUF_INFO_T *log =
(RDA_AP_MBX_LOG_BUF_INFO_T *)RDA_AP_MBX_LOG_BUF_INFO_ADD;
u32 log_addr = rda_mdcom_address_modem2ap(log->modemAddr);
u32 log_len = log->modemLen;
/* Check whether the address is valid */
if (!rda_mdcom_modem_address_valid(log_addr) ||
log_len > RDA_AP_MBX_MAX_MODEM_LOG_LEN) {
log_addr = 0;
log_len = 0;
}
if (addr)
*addr = log_addr;
if (len)
*len = log_len;
}
void rda_mdcom_get_modem_exception_info(u32 *addr, u32 *len)
{
RDA_AP_MBX_LOG_BUF_INFO_T *log =
(RDA_AP_MBX_LOG_BUF_INFO_T *)RDA_AP_MBX_LOG_BUF_INFO_ADD;
u32 exc_addr = RDA_ADD_M2A(log->modemExcAddr);
u32 exc_len = log->modemExcLen;
/* Check whether the address is valid */
if (!rda_mdcom_modem_address_valid(exc_addr) ||
exc_len > RDA_AP_MBX_MAX_MODEM_EXC_LEN) {
exc_addr = 0;
exc_len = 0;
}
if (addr)
*addr = exc_addr;
if (len)
*len = exc_len;
}
/*
* Modem XCPU info
*/
void rda_mdcom_show_xcpu_info(void)
{
printf("\n");
printf("Modem XCPU info:\n");
printf("----------------\n");
printf("Cause = 0x%08x\n", hwp_xcpu->cp0_Cause);
printf("Status = 0x%08x\n", hwp_xcpu->cp0_Status);
printf("BadAddr = 0x%08x\n", hwp_xcpu->cp0_BadVAddr);
printf("EPC = 0x%08x\n", hwp_xcpu->cp0_EPC);
printf("RA = 0x%08x\n", hwp_xcpu->Regfile_RA);
printf("PC = 0x%08x\n", hwp_xcpu->rf0_addr);
printf("----------------\n");
}
/*
* Modem software version info
*/
void rda_mdcom_show_software_version(void)
{
int i = 0;
char buf[256];
char *str;
RDA_MODEM_MAP_VERSION_T *version;
RDA_MODEM_MAP_MODULE_T *map;
RDA_MODEM_MAP_MODULE_T **ptr =
(RDA_MODEM_MAP_MODULE_T **)RDA_MODEM_MAP_PTR;
printf("\n");
map = (RDA_MODEM_MAP_MODULE_T *)rda_mdcom_address_modem2ap(
(u32)*ptr);
if (!ptr || !rda_mdcom_modem_address_valid((u32)map)) {
printf("No modem software versions\n");
return;
}
printf("Modem software versions:\n");
printf("------------------------\n");
for (i = 0; i < RDA_MODEM_MAP_QTY; i++, map++) {
if (!map->version)
continue;
version = (RDA_MODEM_MAP_VERSION_T *)
rda_mdcom_address_modem2ap((u32)map->version);
if (!rda_mdcom_modem_address_valid((u32)version))
continue;
printf("[%02d]\n", i);
printf("revision = %d / 0x %07x\n",
version->revision,
version->revision);
printf("number = %d\n", version->number);
printf("date = %d\n", version->date);
str = (char *)rda_mdcom_address_modem2ap((u32)version->string);
if (version->string &&
rda_mdcom_modem_address_valid((u32)str)) {
snprintf(buf, sizeof(buf), "%s", str);
buf[sizeof(buf) - 1] = '\0';
printf("string = %s\n", buf);
} else {
printf("string = <n/a>\n");
}
}
printf("------------------------\n");
}
/*
* Communication channels
*/
static struct rda_mdcom_channel rda_rda_mdcom_chn[] = {
/* AT command channel */
{
RDA_MDCOM_LINE_AT_CMD,
RDA_MDCOM_LINE_AT_CMD_FC,
(struct rda_mdcom_channel_head*)RDA_MDCOM_CHN_AT_HEAD_ADD_READ,
(void *)RDA_MDCOM_CHN_AT_BUF_ADD_READ,
RDA_MDCOM_CHN_AT_BUF_LEN_READ-1,
(struct rda_mdcom_channel_head*)RDA_MDCOM_CHN_AT_HEAD_ADD_WRITE,
(void *)RDA_MDCOM_CHN_AT_BUF_ADD_WRITE,
RDA_MDCOM_CHN_AT_BUF_LEN_WRITE-1
},
/* SYSTEM command channel */
{
RDA_MDCOM_LINE_SYSTEM,
RDA_MDCOM_LINE_SYSTEM_FC,
(struct rda_mdcom_channel_head*)RDA_MDCOM_CHN_SYS_HEAD_ADD_READ,
(void *)RDA_MDCOM_CHN_SYS_BUF_ADD_READ,
RDA_MDCOM_CHN_SYS_BUF_LEN_READ-1,
(struct rda_mdcom_channel_head*)RDA_MDCOM_CHN_SYS_HEAD_ADD_WRITE,
(void *)RDA_MDCOM_CHN_SYS_BUF_ADD_WRITE,
RDA_MDCOM_CHN_SYS_BUF_LEN_WRITE-1
},
/* TRACE communciation channel */
{
RDA_MDCOM_LINE_TRACE,
RDA_MDCOM_LINE_TRACE_FC,
(struct rda_mdcom_channel_head*)RDA_MDCOM_CHN_TRACE_HEAD_ADD_READ,
(void *)RDA_MDCOM_CHN_TRACE_BUF_ADD_READ,
RDA_MDCOM_CHN_TRACE_BUF_LEN_READ-1,
(struct rda_mdcom_channel_head*)RDA_MDCOM_CHN_TRACE_HEAD_ADD_WRITE,
(void *)RDA_MDCOM_CHN_TRACE_BUF_ADD_WRITE,
RDA_MDCOM_CHN_TRACE_BUF_LEN_WRITE-1
}
};
int rda_mdcom_init_port(int port_id)
{
switch (port_id) {
case RDA_MDCOM_PORT0:
hwp_mdComregs->Mask_Set = COMREGS_IRQ0_MASK_SET(0);
hwp_mdComregs->Mask_Clr = COMREGS_IRQ0_MASK_CLR(0xFF);
hwp_mdComregs->ItReg_Set = COMREGS_IRQ0_SET(0);
hwp_mdComregs->ItReg_Clr = COMREGS_IRQ0_CLR(0xFF);
return 0;
case RDA_MDCOM_PORT1:
hwp_mdComregs->Mask_Set = COMREGS_IRQ1_MASK_SET(0);
hwp_mdComregs->Mask_Clr = COMREGS_IRQ1_MASK_CLR(0xFF);
hwp_mdComregs->ItReg_Set = COMREGS_IRQ1_SET(0);
hwp_mdComregs->ItReg_Clr = COMREGS_IRQ1_CLR(0xFF);
return 0;
default:
return -EINVAL;
}
}
int rda_mdcom_line_set(int port_id, int line_id)
{
if (line_id & ~0x7) {
return -EINVAL;
}
switch (port_id) {
case RDA_MDCOM_PORT0:
hwp_mdComregs->ItReg_Set = COMREGS_IRQ0_SET(1 << line_id);
return 0;
case RDA_MDCOM_PORT1:
hwp_mdComregs->ItReg_Set = COMREGS_IRQ1_SET(1 << line_id);
return 0;
default:
return -EINVAL;
}
}
int rda_mdcom_line_clear(int port_id, int line_id)
{
if (line_id & ~0x7) {
return -EINVAL;
}
switch (port_id) {
case RDA_MDCOM_PORT0:
hwp_mdComregs->ItReg_Clr = COMREGS_IRQ0_CLR(1 << line_id);
return 0;
case RDA_MDCOM_PORT1:
hwp_mdComregs->ItReg_Clr = COMREGS_IRQ0_CLR(1 << line_id);
return 0;
default:
return -EINVAL;
}
}
int rda_mdcom_line_set_check(int port_id, int line_id)
{
if (line_id & ~0x7) {
return 0;
}
switch (port_id) {
case RDA_MDCOM_PORT0:
return !!(hwp_mdComregs->ItReg_Clr & COMREGS_IRQ0_CLR(1 << line_id));
case RDA_MDCOM_PORT1:
return !!(hwp_mdComregs->ItReg_Clr & COMREGS_IRQ1_CLR(1 << line_id));
default:
return 0;
}
}
int rda_mdcom_line_clear_check(int port_id, int line_id)
{
if (line_id & ~0x7) {
return 0;
}
switch (port_id) {
case RDA_MDCOM_PORT0:
return !(hwp_mdComregs->ItReg_Set & COMREGS_IRQ0_SET(1 << line_id));
case RDA_MDCOM_PORT1:
return !(hwp_mdComregs->ItReg_Set & COMREGS_IRQ0_SET(1 << line_id));
default:
return 0;
}
}
int rda_mdcom_line_set_wait(int port_id, int line_id, int waittime)
{
unsigned long end_time = get_ticks() + waittime;
if (line_id & ~0x7) {
return 0;
}
switch (port_id) {
case RDA_MDCOM_PORT0:
while (!(hwp_mdComregs->ItReg_Clr & COMREGS_IRQ0_CLR(1 << line_id))) {
if ((waittime >= 0) && (end_time <= get_ticks()))
return 0;
}
return 1;
case RDA_MDCOM_PORT1:
while (!(hwp_mdComregs->ItReg_Clr & COMREGS_IRQ1_CLR(1 << line_id))) {
if ((waittime >= 0) && (end_time <= get_ticks()))
return 0;
}
return 1;
default:
return 0;
}
}
int rda_mdcom_line_clear_wait(int port_id, int line_id, int waittime)
{
unsigned long end_time = get_ticks() + waittime;
if (line_id & ~0x7) {
return 0;
}
switch (port_id) {
case RDA_MDCOM_PORT0:
while (hwp_mdComregs->ItReg_Set & COMREGS_IRQ0_SET(1 << line_id)) {
if ((waittime >= 0) && (end_time <= get_ticks()))
return 0;
}
return 1;
case RDA_MDCOM_PORT1:
while (hwp_mdComregs->ItReg_Set & COMREGS_IRQ0_SET(1 << line_id)) {
if ((waittime >= 0) && (end_time <= get_ticks()))
return 0;
}
return 1;
default:
return 0;
}
}
void rda_mdcom_port_show(void)
{
printf("RDA MDCOM ports stauts:\n");
printf("REGISTER Cause = 0x%.16x\n", hwp_mdComregs->Cause);
printf("REGISTER Mask_Set = 0x%.16x\n", hwp_mdComregs->Mask_Set);
printf("REGISTER Mask_Clr = 0x%.16x\n", hwp_mdComregs->Mask_Clr);
printf("REGISTER ItReg_Set = 0x%.16x\n", hwp_mdComregs->ItReg_Set);
printf("REGISTER ItReg_Clr = 0x%.16x\n", hwp_mdComregs->ItReg_Clr);
printf("RDA MDCOM ports stauts end.\n");
}
int rda_mdcom_channel_init(const unsigned int channel)
{
if (channel >= sizeof(rda_rda_mdcom_chn) / sizeof(struct rda_mdcom_channel)) {
return -EINVAL;
}
memset(rda_rda_mdcom_chn[channel].read_buf_head, 0,
sizeof(struct rda_mdcom_channel_head));
memset(rda_rda_mdcom_chn[channel].write_buf_head, 0,
sizeof(struct rda_mdcom_channel_head));
return 0;
}
int rda_mdcom_channel_all_init(void)
{
return rda_mdcom_channel_init(RDA_MDCOM_CHANNEL_AT) ||
rda_mdcom_channel_init(RDA_MDCOM_CHANNEL_SYSTEM) ||
rda_mdcom_channel_init(RDA_MDCOM_CHANNEL_TRACE);
}
int rda_mdcom_channel_buf_send_stream(const unsigned int channel, void *buf,
int size, int waittime)
{
unsigned long end_time = get_ticks() + waittime;
struct rda_mdcom_channel* channel_ptr;
struct rda_mdcom_channel_head* channel_head_ptr;
int buffer_size_mask;
int count = 0;
if (channel >= sizeof(rda_rda_mdcom_chn) / sizeof(struct rda_mdcom_channel)) {
return -EINVAL;
}
if (size < 0) {
return -EINVAL;
}
channel_ptr = &rda_rda_mdcom_chn[channel];
channel_head_ptr = channel_ptr->write_buf_head;
buffer_size_mask = channel_ptr->write_buf_size_mask;
while (1) {
int write_offset = channel_head_ptr->write_offset;
int remain_len = (buffer_size_mask + 1) -
((write_offset - channel_head_ptr->read_offset) & buffer_size_mask);
if (remain_len > buffer_size_mask + 1 - write_offset) {
remain_len = buffer_size_mask + 1 - write_offset;
}
if (remain_len) {
if (remain_len > size) {
remain_len = size;
}
memcpy(((char*)channel_ptr->write_buf) + write_offset, buf, remain_len);
channel_head_ptr->write_offset = (write_offset + remain_len) & buffer_size_mask;
size -= remain_len;
buf = (char*)buf + remain_len;
count += remain_len;
if (!size) {
return count;
}
} else if ((waittime >= 0) && (end_time <= get_ticks())) {
return count;
}
}
}
int rda_mdcom_channel_buf_send_dgram(const unsigned int channel, void *buf,
int size, int waittime)
{
unsigned long end_time = get_ticks() + waittime;
struct rda_mdcom_channel* channel_ptr;
struct rda_mdcom_channel_head* channel_head_ptr;
int buffer_size_mask, write_offset;
if (channel >= sizeof(rda_rda_mdcom_chn) / sizeof(struct rda_mdcom_channel)) {
return -EINVAL;
}
if (size < 0) {
return -EINVAL;
}
channel_ptr = &rda_rda_mdcom_chn[channel];
channel_head_ptr = channel_ptr->write_buf_head;
buffer_size_mask = channel_ptr->write_buf_size_mask;
write_offset = ALIGN(channel_head_ptr->write_offset, 4) & buffer_size_mask;
while (1) {
int remain_len = (buffer_size_mask + 1) -
((write_offset - channel_head_ptr->read_offset) & buffer_size_mask);
if (remain_len >= size) {
remain_len = buffer_size_mask + 1 - write_offset;
if (remain_len > size) {
remain_len = size;
}
memcpy(((char*)channel_ptr->write_buf) + write_offset, buf,
remain_len);
if (remain_len != size) {
memcpy(channel_ptr->write_buf, (char*)buf + remain_len,
size - remain_len);
}
channel_head_ptr->write_offset = (write_offset + size) &
buffer_size_mask;
return 0;
}
if ((waittime >= 0) && (end_time <= get_ticks())) {
return -EAGAIN;
}
}
}
int rda_mdcom_channel_buf_send_available(const unsigned int channel)
{
struct rda_mdcom_channel* channel_ptr;
struct rda_mdcom_channel_head* channel_head_ptr;
int buffer_size_mask;
int read_offset;
int write_offset;
if (channel >= sizeof(rda_rda_mdcom_chn)/sizeof(struct rda_mdcom_channel)) {
return 0;
}
channel_ptr = &rda_rda_mdcom_chn[channel];
channel_head_ptr = channel_ptr->write_buf_head;
buffer_size_mask = channel_ptr->write_buf_size_mask;
read_offset = channel_head_ptr->read_offset;
write_offset = channel_head_ptr->write_offset;
return ((buffer_size_mask + 1) - ((write_offset - read_offset) & buffer_size_mask));
}
int rda_mdcom_channel_buf_recv_stream(const unsigned int channel, void *buf,
int size, int waittime)
{
unsigned long end_time = get_ticks() + waittime;
struct rda_mdcom_channel* channel_ptr;
struct rda_mdcom_channel_head* channel_head_ptr;
int buffer_size_mask;
int count = 0;
int buf_offset = 0;
if (channel >= sizeof(rda_rda_mdcom_chn) / sizeof(struct rda_mdcom_channel)) {
return -EINVAL;
}
if (size < 0) {
return -EINVAL;
}
channel_ptr = &rda_rda_mdcom_chn[channel];
channel_head_ptr = channel_ptr->read_buf_head;
buffer_size_mask = channel_ptr->read_buf_size_mask;
while (1) {
int read_offset = channel_head_ptr->read_offset;
int remain_len = channel_head_ptr->write_offset - read_offset;
if (remain_len < 0) {
remain_len = buffer_size_mask + 1 - read_offset;
}
if (remain_len) {
if (remain_len > size) {
remain_len = size;
}
memcpy((char *)buf + buf_offset, ((char*)channel_ptr->read_buf) + read_offset, remain_len);
channel_head_ptr->read_offset = (read_offset + remain_len) &
buffer_size_mask;
size -= remain_len;
count += remain_len;
buf_offset += remain_len;
if (!size) {
return count;
}
} else if ((waittime >= 0) && (end_time <= get_ticks())) {
return count;
}
}
}
int rda_mdcom_channel_buf_recv_dgram(const unsigned int channel, void *buf,
int size, int waittime)
{
unsigned long end_time = get_ticks() + waittime;
struct rda_mdcom_channel* channel_ptr;
struct rda_mdcom_channel_head* channel_head_ptr;
int buffer_size_mask, read_offset;
if (channel >= sizeof(rda_rda_mdcom_chn) / sizeof(struct rda_mdcom_channel)) {
return -EINVAL;
}
if (size < 0) {
return -EINVAL;
}
channel_ptr = &rda_rda_mdcom_chn[channel];
channel_head_ptr = channel_ptr->read_buf_head;
buffer_size_mask = channel_ptr->read_buf_size_mask;
read_offset = ALIGN(channel_head_ptr->read_offset, 4) & buffer_size_mask;
while (1) {
int remain_len = (channel_head_ptr->write_offset - read_offset +
buffer_size_mask + 1) & buffer_size_mask;
if (remain_len >= size) {
remain_len = buffer_size_mask + 1 - read_offset;
if (remain_len > size) {
remain_len = size;
}
memcpy(buf, ((char*)channel_ptr->read_buf) + read_offset, remain_len);
if (remain_len != size) {
memcpy(((char *)buf + remain_len), channel_ptr->read_buf, size - remain_len);
}
channel_head_ptr->read_offset = (read_offset + size) & buffer_size_mask;
return 0;
}
if ((waittime >= 0) && (end_time <= get_ticks())) {
return -EAGAIN;
}
}
}
int rda_mdcom_channel_buf_recv_available(const unsigned int channel)
{
struct rda_mdcom_channel* channel_ptr;
struct rda_mdcom_channel_head* channel_head_ptr;
int buffer_size_mask;
int read_offset;
int write_offset;
if (channel >= sizeof(rda_rda_mdcom_chn) / sizeof(struct rda_mdcom_channel)) {
return 0;
}
channel_ptr = &rda_rda_mdcom_chn[channel];
channel_head_ptr = channel_ptr->write_buf_head;
buffer_size_mask = channel_ptr->write_buf_size_mask;
read_offset = channel_head_ptr->read_offset;
write_offset = channel_head_ptr->write_offset;
return ((write_offset - read_offset) & buffer_size_mask);
}
void rda_mdcom_channel_show(const unsigned int channel)
{
printf("RDA MDCOM channel %d stauts:\n", channel);
if (channel >= sizeof(rda_rda_mdcom_chn) / sizeof(struct rda_mdcom_channel)) {
printf("Channel number is out of range, ERROR!\n");
} else {
struct rda_mdcom_channel* channel_ptr = &rda_rda_mdcom_chn[channel];
struct rda_mdcom_channel_head* channel_head_ptr;
printf("Read buffer head address = 0x%p\n",
channel_ptr->read_buf_head);
printf("Read buffer address = 0x%p\n",
channel_ptr->read_buf);
printf("Read buffer length = %d\n",
channel_ptr->read_buf_size_mask + 1);
channel_head_ptr = channel_ptr->read_buf_head;
printf("Read buffer offset read = 0x%x\n",
channel_head_ptr->read_offset);
printf("Read buffer offset write = 0x%x\n",
channel_head_ptr->write_offset);
printf("Write buffer head address = 0x%p\n",
channel_ptr->write_buf_head);
printf("Write buffer address = 0x%p\n",
channel_ptr->write_buf);
printf("Write buffer length = %d\n",
channel_ptr->write_buf_size_mask + 1);
channel_head_ptr = channel_ptr->write_buf_head;
printf("Write buffer offset read = 0x%x\n",
channel_head_ptr->read_offset);
printf("Write buffer offset write = 0x%x\n",
channel_head_ptr->write_offset);
}
printf("RDA MDCOM channel %d stauts end.\n", channel);
}
int rda_mdcom_tstc(const unsigned int channel)
{
struct rda_mdcom_channel_head* channel_head_ptr;
if (channel >= sizeof(rda_rda_mdcom_chn) / sizeof(struct rda_mdcom_channel)) {
return 0;
}
channel_head_ptr = rda_rda_mdcom_chn[channel].read_buf_head;
return (channel_head_ptr->write_offset != channel_head_ptr->read_offset);
}
int rda_mdcom_getc(const unsigned int channel)
{
char c = 0;
rda_mdcom_channel_buf_recv_stream(channel, &c, 1, -1);
return c;
}
void rda_mdcom_putc(const char c, const unsigned int channel)
{
rda_mdcom_channel_buf_send_stream(channel, (void*)&c, 1, -1);
}
void rda_mdcom_puts(const char *s, const unsigned int channel)
{
rda_mdcom_channel_buf_send_stream(channel, (void*)s, strlen(s), -1);
}

View File

@ -0,0 +1,260 @@
#include <common.h>
#include <asm/u-boot.h>
#include <asm/utils.h>
#include <nand.h>
#include <malloc.h>
#include <image.h>
#include <usb/usbserial.h>
#include <asm/arch/rda_sys.h>
#include <asm/arch/rda_crypto.h>
#include <pdl.h>
//#define RDA_CRYPTO_DEBUG
#ifdef CONFIG_SIGNATURE_CHECK_IMAGE
struct pubkey_cert_t {
struct {
uint16_t se_cfg; // vendor_id and key_index
uint8_t dummy[94]; // 96
struct pubkey pubkey; // +64
} c;
struct sig signature; // +96
};
struct rda_cert_t {
// R&D Certificate:
// Create a signature with name[16] =
// " R&D-CERT"(10)
// "F:0000"(6)
// zeros[16] = 0...
// Then Hash:
// sig.name, zeros, UNIQUE-ID
struct sig rnd_cert; // 96
// free space without sign checking:
uint8_t dummy[160]; // 160
};
struct rda_se_image {
uint8_t spl_code[48128+160];
struct sig image_signature; // 96
struct rda_cert_t cert; // 256
struct pubkey_cert_t vendor_pubkey_cert; // 256
};
#ifdef RDA_CRYPTO_DEBUG
# define puts_deb(a) puts(a)
#else
# define puts_deb(a)
# define debug_dump_key_and_signature(h,pk,sig,d,l)
#endif
#ifdef RDA_CRYPTO_DEBUG
static void debug_dump_key_and_signature(
const char *header, const struct pubkey *pk, const struct sig *sig,
const void *data, unsigned data_len)
{
if (sig) {
printf("%s signature:\n", header);
rda_dump_buf((char *)sig, 96);
}
if (pk) {
printf("%s public key:\n", header);
rda_dump_buf((char *)pk, 64);
}
if (data) {
printf("%s data:\n", header);
rda_dump_buf((char *)data, data_len);
}
}
#endif
static int check_rnd_certificate(
const struct rda_cert_t *certs,
const struct pubkey *pubkey,
struct spl_security_info *info)
{
int ret;
const struct sig *rnd_signature = &certs->rnd_cert;
struct {
uint8_t message[32];
struct chip_unique_id id;
} hashme;
puts_deb("Checking R&D Certificate\n");
// create message
memset(&hashme, 0, sizeof(hashme));
memcpy(hashme.message, rnd_signature->name, 16);
hashme.id = info->chip_unique_id;
// Dump the R&D hashme
debug_dump_key_and_signature("R&D hashme", pubkey, rnd_signature,
(char *)&hashme, sizeof(hashme));
ret = signature_check(
(const uint8_t*)&hashme, sizeof(hashme),
rnd_signature,
pubkey);
return ret;
}
static void get_device_security_context(
const struct rda_se_image *image,
struct spl_security_info *info)
{
// Get ROM public key and context
info->secure_mode = get_chip_security_context(
&info->chip_security_context,
&info->pubkey);
int flags = info->chip_security_context.flags;
// Fix the return code if security hasn't been enabled
if ((flags & RDA_SE_CFG_SECURITY_ENABLE_BIT) == 0) {
puts_deb("(Security disabled by efuse flags)\n");
info->secure_mode = ROM_API_SECURITY_DISABLED;
return;
}
// Check if we a using the customer public-key certificate
if (flags & RDA_SE_CFG_INDIRECT_SIGN_BIT) {
const struct pubkey_cert_t *vendor_cert = &image->vendor_pubkey_cert;
puts_deb("(Using vendor pkcert as per efuse flags)\n");
// The vendor pkey cert has already been verified
// by the bootrom. For debugging check again here:
#ifdef RDA_CRYPTO_DEBUG
// Dump the PKCERT data
debug_dump_key_and_signature("PKCERT",
&info->pubkey, &vendor_cert->signature,
&vendor_cert->c, sizeof(vendor_cert->c));
int ret;
ret = signature_check(
(uint8_t*)&vendor_cert->c, sizeof(vendor_cert->c),
&vendor_cert->signature,
&info->pubkey);
printf("PKCERT check return %d\n", ret);
#endif
// copy public key certificate
info->pubkey = vendor_cert->c.pubkey;
}
// Sanity check for PKEY
if (memcmp(&info->pubkey, "RDASEd", 6) != 0) {
puts_deb("(Public key for signature check invalid)\n");
info->secure_mode = -1; // better: ROM_API_SECURITY_INVALID_PKEY
return;
}
// Dump the keys and signature when debugging
debug_dump_key_and_signature("PDL1 -",
&info->pubkey, &image->image_signature, NULL, 0);
// Check if device is in R&D mode
int rnd_status = check_rnd_certificate(&image->cert, &info->pubkey, info);
if (rnd_status == 0) {
puts("(R&D mode override) ");
// ... and disable security...
info->secure_mode = ROM_API_SECURITY_DISABLED;
}
}
int set_security_context(struct spl_security_info *info, const void *_image)
{
const struct rda_se_image *image = _image;
memset(info, 0, sizeof(*info));
if (memcmp(romapi->magic, "RDA API", 8) != 0) {
puts("Board security: Not present\n");
info->secure_mode = ROM_API_SECURITY_UNAVAILABLE;
}
else {
puts("Board security: present ");
info->version = romapi->version;
get_chip_id(&info->chip_id);
get_chip_true_random(info->random, 32);
get_chip_unique(&info->chip_unique_id);
get_device_security_context(image, info);
switch (info->secure_mode) {
case ROM_API_SECURITY_ENABLED:
puts("and enabled.\n");
break;
case ROM_API_SECURITY_DISABLED:
puts("but disabled.\n");
break;
case ROM_API_INVALID_KEYINDEX:
case ROM_API_INVALID_VENDOR_ID:
puts("but has invalid key-index or vendor-id!\n");
break;
default:
puts("but has invalid configuration!\n");
break;
}
}
return info->secure_mode;
}
int image_sign_verify(const uint8_t *buffer, uint32_t len)
{
spl_bd_t *spl_board_info = (spl_bd_t *)CONFIG_SPL_BOARD_INFO_ADDR;
struct spl_security_info *info = &spl_board_info->spl_security_info;
len -= sizeof(struct sig);
const struct sig *signature = (const struct sig *)(buffer + len);
puts("Verify image:\n");
// Check security mode
int secure_mode = info->secure_mode;
switch (secure_mode) {
case ROM_API_SECURITY_ENABLED:
// Check the signature of the image
debug_dump_key_and_signature("bootloader -",
&info->pubkey, signature, NULL, 0);
return signature_check(buffer, len, signature, &info->pubkey);
case ROM_API_SECURITY_DISABLED:
case ROM_API_SECURITY_UNAVAILABLE:
return 0;
default:
return secure_mode; // This is != 0 -> verify error
}
}
int image_sign_verify_uimage(image_header_t *hdr)
{
return image_sign_verify((const uint8_t *)hdr,
image_get_image_size(hdr) + sizeof(struct sig));
}
#else
int set_security_context(struct spl_security_info *info, const void *_image)
{
memset(info, 0, sizeof(*info));
if (memcmp(romapi->magic, "RDA API", 8) == 0) {
puts("Board security: present ");
info->version = romapi->version;
get_chip_unique(&info->chip_unique_id);
}
return ROM_API_SECURITY_DISABLED;
}
int image_sign_verify(const uint8_t *buffer, uint32_t len)
{
return 0;
}
#endif

View File

@ -0,0 +1,133 @@
/*
* Warning:
*
* This file is a mess of debugging and ROM bug workarounds.
*/
/* Enable a workaround for a bug in the bootrom romapi. */
#define RDA8810_VENDOR_EFUSE_WORKAROUND
/* Enable debugging certificates in pdl1: */
//#define RDA_CRYPTO_DEBUG_FAKE_ROMCERT
#ifdef RDA_CRYPTO_DEBUG_FAKE_ROMCERT
/*
* Debugging version og get_chip_security_context().
* This version is enabled with RDA_CRYPTO_DEBUG_FAKE_ROMCERT
*
TEST DATA
Use this secret key (file: rdatest.sec, pw: pa$$w0rd):
"Comment: RDA PDL-Test-01 secret key
UkRBU0VkQksAAAAq0Ai4xjiIrmda3G8qI6q3B4gPbVQMPISmUkRBIFBETC1UZXN0LTAxACU+PXqYnPYI
gGYdDrpN5PljQAAht3pYTN4bNgtA6oRp/sEVIrSXZiEkZPRGsnqlGPGFRHn3MMsDZBz/FhZGdE1m2FnD
YYgQMg=="
*/
int get_chip_security_context(
struct chip_security_context *context,
struct pubkey *pubkey)
{
const struct chip_security_context c = {
3, 0x42,
RDA_SE_CFG_SECURITY_ENABLE_BIT |
RDA_SE_CFG_INDIRECT_SIGN_BIT |
RDA_SE_CFG_UNLOCK_ALLOWED
};
const struct pubkey pk = {
/* Public key: rdatest.pub */
{'R','D','A','S'}, {'E','d'},{}, "RDA PDL-Test-01 ",
{ 0x25,0x3e,0x3d,0x7a,0x98,0x9c,0xf6,0x08 },
{ 0x7b,0x4a,0x5a,0xa8,0xa1,0xda,0x92,0xea,0x9e,0x90,0xa8,0x7e,
0xfa,0x76,0x37,0x52,0xe0,0xe0,0x40,0x63,0x09,0x02,0xd3,0x86,
0x8b,0x9d,0xe0,0xae,0xf3,0x57,0xd7,0x44 }
};
// Set the hardcoded debug public key and context
*context = c;
*pubkey = pk;
return ROM_API_SECURITY_ENABLED;
}
#endif
#ifdef RDA8810_VENDOR_EFUSE_WORKAROUND
#include <common.h>
#include <asm/arch/rda_crypto.h>
#include <asm/arch/ispi.h>
#define RDA_EFUSE_INDEX_SECURITY (11)
/*
Fuse layout:
VVVVVVVV.T.H.I.S.KKKK
VVVVVVVV: Vendor ID - 6bit + 2bit armour
T: Trace disable
H: Host serial disable
I: Indirectly signed image
S: Security enable
KKKK: RDA Public Key Index - 3bit + 1 bit armour
*/
/* define bit for rda se config */
#define RDA_SE_CFG_KEY_INDEX(n) (((n)&0xF)<<0)
#define RDA_SE_CFG_GET_KEY_INDEX(r) (((r)>>0)&0xF)
#define RDA_SE_CFG_SECURITY_ENABLE_BIT (1<<4)
#define RDA_SE_CFG_INDIRECT_SIGN_BIT (1<<5)
#define RDA_SE_CFG_HOST_DISABLE_BIT (1<<6)
#define RDA_SE_CFG_TRACE_DISABLE_BIT (1<<7)
#define RDA_SE_CFG_VENDOR_ID(n) (((n)&0xFF)<<8)
#define RDA_SE_CFG_GET_VENDOR_ID(r) (((r)>>8)&0xFF)
// RDA Public Key index map
// (armour 6 indexes in 4 bits)
static const uint8_t keyindex_map[16] = {
15, 15, 15, 0, 15, 1, 2, 15,
15, 3, 4, 15, 5, 15, 15, 15
};
// Vendor ID
// (armour 50 vendor ID'd in 8 bits)
static int valid_vendor_id( unsigned vendor )
{
unsigned c;
unsigned i = vendor >> 2;
c = ((i & 0xaa)>>1) + (i & 0x55);
c = ((c & 0xcc)>>2) + (c & 0x33);
c = ((c & 0xf0)>>4) + (c & 0x0f);
return ((vendor & 3) + c) == 5;
}
#endif
#ifndef RDA_CRYPTO_DEBUG_FAKE_ROMCERT
int get_chip_security_context(
struct chip_security_context *context,
struct pubkey *pubkey)
{
int ret = romapi->get_chip_security_context(context, pubkey);
#ifdef RDA8810_VENDOR_EFUSE_WORKAROUND
if (ret == ROM_API_INVALID_VENDOR_ID && romapi->version == 100) {
uint16_t sec = rda_read_efuse(RDA_EFUSE_INDEX_SECURITY);
// check validity of key index
int key = keyindex_map[RDA_SE_CFG_GET_KEY_INDEX(sec)];
// check validity of vendor id
int vendor = RDA_SE_CFG_GET_VENDOR_ID(sec);
if (valid_vendor_id(vendor)) {
context->rda_key_index = key;
context->vendor_id = vendor;
ret = 0;
}
}
#endif
return ret;
}
#endif

View File

@ -0,0 +1,507 @@
#include <common.h>
#include <asm/arch/hardware.h>
#include <asm/io.h>
#include <asm/arch/reg_sysctrl.h>
#include <asm/arch/reg_md_sysctrl.h>
#include <asm/arch/reg_cfg_regs.h>
#include <asm/arch/reg_keypad.h>
#include <asm/arch/reg_gpio.h>
#include <asm/arch/hwcfg.h>
#include <asm/arch/ispi.h>
#include <asm/arch/reg_md_sysctrl.h>
#include <asm/arch/hwcfg.h>
#include <asm/arch/rda_sys.h>
#include <asm/arch/spl_board_info.h>
#ifdef CONFIG_CMD_MISC
#include <usb/usbserial.h>
#include <asm/arch/mdcom.h>
#endif
#define RDA_AP_MBX_HWCFG_SWCFG_ADD (RDA_MD_MAILBOX_BASE + 0x1AE0)
#define RDA_HWCFG_SWCFG (*(u32 *)RDA_AP_MBX_HWCFG_SWCFG_ADD)
/*
* Hardware and software configuration
*/
void hwcfg_swcfg_init(void)
{
u16 hwcfg, swcfg;
RDA_HWCFG_SWCFG = hwp_sysCtrlMd->Reset_Cause;
hwcfg = rda_hwcfg_reg_get();
swcfg = rda_swcfg_reg_get();
/* clear the sw boot modes handled by bootloader */
rda_swcfg_reg_set(swcfg & ~(RDA_SW_CFG_BIT_2 |
RDA_SW_CFG_BIT_3 |
RDA_SW_CFG_BIT_4 |
RDA_SW_CFG_BIT_5 |
RDA_SW_CFG_BIT_6));
/* clear the hw boot modes for download/factory modes */
rda_hwcfg_reg_set(hwcfg & ~(RDA_HW_CFG_BIT_10 |
RDA_HW_CFG_BIT_11 |
RDA_HW_CFG_BIT_12 |
RDA_HW_CFG_BIT_13 |
RDA_HW_CFG_BIT_14 |
RDA_HW_CFG_BIT_15));
}
void rda_hwcfg_reg_set(u16 hwcfg)
{
hwp_sysCtrlMd->Reset_Cause = SET_BITFIELD(hwp_sysCtrlMd->Reset_Cause,
SYS_CTRL_BOOT_MODE, hwcfg);
hwp_sysCtrlAp->Reset_Cause = hwp_sysCtrlMd->Reset_Cause;
}
u16 rda_hwcfg_reg_get(void)
{
u16 hwcfg = GET_BITFIELD(hwp_sysCtrlMd->Reset_Cause, SYS_CTRL_BOOT_MODE);
return hwcfg;
}
u16 rda_hwcfg_get(void)
{
u16 hwcfg = GET_BITFIELD(RDA_HWCFG_SWCFG, SYS_CTRL_BOOT_MODE);
return hwcfg;
}
void rda_swcfg_reg_set(u16 swcfg)
{
hwp_sysCtrlMd->Reset_Cause = SET_BITFIELD(hwp_sysCtrlMd->Reset_Cause,
SYS_CTRL_SW_BOOT_MODE, swcfg);
hwp_sysCtrlAp->Reset_Cause = hwp_sysCtrlMd->Reset_Cause;
}
u16 rda_swcfg_reg_get(void)
{
u16 swcfg = GET_BITFIELD(hwp_sysCtrlMd->Reset_Cause, SYS_CTRL_SW_BOOT_MODE);
return swcfg;
}
u16 rda_swcfg_get(void)
{
u16 swcfg = GET_BITFIELD(RDA_HWCFG_SWCFG, SYS_CTRL_SW_BOOT_MODE);
return swcfg;
}
u16 rda_prod_id_get(void)
{
u16 prod_id = GET_BITFIELD(hwp_configRegs->CHIP_ID, CFG_REGS_PROD_ID);
return prod_id;
}
u16 rda_metal_id_get(void)
{
u16 metal_id = GET_BITFIELD(hwp_configRegs->CHIP_ID, CFG_REGS_METAL_ID);
return metal_id;
}
u16 rda_bond_id_get(void)
{
u16 bond_id = GET_BITFIELD(hwp_configRegs->CHIP_ID, CFG_REGS_BOND_ID);
return bond_id;
}
void rda_nand_iodrive_set(void)
{
u32 value = hwp_configRegs->IO_Drive1_Select & (~ CFG_REGS_NFLSH_DRIVE_MASK);
hwp_configRegs->IO_Drive1_Select = value | CFG_REGS_NFLSH_DRIVE_SLOW_AND_WEAK;
}
/*
* System-level control
*/
enum media_type rda_media_get(void)
{
#ifdef CONFIG_SDMMC_BOOT
return MEDIA_MMC;
#else
u16 hwcfg = rda_hwcfg_get();
#ifdef CONFIG_MACH_RDA8810H
/*
* HW BOOT MODE
*
* BIT_2 BIT1 BIT0 MODE
* 0 0 0 emmc
* 0 0 1 spi nand
* 0 1 0 spi nor
* 0 1 1 t-card0(run)
* 1 0 0 t-card1(update)
* 1 0 1 nand 8bit
* 1 1 0 nand 16bit
* 1 1 1 reserved
*/
u32 bm_media = RDA_HW_CFG_GET_BM_IDX(hwcfg);
if (bm_media == RDA_MODE_EMMC)
return MEDIA_MMC;
else if (bm_media == RDA_MODE_SPINAND)
return MEDIA_SPINAND;
else if ((bm_media == RDA_MODE_NAND_8BIT)
|| (bm_media == RDA_MODE_NAND_16BIT))
return MEDIA_NAND;
#else
u16 metal_id = rda_metal_id_get();
u16 prod_id = rda_prod_id_get();
u16 metal_new_bm;
if (prod_id == 0x8810)
metal_new_bm = 0xB;
else if (prod_id == 0x810E || prod_id == 0x8850 || prod_id == 0x850E)
metal_new_bm = 0x2;
else
metal_new_bm = 0;
if (metal_id < metal_new_bm) {
/* SDMMC or SPI NAND */
if (hwcfg & RDA_HW_CFG_BIT_3) {
if (hwcfg & RDA_HW_CFG_BIT_7)
return MEDIA_MMC;
else
return MEDIA_NAND;
} else if (hwcfg & RDA_HW_CFG_BIT_4) {
return MEDIA_MMC;
}
/* EMMC */
if (hwcfg & RDA_HW_CFG_BIT_2)
return MEDIA_MMC;
/* PARALLEL NAND */
if (!(hwcfg & RDA_HW_CFG_BIT_4))
return MEDIA_NAND;
} else {
/* SPI NAND */
if (hwcfg & RDA_HW_CFG_BIT_3)
return MEDIA_NAND;
/* EMMC */
if (hwcfg & RDA_HW_CFG_BIT_2)
return MEDIA_MMC;
/* PARALLEL NAND */
if (!(hwcfg & RDA_HW_CFG_BIT_4))
return MEDIA_NAND;
}
#endif
#endif
return MEDIA_UNKNOWN;
}
void reset_cpu(ulong addr)
{
#ifdef CONFIG_RDA_PDL
enable_charger(1);
#endif
while (1) {
/* to unlock first */
hwp_sysCtrlMd->REG_DBG = 0xa50001;
/* reset */
hwp_sysCtrlMd->Sys_Rst_Set |= SYS_CTRL_SOFT_RST;
}
}
void shutdown_system(void)
{
#ifdef CONFIG_RDA_PDL
enable_charger(1);
#endif
while (1) {
/* to unlock first */
hwp_sysCtrlMd->REG_DBG = 0xa50001;
/* shutdown */
hwp_sysCtrlMd->WakeUp = 0;
}
}
int rda_bm_is_calib(void)
{
u16 swcfg = rda_swcfg_get();
return !!(swcfg & RDA_SW_CFG_BIT_4);
}
int rda_bm_is_autocall(void)
{
u16 swcfg = rda_swcfg_get();
return !!(swcfg & RDA_SW_CFG_BIT_5);
}
int rda_bm_is_download(void)
{
#ifdef CONFIG_RDA_PDL /* for PDL mode, always enable download mode */
return 1;
#else
u16 hwcfg = rda_hwcfg_get();
return !!(hwcfg & RDA_HW_CFG_BIT_11);
#endif
}
/* Check if download keys are pressed. */
int rda_bm_download_key_pressed(void)
{
int key_power = !!(hwp_apKeypad->KP_STATUS & KEYPAD_KP_ON);
int key_vol_up = !!(hwp_apGpioD->gpio_val & 0x40); /* GPIO D6 */
#ifdef CONFIG_SDMMC_BOOT
int key_vol_down = !!(hwp_apGpioD->gpio_val & 0x20); /* GPIO D5 */
return (key_power && key_vol_up && !key_vol_down);
#else
return (key_power && key_vol_up);
#endif
}
void rda_reboot(enum reboot_type type)
{
u16 hwcfg = rda_hwcfg_reg_get();
u16 swcfg = rda_swcfg_reg_get();
int key_vol_down;
hwcfg &= ~(RDA_HW_CFG_BIT_10 | RDA_HW_CFG_BIT_11 |
RDA_HW_CFG_BIT_12 | RDA_HW_CFG_BIT_13 |
RDA_HW_CFG_BIT_14 | RDA_HW_CFG_BIT_15);
switch (type) {
case REBOOT_TO_DOWNLOAD_MODE:
hwcfg |= RDA_HW_CFG_BIT_11 | RDA_HW_CFG_BIT_12 |
RDA_HW_CFG_BIT_14;
key_vol_down = !!(hwp_apGpioD->gpio_val & 0x20); /* GPIO D5 */
if (key_vol_down)
hwcfg |= RDA_HW_CFG_BIT_10 | RDA_HW_CFG_BIT_13;
break;
case REBOOT_TO_FASTBOOT_MODE:
swcfg |= RDA_SW_CFG_BIT_2;
break;
case REBOOT_TO_RECOVERY_MODE:
swcfg |= RDA_SW_CFG_BIT_3;
break;
case REBOOT_TO_CALIB_MODE:
swcfg |= RDA_SW_CFG_BIT_4;
break;
case REBOOT_TO_PDL2_MODE:
swcfg |= RDA_SW_CFG_BIT_6;
break;
default:
break;
}
rda_hwcfg_reg_set(hwcfg);
rda_swcfg_reg_set(swcfg);
reset_cpu(0);
}
void enable_vibrator(int enable)
{
u32 value;
ispi_open(1);
value = ispi_reg_read(0x03);
if (enable)
value |= 0x20;
else
value &= ~0x20;
if (rda_metal_id_get() >= 9)
value ^= 0x20;
ispi_reg_write(0x03, value);
ispi_open(0);
}
void enable_charger(int enable)
{
u32 val;
ispi_open(1);
val = ispi_reg_read(0x15);
if (enable) {
val &= ~((1 << 15) | (1 << 14));
} else {
val |= (1 << 15);
val &= ~(1 << 14);
}
ispi_reg_write(0x15, val);
ispi_open(0);
}
void rda_dump_buf(char *data, size_t len)
{
char temp_buf[64];
size_t i, off = 0;
memset(temp_buf, 0, 64);
for (i=0;i<len;i++) {
if(i%8 == 0) {
sprintf(&temp_buf[off], " ");
off += 2;
}
sprintf(&temp_buf[off], "%02x ", data[i]);
off += 3;
if((i+1)%16 == 0 || (i+1) == len) {
printf("%8d %s\n", (unsigned int)i/16,temp_buf);
memset(temp_buf, 0, 64);
off = 0;
}
}
printf("\n");
}
void print_cur_time(void)
{
unsigned long long time = ticks2usec(get_ticks());
printf("\n****** [CURRENT TIME: %3d.%06d] ******\n\n",
(int)(time / 1000000),
(int)(time % 1000000));
}
#ifdef CONFIG_CMD_MISC
int usb_cable_connected(void)
{
u32 val;
ispi_open(1);
val = ispi_reg_read(0x14);
ispi_open(0);
if (val & (1 << 8))
return 1;
else
return 0;
}
int system_rebooted(void)
{
static int system_rebooted_flag = -1;
if (system_rebooted_flag == -1) {
if (rda_mdcom_system_started_before())
system_rebooted_flag = 1;
else
system_rebooted_flag = 0;
rda_mdcom_set_system_started_flag();
}
return system_rebooted_flag;
}
static int boot_key_long_pressed = 0;
void save_current_boot_key_state(void)
{
int boot_key_on = ((hwp_apKeypad->KP_STATUS & KEYPAD_KP_ON) != 0);
int start_by_boot_key = ((rda_hwcfg_get() & RDA_HW_CFG_BIT_12) != 0);
boot_key_long_pressed = (boot_key_on && start_by_boot_key);
}
int get_saved_boot_key_state(void)
{
return boot_key_long_pressed;
}
void get_board_serial(struct tag_serialnr *serialnr)
{
struct spl_security_info *info = get_bd_spl_security_info();
const uint32_t *id256 = (uint32_t *)info->chip_unique_id.id;
serialnr->low = id256[0];
serialnr->high = id256[1];
if ((serialnr->low | serialnr->high) == 0) {
serialnr->low = 0x90abcdef;
serialnr->high = 0x12345678;
}
/* Set serialno enviroment variable */
char tmp[32];
sprintf(tmp, "%08x%08x", serialnr->high, serialnr->low);
setenv("serialno", tmp);
}
static int boot_mode = RDA_BM_NORMAL;
void rda_bm_init(void)
{
u16 hwcfg = rda_hwcfg_get();
u16 swcfg = rda_swcfg_get();
#ifndef CONFIG_RDA_PDL
int rebooted = system_rebooted();
u32 fastboot_key_mask, all_key_mask;
#endif
char str[2];
struct tag_serialnr serialnr;
get_board_serial(&serialnr);
printf("RDA: HW_CFG 0x%04x\n", hwcfg);
printf("RDA: SW_CFG 0x%04x\n", swcfg);
printf("RDA: ID PROD %04x M %03x B %01x\n",
rda_prod_id_get(), rda_metal_id_get(),
rda_bond_id_get());
#ifdef CONFIG_RDA_PDL
/* PDL: always enable download mode */
boot_mode = RDA_BM_FORCEDOWNLOAD;
#else
/* SPL */
boot_mode = RDA_BM_NORMAL;
if (swcfg & RDA_SW_CFG_BIT_2) {
boot_mode = RDA_BM_FASTBOOT;
} else if (swcfg & RDA_SW_CFG_BIT_3) {
boot_mode = RDA_BM_RECOVERY;
} else if (swcfg & RDA_SW_CFG_BIT_4) {
boot_mode = RDA_BM_CALIB;
} else if (swcfg & RDA_SW_CFG_BIT_5) {
boot_mode = RDA_BM_AUTOCALL;
} else if (swcfg & RDA_SW_CFG_BIT_6) {
/* force to 'pdl2', called by kernel */
boot_mode = RDA_BM_FORCEDOWNLOAD;
} else if ((hwcfg & RDA_HW_CFG_BIT_10) && (hwcfg & RDA_HW_CFG_BIT_11)) {
/*
* If power key, vol-up, and vol-down are all pressed, consider
* it as normal boot (for T-Card)
*/
boot_mode = RDA_BM_NORMAL;
} else if ((hwcfg & RDA_HW_CFG_BIT_10) && !rebooted) {
/* Distinguish between factory mode and h/w force reset */
boot_mode = RDA_BM_FACTORY;
} else if (hwcfg & RDA_HW_CFG_BIT_11) {
/* Force download mode for pdl2 */
boot_mode = RDA_BM_FORCEDOWNLOAD;
} else if (usb_cable_connected()) {
all_key_mask = RDA_HW_CFG_BIT_15 | RDA_HW_CFG_BIT_14 |
RDA_HW_CFG_BIT_13 | RDA_HW_CFG_BIT_12 |
RDA_HW_CFG_BIT_11 | RDA_HW_CFG_BIT_10;
/* Fastboot keys are volume-up + volume-down keys */
fastboot_key_mask = RDA_HW_CFG_BIT_13 | RDA_HW_CFG_BIT_14;
if ((hwcfg & fastboot_key_mask) == fastboot_key_mask &&
(hwcfg & all_key_mask & ~fastboot_key_mask) == 0) {
/*
* All the keys are up, except for the fastboot keys;
* and the usb cable is plugged in
*/
boot_mode = RDA_BM_FASTBOOT;
}
}
#endif /* !CONFIG_RDA_PDL */
printf("RDA: Boot_Mode %d\n", boot_mode);
sprintf(str, "%1d", boot_mode);
setenv ("bootmode", str);
}
enum rda_bm_type rda_bm_get(void)
{
return boot_mode;
}
void rda_bm_set(enum rda_bm_type bm)
{
boot_mode = bm;
}
#endif /* CONFIG_CMD_MISC */

View File

@ -0,0 +1,132 @@
#include <common.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/rda_iomap.h>
#include <asm/arch/reg_sysctrl.h>
#include <asm/arch/reg_uart.h>
DECLARE_GLOBAL_DATA_PTR;
void _serial_set_baudrate(int rate)
{
hwp_sysCtrlAp->Cfg_Clk_Uart[2] = 0x36; // 115200 @ 26MHz
//hwp_sysCtrlAp->Cfg_Clk_Uart[2] = 0x05; // 921600 @ 26MHz
}
void _serial_enable_rtscts(void)
{
hwp_uart->ctrl |= UART_AUTO_FLOW_CONTROL;
}
void _serial_disable_rtscts(void)
{
hwp_uart->ctrl &= ~UART_AUTO_FLOW_CONTROL;
}
void _serial_init(void)
{
_serial_set_baudrate(CONFIG_BAUDRATE);
hwp_uart->triggers = UART_AFC_LEVEL(1); //7 ?
hwp_uart->ctrl = UART_ENABLE | UART_DATA_BITS_8_BITS |
UART_TX_STOP_BITS_1_BIT | UART_PARITY_ENABLE_NO;
/* Allow reception */
hwp_uart->CMD_Set = UART_RTS;
}
void _serial_deinit(void)
{
hwp_uart->ctrl = 0;
hwp_uart->CMD_Clr = UART_RTS;
}
/*
* Test whether a character is in the RX buffer
*/
int _serial_tstc(const int port)
{
return (GET_BITFIELD(hwp_uart->status, UART_RX_FIFO_LEVEL));
}
int _serial_getc(const int port)
{
/* wait for character to arrive */ ;
while (!(GET_BITFIELD(hwp_uart->status, UART_RX_FIFO_LEVEL)))
;
return (hwp_uart->rxtx_buffer & 0xff);
}
void _serial_putc_hw(const char c, const int port)
{
// Place in the TX Fifo ?
while (!(GET_BITFIELD(hwp_uart->status, UART_TX_FIFO_SPACE)))
;
hwp_uart->rxtx_buffer = (u32)c;
}
void _serial_putc(const char c, const int port)
{
if (c == '\n') {
_serial_putc_hw('\r', 0);
}
_serial_putc_hw(c, 0);
}
void _serial_puts(const char *s, const int port)
{
while (*s) {
_serial_putc(*s++, 0);
}
}
static int hwflow = 0; /* turned off by default */
int hwflow_onoff(int on)
{
switch(on) {
case 0:
default:
break; /* return current */
case 1:
hwflow = 1;
_serial_enable_rtscts(); /* turn on */
break;
case -1:
hwflow = 0;
_serial_disable_rtscts(); /* turn off */
break;
}
return hwflow;
}
int serial_init(void)
{
//_serial_init(); // already init in boot_test
return 0;
}
int serial_getc(void)
{
return _serial_getc(0);
}
int serial_tstc(void)
{
return _serial_tstc(0);
}
void serial_putc(const char c)
{
_serial_putc(c, 0);
}
void serial_puts(const char *s)
{
_serial_puts(s, 0);
}
void serial_setbrg (void)
{
}

View File

@ -0,0 +1,189 @@
#include <common.h>
#include <asm/u-boot.h>
#include <asm/utils.h>
#include <nand.h>
#include <malloc.h>
#include <image.h>
#include <usb/usbserial.h>
#include <asm/arch/rda_sys.h>
#include <asm/arch/spl_board_info.h>
#include <asm/arch/rda_crypto.h>
#include <pdl.h>
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
DECLARE_GLOBAL_DATA_PTR;
/* Define global data structure pointer to it*/
static gd_t gdata __attribute__ ((section(".data")));
static bd_t bdata __attribute__ ((section(".data")));
#else
void puts(const char *str)
{
while (*str)
putc(*str++);
}
void putc(char c)
{
}
#endif /* CONFIG_SPL_LIBCOMMON_SUPPORT */
void board_init_f(ulong dummy)
{
relocate_code(CONFIG_SPL_STACK, NULL, CONFIG_SPL_TEXT_BASE);
}
#ifdef CONFIG_SPL_CHECK_IMAGE
int check_uimage(unsigned int *buf)
{
image_header_t *hdr = (image_header_t *)buf;
puts("Check Image ");
if (!image_check_magic(hdr)) {
printf("Magic Error %x\n", image_get_magic(hdr));
rda_dump_buf((char *)buf, 256);
return -1;
}
puts(".");
if (!image_check_hcrc(hdr)) {
printf("HCRC Error %x\n", image_get_hcrc(hdr));
rda_dump_buf((char *)buf, 256);
return -2;
}
puts(".");
if (!image_check_dcrc(hdr)) {
printf("DCRC Error %x\n", image_get_dcrc(hdr));
rda_dump_buf((char *)buf, 256);
//rda_dump_buf(buf,
// image_get_header_size() + image_get_size(hdr));
return -3;
}
puts(".");
#ifdef CONFIG_SIGNATURE_CHECK_IMAGE
if (image_sign_verify_uimage(hdr) != 0) {
printf("Image Signature check failed!\n");
return -4;
}
#endif
puts(" Done\n");
return 0;
}
#endif
#ifdef CONFIG_SPL_EMMC_LOAD
extern void emmc_init(void);
extern void emmc_boot(void);
#endif
#ifdef CONFIG_SPL_XMODEM_LOAD
extern void xmodem_boot(void);
#endif
extern void hwcfg_swcfg_init(void);
extern int clock_init(void);
#ifdef CONFIG_SIGNATURE_CHECK_IMAGE
static const uint8_t *get_spl_load_addr(void)
{
const uint8_t *spl_image = (uint8_t*)CONFIG_SPL_LOAD_ADDRESS + CONFIG_UIMAGEHDR_SIZE;
return spl_image;
}
#endif
void board_init_r(gd_t *id, ulong dummy)
{
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
gd = &gdata;
gd->bd = &bdata;
gd->flags |= GD_FLG_RELOC;
gd->baudrate = CONFIG_BAUDRATE;
serial_init(); /* serial communications setup */
gd->have_console = 1;
#endif
hwcfg_swcfg_init();
clock_init();
#ifdef CONFIG_SIGNATURE_CHECK_IMAGE
// Set the security contex (or get the unique ID of the device)
struct spl_security_info *info = get_bd_spl_security_info();
const uint8_t *spl_image = get_spl_load_addr();
puts("SETTING SECURITY CONTEXT\n");
set_security_context(info, spl_image);
#endif
#ifndef CONFIG_RDA_PDL
/* Note BIT3 for SPINAND got higher priority */
#ifdef CONFIG_SPL_EMMC_SUPPORT
if (rda_media_get() == MEDIA_MMC) {
puts("Init emmc ...\n");
emmc_init();
}
#endif
#ifdef CONFIG_SPL_NAND_SUPPORT
if (rda_media_get() == MEDIA_NAND || rda_media_get() == MEDIA_SPINAND) {
puts("Init nand ...\n");
nand_init();
}
#endif
#endif
#ifdef CONFIG_RDA_PDL
drv_usbser_init();
pdl_main();
#else
/* A workaround to handle the timing issue when detecting
* download mode in h/w */
if( !rda_bm_is_autocall() &&
!rda_bm_is_calib() &&
!rda_bm_is_download() &&
rda_bm_download_key_pressed()) {
puts("Download key pressed. Enter download mode ...\n");
rda_reboot(REBOOT_TO_DOWNLOAD_MODE);
}
#endif
#ifdef CONFIG_SPL_EMMC_LOAD
if (rda_media_get() == MEDIA_MMC) {
puts("EMMC boot ...\n");
emmc_boot();
}
#endif
#ifdef CONFIG_SPL_NAND_LOAD
if (rda_media_get() == MEDIA_NAND || rda_media_get() == MEDIA_SPINAND) {
puts("NAND boot ...\n");
nand_boot();
}
#endif
#ifdef CONFIG_SPL_SPI_LOAD
mem_malloc_init(CONFIG_SYS_TEXT_BASE - CONFIG_SYS_MALLOC_LEN,
CONFIG_SYS_MALLOC_LEN);
gd = &gdata;
gd->bd = &bdata;
gd->flags |= GD_FLG_RELOC;
gd->baudrate = CONFIG_BAUDRATE;
serial_init(); /* serial communications setup */
gd->have_console = 1;
puts("SPI boot...\n");
spi_boot();
#endif
#ifdef CONFIG_SPL_XMODEM_LOAD
puts("Xmodem boot ...\n");
xmodem_boot();
#endif
/*
should never go here
*/
while(1)
;
}

View File

@ -0,0 +1,132 @@
#include <common.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/rda_iomap.h>
#include <asm/arch/reg_timer.h>
DECLARE_GLOBAL_DATA_PTR;
typedef union
{
unsigned long long timer;
struct
{
unsigned long timer_l :32;
unsigned long timer_h :32;
} fields;
} RDA_TIMER;
#if (CONFIG_SYS_HZ_CLOCK == 2000000)
/* optimize for 2M Hz */
static unsigned long tick_to_ms(unsigned long long tick) __attribute__((unused));
static unsigned long tick_to_ms(unsigned long long tick)
{
return (u32)(tick >> 11); // divide 2048
}
static unsigned long long ms_to_tick(unsigned long ms)
{
return (((unsigned long long)ms) << 11); // x 2048
}
static unsigned long tick_to_us(unsigned long long tick)
{
return (unsigned long)(tick >> 1); // divide 2
}
static unsigned long long us_to_tick(unsigned long ms)
{
return (((unsigned long long)ms) << 1); // x2
}
#else
/* need to calc */
#error "Timer is not 2M Hz"
#endif
static void rda_timer_get(RDA_TIMER *timer)
{
/* always read low 32bit first */
timer->fields.timer_l =
(unsigned long)(hwp_apTimer->HWTimer_LockVal_L);
timer->fields.timer_h =
(unsigned long)(hwp_apTimer->HWTimer_LockVal_H);
}
static void rda_timeout_setup_ms(RDA_TIMER *timer, unsigned long ms)
__attribute__((unused));
static void rda_timeout_setup_ms(RDA_TIMER *timer, unsigned long ms)
{
timer->timer = get_ticks() + ms_to_tick(ms);
}
static void rda_timeout_setup_us(RDA_TIMER *timer, unsigned long us)
{
timer->timer = get_ticks() + us_to_tick(us);
}
static int rda_timeout_check(RDA_TIMER *timer)
{
return (get_ticks() > timer->timer);
}
int timer_init(void)
{
gd->timer_rate_hz = CONFIG_SYS_HZ_CLOCK;
gd->timer_reset_value = 0;
/* We are using timer34 in unchained 32-bit mode, full speed */
return(0);
}
void reset_timer(void)
{
gd->timer_reset_value = get_ticks();
}
/*
* Get the current 64 bit timer tick count
*/
unsigned long long get_ticks(void)
{
RDA_TIMER timer;
rda_timer_get(&timer);
return timer.timer;
}
ulong usec2ticks (unsigned long usec)
{
return (ulong)us_to_tick(usec);
}
ulong ticks2usec (unsigned long ticks)
{
return tick_to_us(ticks);
}
ulong get_timer(ulong base)
{
unsigned long long timer_diff;
timer_diff = get_ticks() - gd->timer_reset_value;
return (timer_diff / (gd->timer_rate_hz / CONFIG_SYS_HZ)) - base;
}
void __udelay(unsigned long usec)
{
RDA_TIMER timer;
rda_timeout_setup_us(&timer, usec);
while(!rda_timeout_check(&timer))
;
}
/*
* This function is derived from PowerPC code (timebase clock frequency).
* On ARM it returns the number of timer ticks per second.
*/
ulong get_tbclk(void)
{
return CONFIG_SYS_HZ_CLOCK;
}

View File

@ -0,0 +1,75 @@
#include <common.h>
#include <asm/io.h>
#include <asm/u-boot.h>
#include <asm/utils.h>
#include <xyzModem.h>
void _serial_enable_rtscts(void);
#ifdef CONFIG_SPL_CHECK_IMAGE
int check_uimage(unsigned int *buf);
#endif
static int getcxmodem(void) {
if (tstc())
return (getc());
return -1;
}
static ulong load_serial_xmodem (ulong offset)
{
int size;
int err;
int res;
connection_info_t info;
char ymodemBuf[1024];
ulong store_addr = ~0;
ulong addr = 0;
size = 0;
info.mode = xyzModem_xmodem;
_serial_enable_rtscts();
mdelay(10);
res = xyzModem_stream_open (&info, &err);
if (!res) {
while ((res =
xyzModem_stream_read (ymodemBuf, 1024, &err)) > 0) {
store_addr = addr + offset;
size += res;
addr += res;
memcpy ((char *) (store_addr), ymodemBuf,res);
}
} else {
printf ("%s\n", xyzModem_error (err));
}
xyzModem_stream_close (&err);
xyzModem_stream_terminate (false, &getcxmodem);
flush_cache (offset, size);
printf("\nXmodem Download Success.\n");
printf("Total Size = 0x%08x = %d Bytes\n", size, size);
return offset;
}
void xmodem_boot(void)
{
__attribute__((noreturn)) void (*uboot)(void);
load_serial_xmodem(CONFIG_SYS_XMODEM_U_BOOT_DST);
#ifdef CONFIG_SPL_CHECK_IMAGE
if (check_uimage((unsigned int*)CONFIG_SYS_XMODEM_U_BOOT_DST)) {
printf("Xmodem boot failed.\n");
return;
}
#endif
/*
* Jump to U-Boot image
*/
printf("Running U-Boot ...\n");
uboot = (void *)CONFIG_SYS_XMODEM_U_BOOT_START;
(*uboot)();
}

View File

@ -25,20 +25,22 @@
.align 5
#include <linux/linkage.h>
#ifndef CONFIG_SYS_L2CACHE_OFF
.global v7_outer_cache_enable
v7_outer_cache_enable:
ENTRY(v7_outer_cache_enable)
push {r0, r1, r2, lr}
mrc 15, 0, r3, cr1, cr0, 1
orr r3, r3, #2
mcr 15, 0, r3, cr1, cr0, 1
pop {r1, r2, r3, pc}
ENDPROC(v7_outer_cache_enable)
.global v7_outer_cache_disable
v7_outer_cache_disable:
ENTRY(v7_outer_cache_disable)
push {r0, r1, r2, lr}
mrc 15, 0, r3, cr1, cr0, 1
bic r3, r3, #2
mcr 15, 0, r3, cr1, cr0, 1
pop {r1, r2, r3, pc}
ENDPROC(v7_outer_cache_disable)
#endif

View File

@ -22,12 +22,12 @@
*/
#include <asm/arch/cpu.h>
#include <linux/linkage.h>
#define S5PC100_SWRESET 0xE0200000
#define S5PC110_SWRESET 0xE0102000
.globl reset_cpu
reset_cpu:
ENTRY(reset_cpu)
ldr r1, =S5PC100_PRO_ID
ldr r2, [r1]
ldr r4, =0x00010000
@ -45,3 +45,4 @@ reset_cpu:
str r2, [r1]
_loop_forever:
b _loop_forever
ENDPROC(reset_cpu)

View File

@ -31,8 +31,8 @@
#include <asm-offsets.h>
#include <config.h>
#include <version.h>
#include <asm/system.h>
#include <linux/linkage.h>
.globl _start
_start: b reset
@ -158,7 +158,11 @@ reset:
/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
#ifdef CONFIG_SPL_BUILD
ldr sp, =(CONFIG_SPL_STACK)
#else
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
bl board_init_f
@ -172,8 +176,7 @@ call_board_init_f:
* after relocating the monitor code.
*
*/
.globl relocate_code
relocate_code:
ENTRY(relocate_code)
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
@ -257,12 +260,17 @@ clear_bss:
add r0, r0, r4
add r1, r1, r4
#endif
cmp r0, r1
beq clbss_d
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
clbss_d:
/*
* We are done. Do not return, instead branch to second part of board
@ -289,6 +297,7 @@ jump_2_ram:
_board_init_r_ofs:
.word board_init_r - _start
ENDPROC(relocate_code)
/*************************************************************************
*
@ -298,8 +307,7 @@ _board_init_r_ofs:
* CONFIG_SYS_ICACHE_OFF is defined.
*
*************************************************************************/
.globl cpu_init_cp15
cpu_init_cp15:
ENTRY(cpu_init_cp15)
/*
* Invalidate L1 I/D
*/
@ -325,7 +333,7 @@ cpu_init_cp15:
#endif
mcr p15, 0, r0, c1, c0, 0
mov pc, lr @ back to my caller
ENDPROC(cpu_init_cp15)
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
/*************************************************************************
@ -336,7 +344,7 @@ cpu_init_cp15:
* setup memory timing
*
*************************************************************************/
cpu_init_crit:
ENTRY(cpu_init_crit)
/*
* Jump to board specific initialization...
* The Mask ROM will have already initialized
@ -347,6 +355,7 @@ cpu_init_crit:
bl lowlevel_init @ go setup pll,mux,memory
mov lr, ip @ restore link
mov pc, lr @ back to my caller
ENDPROC(cpu_init_crit)
#endif
#ifndef CONFIG_SPL_BUILD

View File

@ -27,6 +27,7 @@
# flags for any startup files it might use.
CFLAGS_arch/arm/cpu/armv7/tegra2/ap20.o += -march=armv4t
CFLAGS_arch/arm/cpu/armv7/tegra2/clock.o += -march=armv4t
CFLAGS_arch/arm/cpu/armv7/tegra2/warmboot_avp.o += -march=armv4t
include $(TOPDIR)/config.mk
@ -34,7 +35,10 @@ LIB = $(obj)lib$(SOC).o
SOBJS := lowlevel_init.o
COBJS-y := ap20.o board.o clock.o funcmux.o pinmux.o sys_info.o timer.o
COBJS-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o
COBJS-$(CONFIG_TEGRA_PMU) += pmu.o
COBJS-$(CONFIG_USB_EHCI_TEGRA) += usb.o
COBJS-$(CONFIG_TEGRA2_LP0) += crypto.o warmboot.o warmboot_avp.o
COBJS := $(COBJS-y)
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)

View File

@ -21,16 +21,53 @@
* MA 02111-1307 USA
*/
#include "ap20.h"
#include <asm/io.h>
#include <asm/arch/tegra2.h>
#include <asm/arch/ap20.h>
#include <asm/arch/clk_rst.h>
#include <asm/arch/clock.h>
#include <asm/arch/fuse.h>
#include <asm/arch/gp_padctrl.h>
#include <asm/arch/pmc.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/scu.h>
#include <asm/arch/warmboot.h>
#include <common.h>
int tegra_get_chip_type(void)
{
struct apb_misc_gp_ctlr *gp;
struct fuse_regs *fuse = (struct fuse_regs *)TEGRA2_FUSE_BASE;
uint tegra_sku_id, rev;
/*
* This is undocumented, Chip ID is bits 15:8 of the register
* APB_MISC + 0x804, and has value 0x20 for Tegra20, 0x30 for
* Tegra30
*/
gp = (struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE;
rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT;
tegra_sku_id = readl(&fuse->sku_info) & 0xff;
switch (rev) {
case CHIPID_TEGRA2:
switch (tegra_sku_id) {
case SKU_ID_T20:
return TEGRA_SOC_T20;
case SKU_ID_T25SE:
case SKU_ID_AP25:
case SKU_ID_T25:
case SKU_ID_AP25E:
case SKU_ID_T25E:
return TEGRA_SOC_T25;
}
break;
}
/* unknown sku id */
return TEGRA_SOC_UNKNOWN;
}
/* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */
static int ap20_cpu_is_cortexa9(void)
{
@ -286,6 +323,11 @@ void init_pmc_scratch(void)
/* ODMDATA is for kernel use to determine RAM size, LP config, etc. */
writel(CONFIG_SYS_BOARD_ODMDATA, &pmc->pmc_scratch20);
#ifdef CONFIG_TEGRA2_LP0
/* save Sdram params to PMC 2, 4, and 24 for WB0 */
warmboot_save_sdram_params();
#endif
}
void tegra2_start(void)

View File

@ -23,12 +23,12 @@
#include <common.h>
#include <asm/io.h>
#include "ap20.h"
#include <asm/arch/ap20.h>
#include <asm/arch/clock.h>
#include <asm/arch/funcmux.h>
#include <asm/arch/pmc.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/tegra2.h>
#include <asm/arch/pmc.h>
DECLARE_GLOBAL_DATA_PTR;

View File

@ -410,6 +410,16 @@ enum clock_osc_freq clock_get_osc_freq(void)
return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
}
int clock_get_osc_bypass(void)
{
struct clk_rst_ctlr *clkrst =
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
u32 reg;
reg = readl(&clkrst->crc_osc_ctrl);
return (reg & OSC_XOBP_MASK) >> OSC_XOBP_SHIFT;
}
/* Returns a pointer to the registers of the given pll */
static struct clk_pll *get_pll(enum clock_id clkid)
{
@ -420,6 +430,28 @@ static struct clk_pll *get_pll(enum clock_id clkid)
return &clkrst->crc_pll[clkid];
}
int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
u32 *divp, u32 *cpcon, u32 *lfcon)
{
struct clk_pll *pll = get_pll(clkid);
u32 data;
assert(clkid != CLOCK_ID_USB);
/* Safety check, adds to code size but is small */
if (!clock_id_isvalid(clkid) || clkid == CLOCK_ID_USB)
return -1;
data = readl(&pll->pll_base);
*divm = (data & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
*divn = (data & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT;
*divp = (data & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
data = readl(&pll->pll_misc);
*cpcon = (data & PLL_CPCON_MASK) >> PLL_CPCON_SHIFT;
*lfcon = (data & PLL_LFCON_MASK) >> PLL_LFCON_SHIFT;
return 0;
}
unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
u32 divp, u32 cpcon, u32 lfcon)
{
@ -1027,7 +1059,10 @@ void clock_early_init(void)
clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
break;
case CLOCK_OSC_FREQ_13_0:
case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
clock_set_rate(CLOCK_ID_PERIPH, 432, 13, 1, 8);
clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
break;
case CLOCK_OSC_FREQ_19_2:
default:
/*

View File

@ -0,0 +1,230 @@
/*
* Copyright (c) 2011 The Chromium OS Authors.
* (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <asm/errno.h>
#include "crypto.h"
#include "aes.h"
static u8 zero_key[16];
#define AES_CMAC_CONST_RB 0x87 /* from RFC 4493, Figure 2.2 */
enum security_op {
SECURITY_SIGN = 1 << 0, /* Sign the data */
SECURITY_ENCRYPT = 1 << 1, /* Encrypt the data */
};
static void debug_print_vector(char *name, u32 num_bytes, u8 *data)
{
u32 i;
debug("%s [%d] @0x%08x", name, num_bytes, (u32)data);
for (i = 0; i < num_bytes; i++) {
if (i % 16 == 0)
debug(" = ");
debug("%02x", data[i]);
if ((i+1) % 16 != 0)
debug(" ");
}
debug("\n");
}
/**
* Apply chain data to the destination using EOR
*
* Each array is of length AES_AES_KEY_LENGTH.
*
* \param cbc_chain_data Chain data
* \param src Source data
* \param dst Destination data, which is modified here
*/
static void apply_cbc_chain_data(u8 *cbc_chain_data, u8 *src, u8 *dst)
{
int i;
for (i = 0; i < 16; i++)
*dst++ = *src++ ^ *cbc_chain_data++;
}
/**
* Encrypt some data with AES.
*
* \param key_schedule Expanded key to use
* \param src Source data to encrypt
* \param dst Destination buffer
* \param num_aes_blocks Number of AES blocks to encrypt
*/
static void encrypt_object(u8 *key_schedule, u8 *src, u8 *dst,
u32 num_aes_blocks)
{
u8 tmp_data[AES_KEY_LENGTH];
u8 *cbc_chain_data;
u32 i;
cbc_chain_data = zero_key; /* Convenient array of 0's for IV */
for (i = 0; i < num_aes_blocks; i++) {
debug("encrypt_object: block %d of %d\n", i, num_aes_blocks);
debug_print_vector("AES Src", AES_KEY_LENGTH, src);
/* Apply the chain data */
apply_cbc_chain_data(cbc_chain_data, src, tmp_data);
debug_print_vector("AES Xor", AES_KEY_LENGTH, tmp_data);
/* encrypt the AES block */
aes_encrypt(tmp_data, key_schedule, dst);
debug_print_vector("AES Dst", AES_KEY_LENGTH, dst);
/* Update pointers for next loop. */
cbc_chain_data = dst;
src += AES_KEY_LENGTH;
dst += AES_KEY_LENGTH;
}
}
/**
* Shift a vector left by one bit
*
* \param in Input vector
* \param out Output vector
* \param size Length of vector in bytes
*/
static void left_shift_vector(u8 *in, u8 *out, int size)
{
int carry = 0;
int i;
for (i = size - 1; i >= 0; i--) {
out[i] = (in[i] << 1) | carry;
carry = in[i] >> 7; /* get most significant bit */
}
}
/**
* Sign a block of data, putting the result into dst.
*
* \param key Input AES key, length AES_KEY_LENGTH
* \param key_schedule Expanded key to use
* \param src Source data of length 'num_aes_blocks' blocks
* \param dst Destination buffer, length AES_KEY_LENGTH
* \param num_aes_blocks Number of AES blocks to encrypt
*/
static void sign_object(u8 *key, u8 *key_schedule, u8 *src, u8 *dst,
u32 num_aes_blocks)
{
u8 tmp_data[AES_KEY_LENGTH];
u8 left[AES_KEY_LENGTH];
u8 k1[AES_KEY_LENGTH];
u8 *cbc_chain_data;
unsigned i;
cbc_chain_data = zero_key; /* Convenient array of 0's for IV */
/* compute K1 constant needed by AES-CMAC calculation */
for (i = 0; i < AES_KEY_LENGTH; i++)
tmp_data[i] = 0;
encrypt_object(key_schedule, tmp_data, left, 1);
debug_print_vector("AES(key, nonce)", AES_KEY_LENGTH, left);
left_shift_vector(left, k1, sizeof(left));
debug_print_vector("L", AES_KEY_LENGTH, left);
if ((left[0] >> 7) != 0) /* get MSB of L */
k1[AES_KEY_LENGTH-1] ^= AES_CMAC_CONST_RB;
debug_print_vector("K1", AES_KEY_LENGTH, k1);
/* compute the AES-CMAC value */
for (i = 0; i < num_aes_blocks; i++) {
/* Apply the chain data */
apply_cbc_chain_data(cbc_chain_data, src, tmp_data);
/* for the final block, XOR K1 into the IV */
if (i == num_aes_blocks - 1)
apply_cbc_chain_data(tmp_data, k1, tmp_data);
/* encrypt the AES block */
aes_encrypt(tmp_data, key_schedule, dst);
debug("sign_obj: block %d of %d\n", i, num_aes_blocks);
debug_print_vector("AES-CMAC Src", AES_KEY_LENGTH, src);
debug_print_vector("AES-CMAC Xor", AES_KEY_LENGTH, tmp_data);
debug_print_vector("AES-CMAC Dst", AES_KEY_LENGTH, dst);
/* Update pointers for next loop. */
cbc_chain_data = dst;
src += AES_KEY_LENGTH;
}
debug_print_vector("AES-CMAC Hash", AES_KEY_LENGTH, dst);
}
/**
* Encrypt and sign a block of data (depending on security mode).
*
* \param key Input AES key, length AES_KEY_LENGTH
* \param oper Security operations mask to perform (enum security_op)
* \param src Source data
* \param length Size of source data
* \param sig_dst Destination address for signature, AES_KEY_LENGTH bytes
*/
static int encrypt_and_sign(u8 *key, enum security_op oper, u8 *src,
u32 length, u8 *sig_dst)
{
u32 num_aes_blocks;
u8 key_schedule[AES_EXPAND_KEY_LENGTH];
debug("encrypt_and_sign: length = %d\n", length);
debug_print_vector("AES key", AES_KEY_LENGTH, key);
/*
* The only need for a key is for signing/checksum purposes, so
* if not encrypting, expand a key of 0s.
*/
aes_expand_key(oper & SECURITY_ENCRYPT ? key : zero_key, key_schedule);
num_aes_blocks = (length + AES_KEY_LENGTH - 1) / AES_KEY_LENGTH;
if (oper & SECURITY_ENCRYPT) {
/* Perform this in place, resulting in src being encrypted. */
debug("encrypt_and_sign: begin encryption\n");
encrypt_object(key_schedule, src, src, num_aes_blocks);
debug("encrypt_and_sign: end encryption\n");
}
if (oper & SECURITY_SIGN) {
/* encrypt the data, overwriting the result in signature. */
debug("encrypt_and_sign: begin signing\n");
sign_object(key, key_schedule, src, sig_dst, num_aes_blocks);
debug("encrypt_and_sign: end signing\n");
}
return 0;
}
int sign_data_block(u8 *source, unsigned length, u8 *signature)
{
return encrypt_and_sign(zero_key, SECURITY_SIGN, source,
length, signature);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2011 The Chromium OS Authors.
* (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef _CRYPTO_H_
#define _CRYPTO_H_
/**
* Sign a block of data
*
* \param source Source data
* \param length Size of source data
* \param signature Destination address for signature, AES_KEY_LENGTH bytes
*/
int sign_data_block(u8 *source, unsigned length, u8 *signature);
#endif /* #ifndef _CRYPTO_H_ */

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2011 The Chromium OS Authors.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <fdtdec.h>
#include <asm/io.h>
#include <asm/arch/ap20.h>
#include <asm/arch/apb_misc.h>
#include <asm/arch/clock.h>
#include <asm/arch/emc.h>
#include <asm/arch/tegra2.h>
/*
* The EMC registers have shadow registers. When the EMC clock is updated
* in the clock controller, the shadow registers are copied to the active
* registers, allowing glitchless memory bus frequency changes.
* This function updates the shadow registers for a new clock frequency,
* and relies on the clock lock on the emc clock to avoid races between
* multiple frequency changes
*/
/*
* This table defines the ordering of the registers provided to
* tegra_set_mmc()
* TODO: Convert to fdt version once available
*/
static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
0x2c, /* RC */
0x30, /* RFC */
0x34, /* RAS */
0x38, /* RP */
0x3c, /* R2W */
0x40, /* W2R */
0x44, /* R2P */
0x48, /* W2P */
0x4c, /* RD_RCD */
0x50, /* WR_RCD */
0x54, /* RRD */
0x58, /* REXT */
0x5c, /* WDV */
0x60, /* QUSE */
0x64, /* QRST */
0x68, /* QSAFE */
0x6c, /* RDV */
0x70, /* REFRESH */
0x74, /* BURST_REFRESH_NUM */
0x78, /* PDEX2WR */
0x7c, /* PDEX2RD */
0x80, /* PCHG2PDEN */
0x84, /* ACT2PDEN */
0x88, /* AR2PDEN */
0x8c, /* RW2PDEN */
0x90, /* TXSR */
0x94, /* TCKE */
0x98, /* TFAW */
0x9c, /* TRPAB */
0xa0, /* TCLKSTABLE */
0xa4, /* TCLKSTOP */
0xa8, /* TREFBW */
0xac, /* QUSE_EXTRA */
0x114, /* FBIO_CFG6 */
0xb0, /* ODT_WRITE */
0xb4, /* ODT_READ */
0x104, /* FBIO_CFG5 */
0x2bc, /* CFG_DIG_DLL */
0x2c0, /* DLL_XFORM_DQS */
0x2c4, /* DLL_XFORM_QUSE */
0x2e0, /* ZCAL_REF_CNT */
0x2e4, /* ZCAL_WAIT_CNT */
0x2a8, /* AUTO_CAL_INTERVAL */
0x2d0, /* CFG_CLKTRIM_0 */
0x2d4, /* CFG_CLKTRIM_1 */
0x2d8, /* CFG_CLKTRIM_2 */
};
struct emc_ctlr *emc_get_controller(const void *blob)
{
fdt_addr_t addr;
int node;
node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_EMC);
if (node > 0) {
addr = fdtdec_get_addr(blob, node, "reg");
if (addr != FDT_ADDR_T_NONE)
return (struct emc_ctlr *)addr;
}
return NULL;
}
/* Error codes we use */
enum {
ERR_NO_EMC_NODE = -10,
ERR_NO_EMC_REG,
ERR_NO_FREQ,
ERR_FREQ_NOT_FOUND,
ERR_BAD_REGS,
ERR_NO_RAM_CODE,
ERR_RAM_CODE_NOT_FOUND,
};
/**
* Find EMC tables for the given ram code.
*
* The tegra EMC binding has two options, one using the ram code and one not.
* We detect which is in use by looking for the nvidia,use-ram-code property.
* If this is not present, then the EMC tables are directly below 'node',
* otherwise we select the correct emc-tables subnode based on the 'ram_code'
* value.
*
* @param blob Device tree blob
* @param node EMC node (nvidia,tegra20-emc compatible string)
* @param ram_code RAM code to select (0-3, or -1 if unknown)
* @return 0 if ok, otherwise a -ve ERR_ code (see enum above)
*/
static int find_emc_tables(const void *blob, int node, int ram_code)
{
int need_ram_code;
int depth;
int offset;
/* If we are using RAM codes, scan through the tables for our code */
need_ram_code = fdtdec_get_bool(blob, node, "nvidia,use-ram-code");
if (!need_ram_code)
return node;
if (ram_code == -1) {
debug("%s: RAM code required but not supplied\n", __func__);
return ERR_NO_RAM_CODE;
}
offset = node;
depth = 0;
do {
/*
* Sadly there is no compatible string so we cannot use
* fdtdec_next_compatible_subnode().
*/
offset = fdt_next_node(blob, offset, &depth);
if (depth <= 0)
break;
/* Make sure this is a direct subnode */
if (depth != 1)
continue;
if (strcmp("emc-tables", fdt_get_name(blob, offset, NULL)))
continue;
if (fdtdec_get_int(blob, offset, "nvidia,ram-code", -1)
== ram_code)
return offset;
} while (1);
debug("%s: Could not find tables for RAM code %d\n", __func__,
ram_code);
return ERR_RAM_CODE_NOT_FOUND;
}
/**
* Decode the EMC node of the device tree, returning a pointer to the emc
* controller and the table to be used for the given rate.
*
* @param blob Device tree blob
* @param rate Clock speed of memory controller in Hz (=2x memory bus rate)
* @param emcp Returns address of EMC controller registers
* @param tablep Returns pointer to table to program into EMC. There are
* TEGRA_EMC_NUM_REGS entries, destined for offsets as per the
* emc_reg_addr array.
* @return 0 if ok, otherwise a -ve error code which will allow someone to
* figure out roughly what went wrong by looking at this code.
*/
static int decode_emc(const void *blob, unsigned rate, struct emc_ctlr **emcp,
const u32 **tablep)
{
struct apb_misc_pp_ctlr *pp =
(struct apb_misc_pp_ctlr *)NV_PA_APB_MISC_BASE;
int ram_code;
int depth;
int node;
ram_code = (readl(&pp->strapping_opt_a) & RAM_CODE_MASK)
>> RAM_CODE_SHIFT;
/*
* The EMC clock rate is twice the bus rate, and the bus rate is
* measured in kHz
*/
rate = rate / 2 / 1000;
node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_EMC);
if (node < 0) {
debug("%s: No EMC node found in FDT\n", __func__);
return ERR_NO_EMC_NODE;
}
*emcp = (struct emc_ctlr *)fdtdec_get_addr(blob, node, "reg");
if (*emcp == (struct emc_ctlr *)FDT_ADDR_T_NONE) {
debug("%s: No EMC node reg property\n", __func__);
return ERR_NO_EMC_REG;
}
/* Work out the parent node which contains our EMC tables */
node = find_emc_tables(blob, node, ram_code & 3);
if (node < 0)
return node;
depth = 0;
for (;;) {
int node_rate;
node = fdtdec_next_compatible_subnode(blob, node,
COMPAT_NVIDIA_TEGRA20_EMC_TABLE, &depth);
if (node < 0)
break;
node_rate = fdtdec_get_int(blob, node, "clock-frequency", -1);
if (node_rate == -1) {
debug("%s: Missing clock-frequency\n", __func__);
return ERR_NO_FREQ; /* we expect this property */
}
if (node_rate == rate)
break;
}
if (node < 0) {
debug("%s: No node found for clock frequency %d\n", __func__,
rate);
return ERR_FREQ_NOT_FOUND;
}
*tablep = fdtdec_locate_array(blob, node, "nvidia,emc-registers",
TEGRA_EMC_NUM_REGS);
if (!*tablep) {
debug("%s: node '%s' array missing / wrong size\n", __func__,
fdt_get_name(blob, node, NULL));
return ERR_BAD_REGS;
}
/* All seems well */
return 0;
}
int tegra_set_emc(const void *blob, unsigned rate)
{
struct emc_ctlr *emc;
const u32 *table;
int err, i;
err = decode_emc(blob, rate, &emc, &table);
if (err) {
debug("Warning: no valid EMC (%d), memory timings unset\n",
err);
return err;
}
debug("%s: Table found, setting EMC values as follows:\n", __func__);
for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) {
u32 value = fdt32_to_cpu(table[i]);
u32 addr = (uintptr_t)emc + emc_reg_addr[i];
debug(" %#x: %#x\n", addr, value);
writel(value, addr);
}
/* trigger emc with new settings */
clock_adjust_periph_pll_div(PERIPH_ID_EMC, CLOCK_ID_MEMORY,
clock_get_rate(CLOCK_ID_MEMORY), NULL);
debug("EMC clock set to %lu\n",
clock_get_periph_rate(PERIPH_ID_EMC, CLOCK_ID_MEMORY));
return 0;
}

View File

@ -169,6 +169,22 @@ int funcmux_select(enum periph_id id, int config)
}
break;
case PERIPH_ID_KBC:
if (config == FUNCMUX_DEFAULT) {
enum pmux_pingrp grp[] = {PINGRP_KBCA, PINGRP_KBCB,
PINGRP_KBCC, PINGRP_KBCD, PINGRP_KBCE,
PINGRP_KBCF};
int i;
for (i = 0; i < ARRAY_SIZE(grp); i++) {
pinmux_tristate_disable(grp[i]);
pinmux_set_func(grp[i], PMUX_FUNC_KBC);
pinmux_set_pullupdown(grp[i], PMUX_PULL_UP);
}
break;
}
default:
debug("%s: invalid periph_id %d", __func__, id);
return -1;

View File

@ -25,10 +25,10 @@
#include <config.h>
#include <version.h>
#include <linux/linkage.h>
.align 5
.global reset_cpu
reset_cpu:
ENTRY(reset_cpu)
ldr r1, rstctl @ get addr for global reset
@ reg
ldr r3, [r1]
@ -39,3 +39,4 @@ _loop_forever:
b _loop_forever
rstctl:
.word PRM_RSTCTRL
ENDPROC(reset_cpu)

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2011 The Chromium OS Authors.
* (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <tps6586x.h>
#include <asm/io.h>
#include <asm/arch/ap20.h>
#include <asm/arch/tegra2.h>
#include <asm/arch/tegra_i2c.h>
#include <asm/arch/sys_proto.h>
#define VDD_CORE_NOMINAL_T25 0x17 /* 1.3v */
#define VDD_CPU_NOMINAL_T25 0x10 /* 1.125v */
#define VDD_CORE_NOMINAL_T20 0x16 /* 1.275v */
#define VDD_CPU_NOMINAL_T20 0x0f /* 1.1v */
#define VDD_RELATION 0x02 /* 50mv */
#define VDD_TRANSITION_STEP 0x06 /* 150mv */
#define VDD_TRANSITION_RATE 0x06 /* 3.52mv/us */
int pmu_set_nominal(void)
{
int core, cpu, bus;
/* by default, the table has been filled with T25 settings */
switch (tegra_get_chip_type()) {
case TEGRA_SOC_T20:
core = VDD_CORE_NOMINAL_T20;
cpu = VDD_CPU_NOMINAL_T20;
break;
case TEGRA_SOC_T25:
core = VDD_CORE_NOMINAL_T25;
cpu = VDD_CPU_NOMINAL_T25;
break;
default:
debug("%s: Unknown chip type\n", __func__);
return -1;
}
bus = tegra_i2c_get_dvc_bus_num();
if (bus == -1) {
debug("%s: Cannot find DVC I2C bus\n", __func__);
return -1;
}
tps6586x_init(bus);
tps6586x_set_pwm_mode(TPS6586X_PWM_SM1);
return tps6586x_adjust_sm0_sm1(core, cpu, VDD_TRANSITION_STEP,
VDD_TRANSITION_RATE, VDD_RELATION);
}

View File

@ -0,0 +1,386 @@
/*
* (C) Copyright 2010 - 2011
* NVIDIA Corporation <www.nvidia.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <asm/arch/ap20.h>
#include <asm/arch/clk_rst.h>
#include <asm/arch/clock.h>
#include <asm/arch/pmc.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/tegra2.h>
#include <asm/arch/fuse.h>
#include <asm/arch/emc.h>
#include <asm/arch/gp_padctrl.h>
#include <asm/arch/warmboot.h>
#include <asm/arch/sdram_param.h>
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_TEGRA_CLOCK_SCALING
#error "You must enable CONFIG_TEGRA_CLOCK_SCALING to use CONFIG_TEGRA2_LP0"
#endif
/*
* This is the place in SRAM where the SDRAM parameters are stored. There
* are 4 blocks, one for each RAM code
*/
#define SDRAM_PARAMS_BASE (AP20_BASE_PA_SRAM + 0x188)
/* TODO: If we later add support for the Misc GP controller, refactor this */
union xm2cfga_reg {
struct {
u32 reserved0:2;
u32 hsm_en:1;
u32 reserved1:2;
u32 preemp_en:1;
u32 vref_en:1;
u32 reserved2:5;
u32 cal_drvdn:5;
u32 reserved3:3;
u32 cal_drvup:5;
u32 reserved4:3;
u32 cal_drvdn_slwr:2;
u32 cal_drvup_slwf:2;
};
u32 word;
};
union xm2cfgd_reg {
struct {
u32 reserved0:2;
u32 hsm_en:1;
u32 schmt_en:1;
u32 lpmd:2;
u32 vref_en:1;
u32 reserved1:5;
u32 cal_drvdn:5;
u32 reserved2:3;
u32 cal_drvup:5;
u32 reserved3:3;
u32 cal_drvdn_slwr:2;
u32 cal_drvup_slwf:2;
};
u32 word;
};
/*
* TODO: This register is not documented in the TRM yet. We could move this
* into the EMC and give it a proper interface, but not while it is
* undocumented.
*/
union fbio_spare_reg {
struct {
u32 reserved:24;
u32 cfg_wb0:8;
};
u32 word;
};
/* We pack the resume information into these unions for later */
union scratch2_reg {
struct {
u32 pllm_base_divm:5;
u32 pllm_base_divn:10;
u32 pllm_base_divp:3;
u32 pllm_misc_lfcon:4;
u32 pllm_misc_cpcon:4;
u32 gp_xm2cfga_padctrl_preemp:1;
u32 gp_xm2cfgd_padctrl_schmt:1;
u32 osc_ctrl_xobp:1;
u32 memory_type:3;
};
u32 word;
};
union scratch4_reg {
struct {
u32 emc_clock_divider:8;
u32 pllm_stable_time:8;
u32 pllx_stable_time:8;
u32 emc_fbio_spare_cfg_wb0:8;
};
u32 word;
};
union scratch24_reg {
struct {
u32 emc_auto_cal_wait:8;
u32 emc_pin_program_wait:8;
u32 warmboot_wait:8;
u32 reserved:8;
};
u32 word;
};
int warmboot_save_sdram_params(void)
{
u32 ram_code;
struct sdram_params sdram;
struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE;
struct apb_misc_gp_ctlr *gp =
(struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE;
struct emc_ctlr *emc = emc_get_controller(gd->fdt_blob);
union scratch2_reg scratch2;
union scratch4_reg scratch4;
union scratch24_reg scratch24;
union xm2cfga_reg xm2cfga;
union xm2cfgd_reg xm2cfgd;
union fbio_spare_reg fbio_spare;
/* get ram code that is used as index to array sdram_params in BCT */
ram_code = (readl(&pmt->pmt_strap_opt_a) >>
STRAP_OPT_A_RAM_CODE_SHIFT) & 3;
memcpy(&sdram,
(char *)((struct sdram_params *)SDRAM_PARAMS_BASE + ram_code),
sizeof(sdram));
xm2cfga.word = readl(&gp->xm2cfga);
xm2cfgd.word = readl(&gp->xm2cfgd);
scratch2.word = 0;
scratch2.osc_ctrl_xobp = clock_get_osc_bypass();
/* Get the memory PLL settings */
{
u32 divm, divn, divp, cpcon, lfcon;
if (clock_ll_read_pll(CLOCK_ID_MEMORY, &divm, &divn, &divp,
&cpcon, &lfcon))
return -1;
scratch2.pllm_base_divm = divm;
scratch2.pllm_base_divn = divn;
scratch2.pllm_base_divp = divp;
scratch2.pllm_misc_cpcon = cpcon;
scratch2.pllm_misc_lfcon = lfcon;
}
scratch2.gp_xm2cfga_padctrl_preemp = xm2cfga.preemp_en;
scratch2.gp_xm2cfgd_padctrl_schmt = xm2cfgd.schmt_en;
scratch2.memory_type = sdram.memory_type;
writel(scratch2.word, &pmc->pmc_scratch2);
/* collect data from various sources for pmc_scratch4 */
fbio_spare.word = readl(&emc->fbio_spare);
scratch4.word = 0;
scratch4.emc_fbio_spare_cfg_wb0 = fbio_spare.cfg_wb0;
scratch4.emc_clock_divider = sdram.emc_clock_divider;
scratch4.pllm_stable_time = -1;
scratch4.pllx_stable_time = -1;
writel(scratch4.word, &pmc->pmc_scratch4);
/* collect various data from sdram for pmc_scratch24 */
scratch24.word = 0;
scratch24.emc_pin_program_wait = sdram.emc_pin_program_wait;
scratch24.emc_auto_cal_wait = sdram.emc_auto_cal_wait;
scratch24.warmboot_wait = sdram.warm_boot_wait;
writel(scratch24.word, &pmc->pmc_scratch24);
return 0;
}
static u32 get_major_version(void)
{
u32 major_id;
struct apb_misc_gp_ctlr *gp =
(struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE;
major_id = (readl(&gp->hidrev) & HIDREV_MAJORPREV_MASK) >>
HIDREV_MAJORPREV_SHIFT;
return major_id;
}
static int is_production_mode_fuse_set(struct fuse_regs *fuse)
{
return readl(&fuse->production_mode);
}
static int is_odm_production_mode_fuse_set(struct fuse_regs *fuse)
{
return readl(&fuse->security_mode);
}
static int is_failure_analysis_mode(struct fuse_regs *fuse)
{
return readl(&fuse->fa);
}
static int ap20_is_odm_production_mode(void)
{
struct fuse_regs *fuse = (struct fuse_regs *)TEGRA2_FUSE_BASE;
if (!is_failure_analysis_mode(fuse) &&
is_odm_production_mode_fuse_set(fuse))
return 1;
else
return 0;
}
static int ap20_is_production_mode(void)
{
struct fuse_regs *fuse = (struct fuse_regs *)TEGRA2_FUSE_BASE;
if (get_major_version() == 0)
return 1;
if (!is_failure_analysis_mode(fuse) &&
is_production_mode_fuse_set(fuse) &&
!is_odm_production_mode_fuse_set(fuse))
return 1;
else
return 0;
}
static enum fuse_operating_mode fuse_get_operation_mode(void)
{
u32 chip_id;
struct apb_misc_gp_ctlr *gp =
(struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE;
chip_id = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >>
HIDREV_CHIPID_SHIFT;
if (chip_id == CHIPID_TEGRA2) {
if (ap20_is_odm_production_mode()) {
printf("!! odm_production_mode is not supported !!\n");
return MODE_UNDEFINED;
} else
if (ap20_is_production_mode())
return MODE_PRODUCTION;
else
return MODE_UNDEFINED;
}
return MODE_UNDEFINED;
}
static void determine_crypto_options(int *is_encrypted, int *is_signed,
int *use_zero_key)
{
switch (fuse_get_operation_mode()) {
case MODE_PRODUCTION:
*is_encrypted = 0;
*is_signed = 1;
*use_zero_key = 1;
break;
case MODE_UNDEFINED:
default:
*is_encrypted = 0;
*is_signed = 0;
*use_zero_key = 0;
break;
}
}
static int sign_wb_code(u32 start, u32 length, int use_zero_key)
{
int err;
u8 *source; /* Pointer to source */
u8 *hash;
/* Calculate AES block parameters. */
source = (u8 *)(start + offsetof(struct wb_header, random_aes_block));
length -= offsetof(struct wb_header, random_aes_block);
hash = (u8 *)(start + offsetof(struct wb_header, hash));
err = sign_data_block(source, length, hash);
return err;
}
int warmboot_prepare_code(u32 seg_address, u32 seg_length)
{
int err = 0;
u32 length; /* length of the signed/encrypt code */
struct wb_header *dst_header; /* Pointer to dest WB header */
int is_encrypted; /* Segment is encrypted */
int is_signed; /* Segment is signed */
int use_zero_key; /* Use key of all zeros */
/* Determine crypto options. */
determine_crypto_options(&is_encrypted, &is_signed, &use_zero_key);
/* Get the actual code limits. */
length = roundup(((u32)wb_end - (u32)wb_start), 16);
/*
* The region specified by seg_address must be in SDRAM and must be
* nonzero in length.
*/
if (seg_length == 0 || seg_address < NV_PA_SDRAM_BASE ||
seg_address + seg_length >= NV_PA_SDRAM_BASE + gd->ram_size) {
err = -EFAULT;
goto fail;
}
/* Things must be 16-byte aligned. */
if ((seg_length & 0xF) || (seg_address & 0xF)) {
err = -EINVAL;
goto fail;
}
/* Will the code fit? (destination includes wb_header + wb code) */
if (seg_length < (length + sizeof(struct wb_header))) {
err = -EINVAL;
goto fail;
}
dst_header = (struct wb_header *)seg_address;
memset((char *)dst_header, 0, sizeof(struct wb_header));
/* Populate the random_aes_block as requested. */
{
u32 *aes_block = (u32 *)&(dst_header->random_aes_block);
u32 *end = (u32 *)(((u32)aes_block) +
sizeof(dst_header->random_aes_block));
do {
*aes_block++ = 0;
} while (aes_block < end);
}
/* Populate the header. */
dst_header->length_insecure = length + sizeof(struct wb_header);
dst_header->length_secure = length + sizeof(struct wb_header);
dst_header->destination = AP20_WB_RUN_ADDRESS;
dst_header->entry_point = AP20_WB_RUN_ADDRESS;
dst_header->code_length = length;
if (is_encrypted) {
printf("!!!! Encryption is not supported !!!!\n");
dst_header->length_insecure = 0;
err = -EACCES;
goto fail;
} else
/* copy the wb code directly following dst_header. */
memcpy((char *)(dst_header+1), (char *)wb_start, length);
if (is_signed)
err = sign_wb_code(seg_address, dst_header->length_insecure,
use_zero_key);
fail:
if (err)
printf("Warning: warmboot code copy failed (error=%d)\n", err);
return err;
}

View File

@ -0,0 +1,250 @@
/*
* (C) Copyright 2010 - 2011
* NVIDIA Corporation <www.nvidia.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/ap20.h>
#include <asm/arch/clk_rst.h>
#include <asm/arch/clock.h>
#include <asm/arch/flow.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/pmc.h>
#include <asm/arch/tegra2.h>
#include <asm/arch/warmboot.h>
#include "warmboot_avp.h"
#define DEBUG_RESET_CORESIGHT
void wb_start(void)
{
struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE;
struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
struct clk_rst_ctlr *clkrst =
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
union osc_ctrl_reg osc_ctrl;
union pllx_base_reg pllx_base;
union pllx_misc_reg pllx_misc;
union scratch3_reg scratch3;
u32 reg;
/* enable JTAG & TBE */
writel(CONFIG_CTL_TBE | CONFIG_CTL_JTAG, &pmt->pmt_cfg_ctl);
/* Are we running where we're supposed to be? */
asm volatile (
"adr %0, wb_start;" /* reg: wb_start address */
: "=r"(reg) /* output */
/* no input, no clobber list */
);
if (reg != AP20_WB_RUN_ADDRESS)
goto do_reset;
/* Are we running with AVP? */
if (readl(NV_PA_PG_UP_BASE + PG_UP_TAG_0) != PG_UP_TAG_AVP)
goto do_reset;
#ifdef DEBUG_RESET_CORESIGHT
/* Assert CoreSight reset */
reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_U]);
reg |= SWR_CSITE_RST;
writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_U]);
#endif
/* TODO: Set the drive strength - maybe make this a board parameter? */
osc_ctrl.word = readl(&clkrst->crc_osc_ctrl);
osc_ctrl.xofs = 4;
osc_ctrl.xoe = 1;
writel(osc_ctrl.word, &clkrst->crc_osc_ctrl);
/* Power up the CPU complex if necessary */
if (!(readl(&pmc->pmc_pwrgate_status) & PWRGATE_STATUS_CPU)) {
reg = PWRGATE_TOGGLE_PARTID_CPU | PWRGATE_TOGGLE_START;
writel(reg, &pmc->pmc_pwrgate_toggle);
while (!(readl(&pmc->pmc_pwrgate_status) & PWRGATE_STATUS_CPU))
;
}
/* Remove the I/O clamps from the CPU power partition. */
reg = readl(&pmc->pmc_remove_clamping);
reg |= CPU_CLMP;
writel(reg, &pmc->pmc_remove_clamping);
reg = EVENT_ZERO_VAL_20 | EVENT_MSEC | EVENT_MODE_STOP;
writel(reg, &flow->halt_cop_events);
/* Assert CPU complex reset */
reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]);
reg |= CPU_RST;
writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
/* Hold both CPUs in reset */
reg = CPU_CMPLX_CPURESET0 | CPU_CMPLX_CPURESET1 | CPU_CMPLX_DERESET0 |
CPU_CMPLX_DERESET1 | CPU_CMPLX_DBGRESET0 | CPU_CMPLX_DBGRESET1;
writel(reg, &clkrst->crc_cpu_cmplx_set);
/* Halt CPU1 at the flow controller for uni-processor configurations */
writel(EVENT_MODE_STOP, &flow->halt_cpu1_events);
/*
* Set the CPU reset vector. SCRATCH41 contains the physical
* address of the CPU-side restoration code.
*/
reg = readl(&pmc->pmc_scratch41);
writel(reg, EXCEP_VECTOR_CPU_RESET_VECTOR);
/* Select CPU complex clock source */
writel(CCLK_PLLP_BURST_POLICY, &clkrst->crc_cclk_brst_pol);
/* Start the CPU0 clock and stop the CPU1 clock */
reg = CPU_CMPLX_CPU_BRIDGE_CLKDIV_4 | CPU_CMPLX_CPU0_CLK_STP_RUN |
CPU_CMPLX_CPU1_CLK_STP_STOP;
writel(reg, &clkrst->crc_clk_cpu_cmplx);
/* Enable the CPU complex clock */
reg = readl(&clkrst->crc_clk_out_enb[TEGRA_DEV_L]);
reg |= CLK_ENB_CPU;
writel(reg, &clkrst->crc_clk_out_enb[TEGRA_DEV_L]);
/* Make sure the resets were held for at least 2 microseconds */
reg = readl(TIMER_USEC_CNTR);
while (readl(TIMER_USEC_CNTR) <= (reg + 2))
;
#ifdef DEBUG_RESET_CORESIGHT
/*
* De-assert CoreSight reset.
* NOTE: We're leaving the CoreSight clock on the oscillator for
* now. It will be restored to its original clock source
* when the CPU-side restoration code runs.
*/
reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_U]);
reg &= ~SWR_CSITE_RST;
writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_U]);
#endif
/* Unlock the CPU CoreSight interfaces */
reg = 0xC5ACCE55;
writel(reg, CSITE_CPU_DBG0_LAR);
writel(reg, CSITE_CPU_DBG1_LAR);
/*
* Sample the microsecond timestamp again. This is the time we must
* use when returning from LP0 for PLL stabilization delays.
*/
reg = readl(TIMER_USEC_CNTR);
writel(reg, &pmc->pmc_scratch1);
pllx_base.word = 0;
pllx_misc.word = 0;
scratch3.word = readl(&pmc->pmc_scratch3);
/* Get the OSC. For 19.2 MHz, use 19 to make the calculations easier */
reg = (readl(TIMER_USEC_CFG) & USEC_CFG_DIVISOR_MASK) + 1;
/*
* According to the TRM, for 19.2MHz OSC, the USEC_DIVISOR is 0x5f, and
* USEC_DIVIDEND is 0x04. So, if USEC_DIVISOR > 26, OSC is 19.2 MHz.
*
* reg is used to calculate the pllx freq, which is used to determine if
* to set dccon or not.
*/
if (reg > 26)
reg = 19;
/* PLLX_BASE.PLLX_DIVM */
if (scratch3.pllx_base_divm == reg)
reg = 0;
else
reg = 1;
/* PLLX_BASE.PLLX_DIVN */
pllx_base.divn = scratch3.pllx_base_divn;
reg = scratch3.pllx_base_divn << reg;
/* PLLX_BASE.PLLX_DIVP */
pllx_base.divp = scratch3.pllx_base_divp;
reg = reg >> scratch3.pllx_base_divp;
pllx_base.bypass = 1;
/* PLLX_MISC_DCCON must be set for pllx frequency > 600 MHz. */
if (reg > 600)
pllx_misc.dccon = 1;
/* PLLX_MISC_LFCON */
pllx_misc.lfcon = scratch3.pllx_misc_lfcon;
/* PLLX_MISC_CPCON */
pllx_misc.cpcon = scratch3.pllx_misc_cpcon;
writel(pllx_misc.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_misc);
writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
pllx_base.enable = 1;
writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
pllx_base.bypass = 0;
writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
writel(0, flow->halt_cpu_events);
reg = CPU_CMPLX_CPURESET0 | CPU_CMPLX_DBGRESET0 | CPU_CMPLX_DERESET0;
writel(reg, &clkrst->crc_cpu_cmplx_clr);
reg = PLLM_OUT1_RSTN_RESET_DISABLE | PLLM_OUT1_CLKEN_ENABLE |
PLLM_OUT1_RATIO_VAL_8;
writel(reg, &clkrst->crc_pll[CLOCK_ID_MEMORY].pll_out);
reg = SCLK_SWAKE_FIQ_SRC_PLLM_OUT1 | SCLK_SWAKE_IRQ_SRC_PLLM_OUT1 |
SCLK_SWAKE_RUN_SRC_PLLM_OUT1 | SCLK_SWAKE_IDLE_SRC_PLLM_OUT1 |
SCLK_SYS_STATE_IDLE;
writel(reg, &clkrst->crc_sclk_brst_pol);
/* avp_resume: no return after the write */
reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]);
reg &= ~CPU_RST;
writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
/* avp_halt: */
avp_halt:
reg = EVENT_MODE_STOP | EVENT_JTAG;
writel(reg, flow->halt_cop_events);
goto avp_halt;
do_reset:
/*
* Execution comes here if something goes wrong. The chip is reset and
* a cold boot is performed.
*/
writel(SWR_TRIG_SYS_RST, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
goto do_reset;
}
/*
* wb_end() is a dummy function, and must be directly following wb_start(),
* and is used to calculate the size of wb_start().
*/
void wb_end(void)
{
}

View File

@ -0,0 +1,81 @@
/*
* (C) Copyright 2010, 2011
* NVIDIA Corporation <www.nvidia.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef _WARMBOOT_AVP_H_
#define _WARMBOOT_AVP_H_
#define TEGRA_DEV_L 0
#define TEGRA_DEV_H 1
#define TEGRA_DEV_U 2
#define SIMPLE_PLLX (CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE)
#define SIMPLE_PLLE (CLOCK_ID_EPCI - CLOCK_ID_FIRST_SIMPLE)
#define TIMER_USEC_CNTR (NV_PA_TMRUS_BASE + 0)
#define TIMER_USEC_CFG (NV_PA_TMRUS_BASE + 4)
#define USEC_CFG_DIVISOR_MASK 0xffff
#define CONFIG_CTL_TBE (1 << 7)
#define CONFIG_CTL_JTAG (1 << 6)
#define CPU_RST (1 << 0)
#define CLK_ENB_CPU (1 << 0)
#define SWR_TRIG_SYS_RST (1 << 2)
#define SWR_CSITE_RST (1 << 9)
#define PWRGATE_STATUS_CPU (1 << 0)
#define PWRGATE_TOGGLE_PARTID_CPU (0 << 0)
#define PWRGATE_TOGGLE_START (1 << 8)
#define CPU_CMPLX_CPU_BRIDGE_CLKDIV_4 (3 << 0)
#define CPU_CMPLX_CPU0_CLK_STP_STOP (1 << 8)
#define CPU_CMPLX_CPU0_CLK_STP_RUN (0 << 8)
#define CPU_CMPLX_CPU1_CLK_STP_STOP (1 << 9)
#define CPU_CMPLX_CPU1_CLK_STP_RUN (0 << 9)
#define CPU_CMPLX_CPURESET0 (1 << 0)
#define CPU_CMPLX_CPURESET1 (1 << 1)
#define CPU_CMPLX_DERESET0 (1 << 4)
#define CPU_CMPLX_DERESET1 (1 << 5)
#define CPU_CMPLX_DBGRESET0 (1 << 12)
#define CPU_CMPLX_DBGRESET1 (1 << 13)
#define PLLM_OUT1_RSTN_RESET_DISABLE (1 << 0)
#define PLLM_OUT1_CLKEN_ENABLE (1 << 1)
#define PLLM_OUT1_RATIO_VAL_8 (8 << 8)
#define SCLK_SYS_STATE_IDLE (1 << 28)
#define SCLK_SWAKE_FIQ_SRC_PLLM_OUT1 (7 << 12)
#define SCLK_SWAKE_IRQ_SRC_PLLM_OUT1 (7 << 8)
#define SCLK_SWAKE_RUN_SRC_PLLM_OUT1 (7 << 4)
#define SCLK_SWAKE_IDLE_SRC_PLLM_OUT1 (7 << 0)
#define EVENT_ZERO_VAL_20 (20 << 0)
#define EVENT_MSEC (1 << 24)
#define EVENT_JTAG (1 << 28)
#define EVENT_MODE_STOP (2 << 29)
#define CCLK_PLLP_BURST_POLICY 0x20004444
#endif

View File

@ -20,16 +20,17 @@
*/
#include <config.h>
#include <linux/linkage.h>
.globl lowlevel_init
lowlevel_init:
ENTRY(lowlevel_init)
mov pc, lr
ENDPROC(lowlevel_init)
.align 5
.globl reset_cpu
reset_cpu:
ENTRY(reset_cpu)
ldr r0, =CFG_PRCMU_BASE
ldr r1, =0x1
str r1, [r0, #0x228]
_loop_forever:
b _loop_forever
ENDPROC(reset_cpu)

View File

@ -518,7 +518,7 @@ static void npe_halt(struct eth_device *dev)
}
static int npe_send(struct eth_device *dev, volatile void *packet, int len)
static int npe_send(struct eth_device *dev, void *packet, int len)
{
struct npe *p_npe = (struct npe *)dev->priv;
u8 *dest;

View File

@ -193,4 +193,15 @@
clocks = <&tegra_car 59>; /* PERIPH_ID_USB3 */
};
emc@7000f400 {
#address-cells = < 1 >;
#size-cells = < 0 >;
compatible = "nvidia,tegra20-emc";
reg = <0x7000f400 0x200>;
};
kbc@7000e200 {
compatible = "nvidia,tegra20-kbc";
reg = <0x7000e200 0x0078>;
};
};

View File

@ -159,6 +159,6 @@ typedef struct hsmmc {
#define mmc_reg_out(addr, mask, val)\
writel((readl(addr) & (~(mask))) | ((val) & (mask)), (addr))
int omap_mmc_init(int dev_index);
int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max);
#endif /* MMC_HOST_DEF_H */

View File

@ -33,5 +33,8 @@ unsigned long get_arm_clk(void);
unsigned long get_pwm_clk(void);
unsigned long get_uart_clk(int dev_index);
void set_mmc_clk(int dev_index, unsigned int div);
unsigned long get_lcd_clk(void);
void set_lcd_clk(void);
void set_mipi_clk(void);
#endif

View File

@ -29,6 +29,7 @@
/* EXYNOS4 */
#define EXYNOS4_GPIO_PART3_BASE 0x03860000
#define EXYNOS4_PRO_ID 0x10000000
#define EXYNOS4_SYSREG_BASE 0x10010000
#define EXYNOS4_POWER_BASE 0x10020000
#define EXYNOS4_SWRESET 0x10020400
#define EXYNOS4_CLOCK_BASE 0x10030000
@ -40,6 +41,7 @@
#define EXYNOS4_GPIO_PART2_BASE 0x11000000
#define EXYNOS4_GPIO_PART1_BASE 0x11400000
#define EXYNOS4_FIMD_BASE 0x11C00000
#define EXYNOS4_MIPI_DSIM_BASE 0x11C80000
#define EXYNOS4_USBOTG_BASE 0x12480000
#define EXYNOS4_MMC_BASE 0x12510000
#define EXYNOS4_SROMC_BASE 0x12570000
@ -65,6 +67,7 @@
#define EXYNOS5_GPIO_PART3_BASE 0x10D10000
#define EXYNOS5_DMC_CTRL_BASE 0x10DD0000
#define EXYNOS5_GPIO_PART1_BASE 0x11400000
#define EXYNOS5_MIPI_DSIM_BASE 0x11D00000
#define EXYNOS5_MMC_BASE 0x12200000
#define EXYNOS5_SROMC_BASE 0x12250000
#define EXYNOS5_USBOTG_BASE 0x12480000
@ -127,7 +130,9 @@ static inline unsigned int samsung_get_base_##device(void) \
SAMSUNG_BASE(adc, ADC_BASE)
SAMSUNG_BASE(clock, CLOCK_BASE)
SAMSUNG_BASE(sysreg, SYSREG_BASE)
SAMSUNG_BASE(fimd, FIMD_BASE)
SAMSUNG_BASE(mipi_dsim, MIPI_DSIM_BASE)
SAMSUNG_BASE(gpio_part1, GPIO_PART1_BASE)
SAMSUNG_BASE(gpio_part2, GPIO_PART2_BASE)
SAMSUNG_BASE(gpio_part3, GPIO_PART3_BASE)

View File

@ -0,0 +1,181 @@
/*
* Copyright (C) 2012 Samsung Electronics
*
* Author: InKi Dae <inki.dae@samsung.com>
* Author: Donghwa Lee <dh09.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef __ASM_ARM_ARCH_DSIM_H_
#define __ASM_ARM_ARCH_DSIM_H_
#ifndef __ASSEMBLY__
struct exynos_mipi_dsim {
unsigned int status;
unsigned int swrst;
unsigned int clkctrl;
unsigned int timeout;
unsigned int config;
unsigned int escmode;
unsigned int mdresol;
unsigned int mvporch;
unsigned int mhporch;
unsigned int msync;
unsigned int sdresol;
unsigned int intsrc;
unsigned int intmsk;
unsigned int pkthdr;
unsigned int payload;
unsigned int rxfifo;
unsigned int fifothld;
unsigned int fifoctrl;
unsigned int memacchr;
unsigned int pllctrl;
unsigned int plltmr;
unsigned int phyacchr;
unsigned int phyacchr1;
};
#endif /* __ASSEMBLY__ */
/*
* Bit Definitions
*/
/* DSIM_STATUS */
#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0)
#define DSIM_STOP_STATE_CLK (1 << 8)
#define DSIM_TX_READY_HS_CLK (1 << 10)
#define DSIM_PLL_STABLE (1 << 31)
/* DSIM_SWRST */
#define DSIM_FUNCRST (1 << 16)
#define DSIM_SWRST (1 << 0)
/* EXYNOS_DSIM_TIMEOUT */
#define DSIM_LPDR_TOUT_SHIFT (0)
#define DSIM_BTA_TOUT_SHIFT (16)
/* EXYNOS_DSIM_CLKCTRL */
#define DSIM_LANE_ESC_CLKEN_SHIFT (19)
#define DSIM_BYTE_CLKEN_SHIFT (24)
#define DSIM_BYTE_CLK_SRC_SHIFT (25)
#define DSIM_PLL_BYPASS_SHIFT (27)
#define DSIM_ESC_CLKEN_SHIFT (28)
#define DSIM_TX_REQUEST_HSCLK_SHIFT (31)
#define DSIM_LANE_ESC_CLKEN(x) (((x) & 0x1f) << \
DSIM_LANE_ESC_CLKEN_SHIFT)
#define DSIM_BYTE_CLK_ENABLE (1 << DSIM_BYTE_CLKEN_SHIFT)
#define DSIM_BYTE_CLK_DISABLE (0 << DSIM_BYTE_CLKEN_SHIFT)
#define DSIM_PLL_BYPASS_EXTERNAL (1 << DSIM_PLL_BYPASS_SHIFT)
#define DSIM_ESC_CLKEN_ENABLE (1 << DSIM_ESC_CLKEN_SHIFT)
#define DSIM_ESC_CLKEN_DISABLE (0 << DSIM_ESC_CLKEN_SHIFT)
/* EXYNOS_DSIM_CONFIG */
#define DSIM_NUM_OF_DATALANE_SHIFT (5)
#define DSIM_SUBPIX_SHIFT (8)
#define DSIM_MAINPIX_SHIFT (12)
#define DSIM_SUBVC_SHIFT (16)
#define DSIM_MAINVC_SHIFT (18)
#define DSIM_HSA_MODE_SHIFT (20)
#define DSIM_HBP_MODE_SHIFT (21)
#define DSIM_HFP_MODE_SHIFT (22)
#define DSIM_HSE_MODE_SHIFT (23)
#define DSIM_AUTO_MODE_SHIFT (24)
#define DSIM_VIDEO_MODE_SHIFT (25)
#define DSIM_BURST_MODE_SHIFT (26)
#define DSIM_EOT_PACKET_SHIFT (28)
#define DSIM_AUTO_FLUSH_SHIFT (29)
#define DSIM_LANE_ENx(x) (((x) & 0x1f) << 0)
#define DSIM_NUM_OF_DATA_LANE(x) ((x) << DSIM_NUM_OF_DATALANE_SHIFT)
/* EXYNOS_DSIM_ESCMODE */
#define DSIM_TX_LPDT_SHIFT (6)
#define DSIM_CMD_LPDT_SHIFT (7)
#define DSIM_TX_LPDT_LP (1 << DSIM_TX_LPDT_SHIFT)
#define DSIM_CMD_LPDT_LP (1 << DSIM_CMD_LPDT_SHIFT)
#define DSIM_STOP_STATE_CNT_SHIFT (21)
#define DSIM_FORCE_STOP_STATE_SHIFT (20)
/* EXYNOS_DSIM_MDRESOL */
#define DSIM_MAIN_STAND_BY (1 << 31)
#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16)
#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0)
/* EXYNOS_DSIM_MVPORCH */
#define DSIM_CMD_ALLOW_SHIFT (28)
#define DSIM_STABLE_VFP_SHIFT (16)
#define DSIM_MAIN_VBP_SHIFT (0)
#define DSIM_CMD_ALLOW_MASK (0xf << DSIM_CMD_ALLOW_SHIFT)
#define DSIM_STABLE_VFP_MASK (0x7ff << DSIM_STABLE_VFP_SHIFT)
#define DSIM_MAIN_VBP_MASK (0x7ff << DSIM_MAIN_VBP_SHIFT)
/* EXYNOS_DSIM_MHPORCH */
#define DSIM_MAIN_HFP_SHIFT (16)
#define DSIM_MAIN_HBP_SHIFT (0)
#define DSIM_MAIN_HFP_MASK ((0xffff) << DSIM_MAIN_HFP_SHIFT)
#define DSIM_MAIN_HBP_MASK ((0xffff) << DSIM_MAIN_HBP_SHIFT)
/* EXYNOS_DSIM_MSYNC */
#define DSIM_MAIN_VSA_SHIFT (22)
#define DSIM_MAIN_HSA_SHIFT (0)
#define DSIM_MAIN_VSA_MASK ((0x3ff) << DSIM_MAIN_VSA_SHIFT)
#define DSIM_MAIN_HSA_MASK ((0xffff) << DSIM_MAIN_HSA_SHIFT)
/* EXYNOS_DSIM_SDRESOL */
#define DSIM_SUB_STANDY_SHIFT (31)
#define DSIM_SUB_VRESOL_SHIFT (16)
#define DSIM_SUB_HRESOL_SHIFT (0)
#define DSIM_SUB_STANDY_MASK ((0x1) << DSIM_SUB_STANDY_SHIFT)
#define DSIM_SUB_VRESOL_MASK ((0x7ff) << DSIM_SUB_VRESOL_SHIFT)
#define DSIM_SUB_HRESOL_MASK ((0x7ff) << DSIM_SUB_HRESOL_SHIFT)
/* EXYNOS_DSIM_INTSRC */
#define INTSRC_FRAME_DONE (1 << 24)
#define INTSRC_PLL_STABLE (1 << 31)
#define INTSRC_SWRST_RELEASE (1 << 30)
/* EXYNOS_DSIM_INTMSK */
#define INTMSK_FRAME_DONE (1 << 24)
/* EXYNOS_DSIM_FIFOCTRL */
#define SFR_HEADER_EMPTY (1 << 22)
/* EXYNOS_DSIM_PKTHDR */
#define DSIM_PKTHDR_DI(x) (((x) & 0x3f) << 0)
#define DSIM_PKTHDR_DAT0(x) ((x) << 8)
#define DSIM_PKTHDR_DAT1(x) ((x) << 16)
/* EXYNOS_DSIM_PHYACCHR */
#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5)
#define DSIM_AFC_CTL_SHIFT (5)
#define DSIM_AFC_EN (1 << 14)
/* EXYNOS_DSIM_PHYACCHR1 */
#define DSIM_DPDN_SWAP_DATA_SHIFT (0)
/* EXYNOS_DSIM_PLLCTRL */
#define DSIM_SCALER_SHIFT (1)
#define DSIM_MAIN_SHIFT (4)
#define DSIM_PREDIV_SHIFT (13)
#define DSIM_PRECTRL_SHIFT (20)
#define DSIM_PLL_EN_SHIFT (23)
#define DSIM_FREQ_BAND_SHIFT (24)
#define DSIM_ZEROCTRL_SHIFT (28)
#endif

View File

@ -0,0 +1,66 @@
/*
* SAMSUNG S5P USB HOST EHCI Controller
*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
* Vivek Gautam <gautam.vivek@samsung.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef __ASM_ARM_ARCH_EXYNOS5_EHCI_S5P_H__
#define __ASM_ARM_ARCH_EXYNOS5_EHCI_S5P_H__
#define CLK_24MHZ 5
#define HOST_CTRL0_PHYSWRSTALL (1 << 31)
#define HOST_CTRL0_COMMONON_N (1 << 9)
#define HOST_CTRL0_SIDDQ (1 << 6)
#define HOST_CTRL0_FORCESLEEP (1 << 5)
#define HOST_CTRL0_FORCESUSPEND (1 << 4)
#define HOST_CTRL0_WORDINTERFACE (1 << 3)
#define HOST_CTRL0_UTMISWRST (1 << 2)
#define HOST_CTRL0_LINKSWRST (1 << 1)
#define HOST_CTRL0_PHYSWRST (1 << 0)
#define HOST_CTRL0_FSEL_MASK (7 << 16)
#define EHCICTRL_ENAINCRXALIGN (1 << 29)
#define EHCICTRL_ENAINCR4 (1 << 28)
#define EHCICTRL_ENAINCR8 (1 << 27)
#define EHCICTRL_ENAINCR16 (1 << 26)
/* Register map for PHY control */
struct s5p_usb_phy {
unsigned int usbphyctrl0;
unsigned int usbphytune0;
unsigned int reserved1[2];
unsigned int hsicphyctrl1;
unsigned int hsicphytune1;
unsigned int reserved2[2];
unsigned int hsicphyctrl2;
unsigned int hsicphytune2;
unsigned int reserved3[2];
unsigned int ehcictrl;
unsigned int ohcictrl;
unsigned int usbotgsys;
unsigned int reserved4;
unsigned int usbotgtune;
};
/* Switch on the VBUS power. */
int board_usb_vbus_init(void);
#endif /* __ASM_ARM_ARCH_EXYNOS5_EHCI_S5P_H__ */

Some files were not shown because too many files have changed in this diff Show More