WIP: Initial ARMv7 architecture implementation in coreboot
The first ARMv7 CPU we're going to support is the Exynos 5250 used in the Google Snow ChromeBook. Change-Id: I4de8433bbc6202eb8fef2556a11186a3376d411b Signed-off-by: David Hendricks <dhendrix@chromium.org> Signed-off-by: Stefan Reinauer <reinauer@google.com> Signed-off-by: Ronald G. Minnich <rminnich@gmail.com> Reviewed-on: http://review.coreboot.org/2004 Tested-by: build bot (Jenkins)
This commit is contained in:
committed by
Ronald G. Minnich
parent
509f77277c
commit
52db0b9845
@ -1,3 +1,55 @@
|
||||
menu "Architecture (armv7)"
|
||||
|
||||
config SPL_BUILD
|
||||
bool "Build second-phase bootloader (SPL)"
|
||||
default y
|
||||
|
||||
config EABI_COMPAT
|
||||
bool "Toolchain is EABI compatible"
|
||||
default n
|
||||
|
||||
# Maximum reboot count
|
||||
# TODO: Improve description.
|
||||
config MAX_REBOOT_CNT
|
||||
int
|
||||
default 3
|
||||
|
||||
choice
|
||||
prompt "Bootblock behaviour"
|
||||
default ARM_BOOTBLOCK_SIMPLE
|
||||
|
||||
config ARM_BOOTBLOCK_SIMPLE
|
||||
bool "Always load fallback"
|
||||
|
||||
config ARM_BOOTBLOCK_NORMAL
|
||||
bool "Switch to normal if non-volatile memory says so"
|
||||
|
||||
endchoice
|
||||
|
||||
config BOOTBLOCK_SOURCE
|
||||
string
|
||||
default "bootblock_simple.c" if ARM_BOOTBLOCK_SIMPLE
|
||||
default "bootblock_normal.c" if ARM_BOOTBLOCK_NORMAL
|
||||
|
||||
config UPDATE_IMAGE
|
||||
bool "Update existing coreboot.rom image"
|
||||
default n
|
||||
depends on TINY_BOOTBLOCK
|
||||
help
|
||||
If this option is enabled, no new coreboot.rom file
|
||||
is created. Instead it is expected that there already
|
||||
is a suitable file for further processing.
|
||||
The bootblock will not be modified.
|
||||
|
||||
config BOOTBLOCK_SOC_INIT
|
||||
string
|
||||
|
||||
# FIXME: Should cache policy be set on a per-CPU basis?
|
||||
# FIXME(dhendrix): Stefan sayz to make a smart decision and not prompt the user.
|
||||
config ARM_DCACHE_POLICY_WRITEBACK
|
||||
bool y
|
||||
|
||||
config ARM_DCACHE_POLICY_WRITETHROUGH
|
||||
bool n
|
||||
|
||||
endmenu
|
||||
|
324
src/arch/armv7/Makefile.inc
Normal file
324
src/arch/armv7/Makefile.inc
Normal file
@ -0,0 +1,324 @@
|
||||
################################################################################
|
||||
##
|
||||
## This file is part of the coreboot project.
|
||||
##
|
||||
## Copyright (C) 2012 The ChromiumOS Authors
|
||||
## Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
||||
## Copyright (C) 2009-2010 coresystems GmbH
|
||||
## Copyright (C) 2009 Ronald G. Minnich
|
||||
##
|
||||
## 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; version 2 of the License.
|
||||
##
|
||||
## 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
# Take care of subdirectories
|
||||
subdirs-y += boot/
|
||||
subdirs-y += lib/
|
||||
# subdirs-y += smp/
|
||||
|
||||
################################################################################
|
||||
# Build the final rom image
|
||||
COREBOOT_ROM_DEPENDENCIES:=
|
||||
ifeq ($(CONFIG_PAYLOAD_ELF),y)
|
||||
COREBOOT_ROM_DEPENDENCIES+=$(CONFIG_PAYLOAD_FILE)
|
||||
endif
|
||||
#ifeq ($(CONFIG_AP_CODE_IN_CAR),y)
|
||||
#COREBOOT_ROM_DEPENDENCIES+=$(objcbfs)/coreboot_ap.elf
|
||||
#endif
|
||||
|
||||
extract_nth=$(word $(1), $(subst |, ,$(2)))
|
||||
|
||||
ifneq ($(CONFIG_UPDATE_IMAGE),y)
|
||||
prebuild-files = \
|
||||
$(foreach file,$(cbfs-files), \
|
||||
$(CBFSTOOL) $@.tmp \
|
||||
add$(if $(filter stage,$(call extract_nth,3,$(file))),-stage)$(if $(filter payload,$(call extract_nth,3,$(file))),-payload) \
|
||||
$(call extract_nth,1,$(file)) \
|
||||
$(call extract_nth,2,$(file)) $(if $(filter-out stage payload,$(call extract_nth,3,$(file))),$(call extract_nth,3,$(file))) \
|
||||
$(call extract_nth,4,$(file)) &&)
|
||||
prebuilt-files = $(foreach file,$(cbfs-files), $(call extract_nth,1,$(file)))
|
||||
|
||||
$(obj)/coreboot.pre1: $(objcbfs)/bootblock.bin $$(prebuilt-files) $(CBFSTOOL)
|
||||
$(CBFSTOOL) $@.tmp create -m armv7 -s $(CONFIG_COREBOOT_ROMSIZE_KB)K \
|
||||
-B $(objcbfs)/bootblock.bin -a 64 \
|
||||
-o $$(( $(CONFIG_ROM_SIZE) - $(CONFIG_CBFS_SIZE) ))
|
||||
$(prebuild-files) true
|
||||
mv $@.tmp $@
|
||||
else
|
||||
.PHONY: $(obj)/coreboot.pre1
|
||||
$(obj)/coreboot.pre1: $(CBFSTOOL)
|
||||
mv $(obj)/coreboot.rom $@
|
||||
endif
|
||||
|
||||
$(obj)/coreboot.rom: $(obj)/coreboot.pre $(objcbfs)/coreboot_ram.elf $(CBFSTOOL) $(call strip_quotes,$(COREBOOT_ROM_DEPENDENCIES))
|
||||
@printf " CBFS $(subst $(obj)/,,$(@))\n"
|
||||
cp $(obj)/coreboot.pre $@.tmp
|
||||
if [ -f $(objcbfs)/coreboot_ap.elf ]; \
|
||||
then \
|
||||
$(CBFSTOOL) $@.tmp add-stage -f $(objcbfs)/coreboot_ap.elf -n $(CONFIG_CBFS_PREFIX)/coreboot_ap -c $(CBFS_COMPRESS_FLAG) ; \
|
||||
fi
|
||||
$(CBFSTOOL) $@.tmp add-stage -f $(objcbfs)/coreboot_ram.elf -n $(CONFIG_CBFS_PREFIX)/coreboot_ram -c $(CBFS_COMPRESS_FLAG)
|
||||
ifeq ($(CONFIG_PAYLOAD_NONE),y)
|
||||
@printf " PAYLOAD \e[1;31mnone (as specified by user)\e[0m\n"
|
||||
endif
|
||||
ifeq ($(CONFIG_PAYLOAD_ELF),y)
|
||||
@printf " PAYLOAD $(CONFIG_PAYLOAD_FILE) (compression: $(CBFS_PAYLOAD_COMPRESS_NAME))\n"
|
||||
$(CBFSTOOL) $@.tmp add-payload $(CONFIG_PAYLOAD_FILE) $(CONFIG_CBFS_PREFIX)/payload $(CBFS_PAYLOAD_COMPRESS_FLAG)
|
||||
endif
|
||||
ifeq ($(CONFIG_INCLUDE_CONFIG_FILE),y)
|
||||
@printf " CONFIG $(DOTCONFIG)\n"
|
||||
if [ -f $(DOTCONFIG) ]; then \
|
||||
echo "# This image was built using git revision" `git rev-parse HEAD` > $(obj)/config.tmp ; \
|
||||
sed -e '/^#/d' -e '/^ *$$/d' $(DOTCONFIG) >> $(obj)/config.tmp ; \
|
||||
$(CBFSTOOL) $@.tmp add -f $(obj)/config.tmp -n config -t raw; rm -f $(obj)/config.tmp ; fi
|
||||
endif
|
||||
mv $@.tmp $@
|
||||
@printf " CBFSPRINT $(subst $(obj)/,,$(@))\n\n"
|
||||
$(CBFSTOOL) $@ print
|
||||
|
||||
bootsplash.jpg-file := $(call strip_quotes,$(CONFIG_BOOTSPLASH_FILE))
|
||||
bootsplash.jpg-type := bootsplash
|
||||
|
||||
################################################################################
|
||||
# armv7 specific tools
|
||||
|
||||
################################################################################
|
||||
# Common recipes for all stages
|
||||
|
||||
$(objcbfs)/%.bin: $(objcbfs)/%.elf
|
||||
@printf " OBJCOPY $(subst $(obj)/,,$(@))\n"
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
|
||||
$(objcbfs)/%.elf: $(objcbfs)/%.debug
|
||||
@printf " OBJCOPY $(subst $(obj)/,,$(@))\n"
|
||||
cp $< $@.tmp
|
||||
$(NM) -n $@.tmp | sort > $(basename $@).map
|
||||
$(OBJCOPY) --strip-debug $@.tmp
|
||||
$(OBJCOPY) --add-gnu-debuglink=$< $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
################################################################################
|
||||
# Build the coreboot_ram (stage 2)
|
||||
|
||||
$(objcbfs)/coreboot_ram.debug: $(objgenerated)/coreboot_ram.o $(src)/arch/armv7/coreboot_ram.ld
|
||||
@printf " CC $(subst $(obj)/,,$(@))\n"
|
||||
ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
|
||||
$(LD) -m armelf_linux_eabi -o $@ -L$(obj) $< -T $(src)/arch/armv7/coreboot_ram.ld
|
||||
else
|
||||
$(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(src)/arch/armv7/coreboot_ram.ld $<
|
||||
endif
|
||||
|
||||
$(objgenerated)/coreboot_ram.o: $$(ramstage-objs) $(LIBGCC_FILE_NAME)
|
||||
@printf " CC $(subst $(obj)/,,$(@))\n"
|
||||
ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
|
||||
$(LD) -m -m armelf_linux_eabi -r -o $@ --wrap __divdi3 --wrap __udivdi3 --wrap __moddi3 --wrap __umoddi3 --wrap __uidiv --wrap __do_div64 --start-group $(ramstage-objs) $(LIBGCC_FILE_NAME) --end-group
|
||||
else
|
||||
$(CC) -nostdlib -r -o $@ -Wl,--start-group $(ramstage-objs) $(LIBGCC_FILE_NAME) -Wl,--end-group
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Ramstage for AP CPU (AMD K8, obsolete?)
|
||||
|
||||
#$(objcbfs)/coreboot_ap.debug: $(objgenerated)/coreboot_ap.o $(src)/arch/armv7/init/ldscript_apc.lb
|
||||
# @printf " CC $(subst $(obj)/,,$(@))\n"
|
||||
# $(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(src)/arch/armv7/init/ldscript_apc.lb $<
|
||||
|
||||
#$(objgenerated)/coreboot_ap.o: $(src)/mainboard/$(MAINBOARDDIR)/ap_romstage.c $(OPTION_TABLE_H)
|
||||
# @printf " CC $(subst $(obj)/,,$(@))\n"
|
||||
# $(CC) -MMD $(CFLAGS) -I$(src) -D__PRE_RAM__ -I. -I$(obj) -c $< -o $@
|
||||
|
||||
################################################################################
|
||||
# done
|
||||
|
||||
# For various headers imported from Linux
|
||||
CFLAGS += -D__KERNEL__
|
||||
CFLAGS += -D__LINUX_ARM_ARCH__=7
|
||||
INCLUDES += -Isrc/include/linux
|
||||
INCLUDES += -Isrc/include/linux/uapi
|
||||
|
||||
# FIXME(dhendrix): trying to split start.S apart...
|
||||
crt0s = $(src)/arch/armv7/start.S
|
||||
#crt0s = $(src)/arch/armv7/romstage.S
|
||||
ldscripts =
|
||||
ldscripts += $(src)/arch/armv7/romstage.ld
|
||||
|
||||
#crt0s += $(src)/cpu/arm/fpu_enable.inc
|
||||
# FIXME: CONFIG_NEON or something similar for ARM?
|
||||
#ifeq ($(CONFIG_SSE),y)
|
||||
#crt0s += $(src)/cpu/arm/sse_enable.inc
|
||||
#endif
|
||||
|
||||
crt0s += $(cpu_incs)
|
||||
crt0s += $(cpu_incs-y)
|
||||
|
||||
ifeq ($(CONFIG_LLSHELL),y)
|
||||
crt0s += $(src)/arch/armv7/llshell/llshell.inc
|
||||
endif
|
||||
|
||||
crt0s += $(obj)/mainboard/$(MAINBOARDDIR)/romstage.inc
|
||||
|
||||
$(obj)/mainboard/$(MAINBOARDDIR)/romstage.pre.inc: $(src)/mainboard/$(MAINBOARDDIR)/romstage.c $(OPTION_TABLE_H) $(obj)/build.h $(obj)/config.h
|
||||
@printf " CC romstage.inc\n"
|
||||
$(CC) -MMD $(CFLAGS) -D__PRE_RAM__ -I$(src) -I. -I$(obj) -c -S $< -o $@
|
||||
|
||||
$(obj)/mainboard/$(MAINBOARDDIR)/romstage.inc: $(obj)/mainboard/$(MAINBOARDDIR)/romstage.pre.inc
|
||||
@printf " POST romstage.inc\n"
|
||||
sed -e 's/\.rodata/.rom.data/g' -e 's/\^\.text/.section .rom.text/g' \
|
||||
-e 's/\^\.section \.text/.section .rom.text/g' $^ > $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
# Things that appear in every board
|
||||
romstage-srcs += $(objgenerated)/crt0.s
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/mainboard.c
|
||||
ifeq ($(CONFIG_GENERATE_PIRQ_TABLE),y)
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/irq_tables.c
|
||||
endif
|
||||
ifeq ($(CONFIG_BOARD_HAS_HARD_RESET),y)
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/reset.c
|
||||
endif
|
||||
ifeq ($(CONFIG_GENERATE_ACPI_TABLES),y)
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/acpi_tables.c
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/dsdt.asl
|
||||
# make doesn't have arithmetic operators or greater-than comparisons
|
||||
ifeq ($(subst 5,4,$(CONFIG_ACPI_SSDTX_NUM)),4)
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/ssdt2.asl
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/ssdt3.asl
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/ssdt4.asl
|
||||
endif
|
||||
ifeq ($(CONFIG_ACPI_SSDTX_NUM),5)
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/ssdt5.asl
|
||||
endif
|
||||
ifeq ($(CONFIG_BOARD_HAS_FADT),y)
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/fadt.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_HAVE_BUS_CONFIG),y)
|
||||
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/get_bus_conf.c
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Build the final rom image
|
||||
|
||||
$(obj)/coreboot.pre: $(objcbfs)/romstage_xip.elf $(obj)/coreboot.pre1 $(CBFSTOOL)
|
||||
@printf " CBFS $(subst $(obj)/,,$(@))\n"
|
||||
cp $(obj)/coreboot.pre1 $@.tmp
|
||||
$(CBFSTOOL) $@.tmp add-stage \
|
||||
-f $(objcbfs)/romstage_xip.elf \
|
||||
-n $(CONFIG_CBFS_PREFIX)/romstage -c none \
|
||||
-b $(shell cat $(objcbfs)/base_xip.txt)
|
||||
mv $@.tmp $@
|
||||
|
||||
################################################################################
|
||||
# Build the bootblock
|
||||
|
||||
#bootblock_lds = $(src)/arch/armv7/ldscript_fallback_cbfs.lb
|
||||
bootblock_lds = $(src)/arch/armv7/lib/id.lds
|
||||
#bootblock_lds = $(src)/arch/armv7/romstage.ld
|
||||
bootblock_lds += $(chipset_bootblock_lds)
|
||||
|
||||
bootblock_inc += $(src)/arch/armv7/lib/id.inc
|
||||
bootblock_inc += $(chipset_bootblock_inc)
|
||||
|
||||
# FIXME: CONFIG_NEON or something similar for ARM?
|
||||
#ifeq ($(CONFIG_SSE),y)
|
||||
#bootblock_inc += $(src)/cpu/x86/sse_enable.inc
|
||||
#endif
|
||||
#bootblock_inc += $(objgenerated)/bootblock.inc
|
||||
|
||||
$(objgenerated)/bootblock.ld: $$(bootblock_lds) $(obj)/ldoptions
|
||||
@printf " GEN $(subst $(obj)/,,$(@))\n"
|
||||
printf '$(foreach ldscript,ldoptions $(bootblock_lds),INCLUDE "$(ldscript)"\n)' > $@
|
||||
|
||||
$(objgenerated)/bootblock_inc.S: $$(bootblock_inc)
|
||||
@printf " GEN $(subst $(obj)/,,$(@))\n"
|
||||
printf '$(foreach crt0,$(bootblock_inc),#include "$(crt0)"\n)' > $@
|
||||
|
||||
$(objgenerated)/bootblock.o: $(objgenerated)/bootblock.s
|
||||
@printf " CC $(subst $(obj)/,,$(@))\n"
|
||||
$(CC) -Wa,-acdlns -c -o $@ $< > $(basename $@).disasm
|
||||
|
||||
$(objgenerated)/bootblock.s: $(objgenerated)/bootblock_inc.S $(obj)/config.h $(obj)/build.h
|
||||
@printf " CC $(subst $(obj)/,,$(@))\n"
|
||||
$(CC) -MMD -x assembler-with-cpp -E -I$(src)/include -I$(src)/arch/armv7/include -I$(obj) -include $(obj)/build.h -include $(obj)/config.h -I. -I$(src) $< -o $@
|
||||
|
||||
#$(objgenerated)/bootblock.inc: $(src)/arch/armv7/init/$(subst ",,$(CONFIG_BOOTBLOCK_SOURCE)) $(objutil)/romcc/romcc $(OPTION_TABLE_H)
|
||||
# @printf " ROMCC $(subst $(obj)/,,$(@))\n"
|
||||
# $(CC) $(INCLUDES) -MM -MT$(objgenerated)/bootblock.inc \
|
||||
# $< > $(objgenerated)/bootblock.inc.d
|
||||
# $(ROMCC) -c -S $(bootblock_romccflags) $(ROMCCFLAGS) -I. $(INCLUDES) $< -o $@
|
||||
|
||||
$(objcbfs)/bootblock.debug: $(objgenerated)/bootblock.o $(objgenerated)/bootblock.ld
|
||||
@printf " LINK $(subst $(obj)/,,$(@))\n"
|
||||
ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
|
||||
$(LD) -m armelf_linux_eabi -static -o $@.tmp -L$(obj) $< -T $(objgenerated)/bootblock.ld
|
||||
else
|
||||
$(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(objgenerated)/bootblock.ld $<
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Build the romstage
|
||||
|
||||
# FIXME(dhendrix): added debug printfs
|
||||
$(objcbfs)/romstage_null.debug: $$(romstage-objs) $(objgenerated)/romstage_null.ld
|
||||
@printf " LINK $(subst $(obj)/,,$(@))\n"
|
||||
ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
|
||||
$(LD) -nostdlib -nostartfiles -static -o $@ -L$(obj) $(romstage-objs) -T $(objgenerated)/romstage_null.ld
|
||||
else
|
||||
$(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(objgenerated)/romstage_null.ld -Wl,--start-group $(romstage-objs) $(LIBGCC_FILE_NAME) -Wl,--end-group
|
||||
endif
|
||||
|
||||
$(objcbfs)/romstage_xip.debug: $$(romstage-objs) $(objgenerated)/romstage_xip.ld
|
||||
@printf " LINK $(subst $(obj)/,,$(@))\n"
|
||||
ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
|
||||
$(LD) -nostdlib -nostartfiles -static -o $@ -L$(obj) $(romstage-objs) -T $(objgenerated)/romstage_xip.ld
|
||||
else
|
||||
$(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(objgenerated)/romstage_xip.ld -Wl,--start-group $(romstage-objs) $(LIBGCC_FILE_NAME) -Wl,--end-group
|
||||
endif
|
||||
|
||||
$(objgenerated)/romstage_null.ld: $$(ldscripts) $(obj)/ldoptions
|
||||
@printf " GEN $(subst $(obj)/,,$(@))\n"
|
||||
rm -f $@
|
||||
printf "ROMSTAGE_BASE = 0x0;\n" > $@.tmp
|
||||
printf '$(foreach ldscript,ldoptions $(ldscripts),INCLUDE "$(ldscript:$(obj)/%=%)"\n)' >> $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
$(objgenerated)/romstage_xip.ld: $(objgenerated)/romstage_null.ld $(objcbfs)/base_xip.txt
|
||||
@printf " GEN $(subst $(obj)/,,$(@))\n"
|
||||
rm -f $@
|
||||
sed -e 's/^/ROMSTAGE_BASE = /g' -e 's/$$/;/g' $(objcbfs)/base_xip.txt > $@.tmp
|
||||
sed -e '/ROMSTAGE_BASE/d' $(objgenerated)/romstage_null.ld >> $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
$(objcbfs)/base_xip.txt: $(obj)/coreboot.pre1 $(objcbfs)/romstage_null.bin
|
||||
@printf " generating base_xip.txt\n"
|
||||
rm -f $@
|
||||
$(CBFSTOOL) $(obj)/coreboot.pre1 locate -f $(objcbfs)/romstage_null.bin -n $(CONFIG_CBFS_PREFIX)/romstage -a $(CONFIG_XIP_ROM_SIZE) > $@.tmp \
|
||||
|| { echo "The romstage is larger than XIP size. Please expand the CONFIG_XIP_ROM_SIZE" ; exit 1; }
|
||||
sed -e 's/^/0x/g' $@.tmp > $@.tmp2
|
||||
rm $@.tmp
|
||||
mv $@.tmp2 $@
|
||||
|
||||
$(objgenerated)/crt0.romstage.S: $$(crt0s)
|
||||
@printf " GEN $(subst $(obj)/,,$(@))\n"
|
||||
printf '$(foreach crt0,$(crt0s),#include "$(crt0:$(obj)/%=%)"\n)' > $@
|
||||
|
||||
$(objgenerated)/crt0.romstage.o: $(objgenerated)/crt0.s
|
||||
@printf " CC $(subst $(obj)/,,$(@))\n"
|
||||
$(CC) -Wa,-acdlns -c -o $@ $< > $(basename $@).disasm
|
||||
|
||||
$(objgenerated)/crt0.s: $(objgenerated)/crt0.romstage.S $(obj)/config.h $(obj)/build.h
|
||||
@printf " CC $(subst $(obj)/,,$(@))\n"
|
||||
$(CC) -MMD -x assembler-with-cpp -E -I$(src)/include -I$(src)/arch/armv7/include -I$(obj) -include $(obj)/config.h -include $(obj)/build.h -I. -I$(src) $< -o $@
|
||||
|
13
src/arch/armv7/boot/Makefile.inc
Normal file
13
src/arch/armv7/boot/Makefile.inc
Normal file
@ -0,0 +1,13 @@
|
||||
ramstage-y += boot.c
|
||||
ramstage-y += coreboot_table.c
|
||||
#ramstage-$(CONFIG_MULTIBOOT) += multiboot.c
|
||||
ramstage-y += tables.c
|
||||
#ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c
|
||||
#ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpigen.c
|
||||
#ramstage-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.S
|
||||
|
||||
#FIXME(dhendrix): is there anything preventing multiboot from
|
||||
#working on ARM?
|
||||
|
||||
$(obj)/arch/armv7/boot/coreboot_table.ramstage.o : $(OPTION_TABLE_H)
|
||||
#$(obj)/arch/x86/boot/smbios.ramstage.o: $(obj)/build.h
|
791
src/arch/armv7/boot/acpi.c
Normal file
791
src/arch/armv7/boot/acpi.c
Normal file
@ -0,0 +1,791 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* coreboot ACPI Table support
|
||||
* written by Stefan Reinauer <stepan@openbios.org>
|
||||
*
|
||||
* Copyright (C) 2004 SUSE LINUX AG
|
||||
* Copyright (C) 2005-2009 coresystems GmbH
|
||||
*
|
||||
* ACPI FADT, FACS, and DSDT table support added by
|
||||
* Nick Barker <nick.barker9@btinternet.com>, and those portions
|
||||
* Copyright (C) 2004 Nick Barker
|
||||
*
|
||||
* Copyright (C) 2005 ADVANCED MICRO DEVICES, INC. All Rights Reserved.
|
||||
* 2005.9 yhlu add SRAT table generation
|
||||
*/
|
||||
|
||||
/*
|
||||
* Each system port implementing ACPI has to provide two functions:
|
||||
*
|
||||
* write_acpi_tables()
|
||||
* acpi_dump_apics()
|
||||
*
|
||||
* See Kontron 986LCD-M port for a good example of an ACPI implementation
|
||||
* in coreboot.
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <string.h>
|
||||
#include <arch/acpi.h>
|
||||
#include <arch/acpigen.h>
|
||||
#include <device/pci.h>
|
||||
#include <cbmem.h>
|
||||
#include <cpu/x86/lapic_def.h>
|
||||
#include <cpu/cpu.h>
|
||||
#if CONFIG_COLLECT_TIMESTAMPS
|
||||
#include <timestamp.h>
|
||||
#endif
|
||||
|
||||
/* FIXME: Kconfig doesn't support overridable defaults :-( */
|
||||
#ifndef CONFIG_HPET_MIN_TICKS
|
||||
#define CONFIG_HPET_MIN_TICKS 0x1000
|
||||
#endif
|
||||
|
||||
u8 acpi_checksum(u8 *table, u32 length)
|
||||
{
|
||||
u8 ret = 0;
|
||||
while (length--) {
|
||||
ret += *table;
|
||||
table++;
|
||||
}
|
||||
return -ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
|
||||
* and checksum.
|
||||
*/
|
||||
void acpi_add_table(acpi_rsdp_t *rsdp, void *table)
|
||||
{
|
||||
int i, entries_num;
|
||||
acpi_rsdt_t *rsdt;
|
||||
acpi_xsdt_t *xsdt = NULL;
|
||||
|
||||
/* The RSDT is mandatory... */
|
||||
rsdt = (acpi_rsdt_t *)rsdp->rsdt_address;
|
||||
|
||||
/* ...while the XSDT is not. */
|
||||
if (rsdp->xsdt_address)
|
||||
xsdt = (acpi_xsdt_t *)((u32)rsdp->xsdt_address);
|
||||
|
||||
/* This should always be MAX_ACPI_TABLES. */
|
||||
entries_num = ARRAY_SIZE(rsdt->entry);
|
||||
|
||||
for (i = 0; i < entries_num; i++) {
|
||||
if (rsdt->entry[i] == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= entries_num) {
|
||||
printk(BIOS_ERR, "ACPI: Error: Could not add ACPI table, "
|
||||
"too many tables.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add table to the RSDT. */
|
||||
rsdt->entry[i] = (u32)table;
|
||||
|
||||
/* Fix RSDT length or the kernel will assume invalid entries. */
|
||||
rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1));
|
||||
|
||||
/* Re-calculate checksum. */
|
||||
rsdt->header.checksum = 0; /* Hope this won't get optimized away */
|
||||
rsdt->header.checksum = acpi_checksum((u8 *)rsdt, rsdt->header.length);
|
||||
|
||||
/*
|
||||
* And now the same thing for the XSDT. We use the same index as for
|
||||
* now we want the XSDT and RSDT to always be in sync in coreboot.
|
||||
*/
|
||||
if (xsdt) {
|
||||
/* Add table to the XSDT. */
|
||||
xsdt->entry[i] = (u64)(u32)table;
|
||||
|
||||
/* Fix XSDT length. */
|
||||
xsdt->header.length = sizeof(acpi_header_t) +
|
||||
(sizeof(u64) * (i + 1));
|
||||
|
||||
/* Re-calculate checksum. */
|
||||
xsdt->header.checksum = 0;
|
||||
xsdt->header.checksum = acpi_checksum((u8 *)xsdt,
|
||||
xsdt->header.length);
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "ACPI: added table %d/%d, length now %d\n",
|
||||
i + 1, entries_num, rsdt->header.length);
|
||||
}
|
||||
|
||||
int acpi_create_mcfg_mmconfig(acpi_mcfg_mmconfig_t *mmconfig, u32 base,
|
||||
u16 seg_nr, u8 start, u8 end)
|
||||
{
|
||||
mmconfig->base_address = base;
|
||||
mmconfig->base_reserved = 0;
|
||||
mmconfig->pci_segment_group_number = seg_nr;
|
||||
mmconfig->start_bus_number = start;
|
||||
mmconfig->end_bus_number = end;
|
||||
|
||||
return sizeof(acpi_mcfg_mmconfig_t);
|
||||
}
|
||||
|
||||
int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic)
|
||||
{
|
||||
lapic->type = 0; /* Local APIC structure */
|
||||
lapic->length = sizeof(acpi_madt_lapic_t);
|
||||
lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
|
||||
lapic->processor_id = cpu;
|
||||
lapic->apic_id = apic;
|
||||
|
||||
return lapic->length;
|
||||
}
|
||||
|
||||
unsigned long acpi_create_madt_lapics(unsigned long current)
|
||||
{
|
||||
device_t cpu;
|
||||
int index = 0;
|
||||
|
||||
for (cpu = all_devices; cpu; cpu = cpu->next) {
|
||||
if ((cpu->path.type != DEVICE_PATH_APIC) ||
|
||||
(cpu->bus->dev->path.type != DEVICE_PATH_APIC_CLUSTER)) {
|
||||
continue;
|
||||
}
|
||||
if (!cpu->enabled)
|
||||
continue;
|
||||
current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current,
|
||||
index, cpu->path.apic.apic_id);
|
||||
index++;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,
|
||||
u32 gsi_base)
|
||||
{
|
||||
ioapic->type = 1; /* I/O APIC structure */
|
||||
ioapic->length = sizeof(acpi_madt_ioapic_t);
|
||||
ioapic->reserved = 0x00;
|
||||
ioapic->gsi_base = gsi_base;
|
||||
ioapic->ioapic_id = id;
|
||||
ioapic->ioapic_addr = addr;
|
||||
|
||||
return ioapic->length;
|
||||
}
|
||||
|
||||
int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
|
||||
u8 bus, u8 source, u32 gsirq, u16 flags)
|
||||
{
|
||||
irqoverride->type = 2; /* Interrupt source override */
|
||||
irqoverride->length = sizeof(acpi_madt_irqoverride_t);
|
||||
irqoverride->bus = bus;
|
||||
irqoverride->source = source;
|
||||
irqoverride->gsirq = gsirq;
|
||||
irqoverride->flags = flags;
|
||||
|
||||
return irqoverride->length;
|
||||
}
|
||||
|
||||
int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
|
||||
u16 flags, u8 lint)
|
||||
{
|
||||
lapic_nmi->type = 4; /* Local APIC NMI structure */
|
||||
lapic_nmi->length = sizeof(acpi_madt_lapic_nmi_t);
|
||||
lapic_nmi->flags = flags;
|
||||
lapic_nmi->processor_id = cpu;
|
||||
lapic_nmi->lint = lint;
|
||||
|
||||
return lapic_nmi->length;
|
||||
}
|
||||
|
||||
void acpi_create_madt(acpi_madt_t *madt)
|
||||
{
|
||||
acpi_header_t *header = &(madt->header);
|
||||
unsigned long current = (unsigned long)madt + sizeof(acpi_madt_t);
|
||||
|
||||
memset((void *)madt, 0, sizeof(acpi_madt_t));
|
||||
|
||||
/* Fill out header fields. */
|
||||
memcpy(header->signature, "APIC", 4);
|
||||
memcpy(header->oem_id, OEM_ID, 6);
|
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
||||
memcpy(header->asl_compiler_id, ASLC, 4);
|
||||
|
||||
header->length = sizeof(acpi_madt_t);
|
||||
header->revision = 1; /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
|
||||
|
||||
madt->lapic_addr = LOCAL_APIC_ADDR;
|
||||
madt->flags = 0x1; /* PCAT_COMPAT */
|
||||
|
||||
current = acpi_fill_madt(current);
|
||||
|
||||
/* (Re)calculate length and checksum. */
|
||||
header->length = current - (unsigned long)madt;
|
||||
|
||||
header->checksum = acpi_checksum((void *)madt, header->length);
|
||||
}
|
||||
|
||||
/* MCFG is defined in the PCI Firmware Specification 3.0. */
|
||||
void acpi_create_mcfg(acpi_mcfg_t *mcfg)
|
||||
{
|
||||
acpi_header_t *header = &(mcfg->header);
|
||||
unsigned long current = (unsigned long)mcfg + sizeof(acpi_mcfg_t);
|
||||
|
||||
memset((void *)mcfg, 0, sizeof(acpi_mcfg_t));
|
||||
|
||||
/* Fill out header fields. */
|
||||
memcpy(header->signature, "MCFG", 4);
|
||||
memcpy(header->oem_id, OEM_ID, 6);
|
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
||||
memcpy(header->asl_compiler_id, ASLC, 4);
|
||||
|
||||
header->length = sizeof(acpi_mcfg_t);
|
||||
header->revision = 1;
|
||||
|
||||
current = acpi_fill_mcfg(current);
|
||||
|
||||
/* (Re)calculate length and checksum. */
|
||||
header->length = current - (unsigned long)mcfg;
|
||||
header->checksum = acpi_checksum((void *)mcfg, header->length);
|
||||
}
|
||||
|
||||
/*
|
||||
* This can be overriden by platform ACPI setup code, if it calls
|
||||
* acpi_create_ssdt_generator().
|
||||
*/
|
||||
unsigned long __attribute__((weak)) acpi_fill_ssdt_generator(
|
||||
unsigned long current, const char *oem_table_id)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char *oem_table_id)
|
||||
{
|
||||
unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t);
|
||||
|
||||
memset((void *)ssdt, 0, sizeof(acpi_header_t));
|
||||
|
||||
memcpy(&ssdt->signature, "SSDT", 4);
|
||||
ssdt->revision = 2; /* ACPI 1.0/2.0: ?, ACPI 3.0/4.0: 2 */
|
||||
memcpy(&ssdt->oem_id, OEM_ID, 6);
|
||||
memcpy(&ssdt->oem_table_id, oem_table_id, 8);
|
||||
ssdt->oem_revision = 42;
|
||||
memcpy(&ssdt->asl_compiler_id, ASLC, 4);
|
||||
ssdt->asl_compiler_revision = 42;
|
||||
ssdt->length = sizeof(acpi_header_t);
|
||||
|
||||
acpigen_set_current((char *) current);
|
||||
current = acpi_fill_ssdt_generator(current, oem_table_id);
|
||||
|
||||
/* (Re)calculate length and checksum. */
|
||||
ssdt->length = current - (unsigned long)ssdt;
|
||||
ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length);
|
||||
}
|
||||
|
||||
int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic)
|
||||
{
|
||||
memset((void *)lapic, 0, sizeof(acpi_srat_lapic_t));
|
||||
|
||||
lapic->type = 0; /* Processor local APIC/SAPIC affinity structure */
|
||||
lapic->length = sizeof(acpi_srat_lapic_t);
|
||||
lapic->flags = (1 << 0); /* Enabled (the use of this structure). */
|
||||
lapic->proximity_domain_7_0 = node;
|
||||
/* TODO: proximity_domain_31_8, local SAPIC EID, clock domain. */
|
||||
lapic->apic_id = apic;
|
||||
|
||||
return lapic->length;
|
||||
}
|
||||
|
||||
int acpi_create_srat_mem(acpi_srat_mem_t *mem, u8 node, u32 basek, u32 sizek,
|
||||
u32 flags)
|
||||
{
|
||||
mem->type = 1; /* Memory affinity structure */
|
||||
mem->length = sizeof(acpi_srat_mem_t);
|
||||
mem->base_address_low = (basek << 10);
|
||||
mem->base_address_high = (basek >> (32 - 10));
|
||||
mem->length_low = (sizek << 10);
|
||||
mem->length_high = (sizek >> (32 - 10));
|
||||
mem->proximity_domain = node;
|
||||
mem->flags = flags;
|
||||
|
||||
return mem->length;
|
||||
}
|
||||
|
||||
/* http://www.microsoft.com/whdc/system/sysinternals/sratdwn.mspx */
|
||||
void acpi_create_srat(acpi_srat_t *srat)
|
||||
{
|
||||
acpi_header_t *header = &(srat->header);
|
||||
unsigned long current = (unsigned long)srat + sizeof(acpi_srat_t);
|
||||
|
||||
memset((void *)srat, 0, sizeof(acpi_srat_t));
|
||||
|
||||
/* Fill out header fields. */
|
||||
memcpy(header->signature, "SRAT", 4);
|
||||
memcpy(header->oem_id, OEM_ID, 6);
|
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
||||
memcpy(header->asl_compiler_id, ASLC, 4);
|
||||
|
||||
header->length = sizeof(acpi_srat_t);
|
||||
header->revision = 1; /* ACPI 1.0: N/A, 2.0: 1, 3.0: 2, 4.0: 3 */
|
||||
|
||||
srat->resv = 1; /* Spec: Reserved to 1 for backwards compatibility. */
|
||||
|
||||
current = acpi_fill_srat(current);
|
||||
|
||||
/* (Re)calculate length and checksum. */
|
||||
header->length = current - (unsigned long)srat;
|
||||
header->checksum = acpi_checksum((void *)srat, header->length);
|
||||
}
|
||||
|
||||
unsigned long __attribute__((weak)) acpi_fill_dmar(unsigned long current)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
void acpi_create_dmar(acpi_dmar_t *dmar)
|
||||
{
|
||||
acpi_header_t *header = &(dmar->header);
|
||||
unsigned long current = (unsigned long)dmar + sizeof(acpi_dmar_t);
|
||||
|
||||
memset((void *)dmar, 0, sizeof(acpi_dmar_t));
|
||||
|
||||
/* Fill out header fields. */
|
||||
memcpy(header->signature, "DMAR", 4);
|
||||
memcpy(header->oem_id, OEM_ID, 6);
|
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
||||
memcpy(header->asl_compiler_id, ASLC, 4);
|
||||
|
||||
header->length = sizeof(acpi_dmar_t);
|
||||
header->revision = 1;
|
||||
|
||||
dmar->host_address_width = 40 - 1; /* FIXME: == MTRR size? */
|
||||
dmar->flags = 0;
|
||||
|
||||
current = acpi_fill_dmar(current);
|
||||
|
||||
/* (Re)calculate length and checksum. */
|
||||
header->length = current - (unsigned long)dmar;
|
||||
header->checksum = acpi_checksum((void *)dmar, header->length);
|
||||
}
|
||||
|
||||
unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags,
|
||||
u16 segment, u32 bar)
|
||||
{
|
||||
dmar_entry_t *drhd = (dmar_entry_t *)current;
|
||||
memset(drhd, 0, sizeof(*drhd));
|
||||
drhd->type = DMAR_DRHD;
|
||||
drhd->length = sizeof(*drhd); /* will be fixed up later */
|
||||
drhd->flags = flags;
|
||||
drhd->segment = segment;
|
||||
drhd->bar = bar;
|
||||
|
||||
return drhd->length;
|
||||
}
|
||||
|
||||
void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current)
|
||||
{
|
||||
dmar_entry_t *drhd = (dmar_entry_t *)base;
|
||||
drhd->length = current - base;
|
||||
}
|
||||
|
||||
unsigned long acpi_create_dmar_drhd_ds_pci(unsigned long current, u8 segment,
|
||||
u8 dev, u8 fn)
|
||||
{
|
||||
dev_scope_t *ds = (dev_scope_t *)current;
|
||||
memset(ds, 0, sizeof(*ds));
|
||||
ds->type = SCOPE_PCI_ENDPOINT;
|
||||
ds->length = sizeof(*ds) + 2; /* we don't support longer paths yet */
|
||||
ds->start_bus = segment;
|
||||
ds->path[0].dev = dev;
|
||||
ds->path[0].fn = fn;
|
||||
|
||||
return ds->length;
|
||||
}
|
||||
|
||||
/* http://h21007.www2.hp.com/portal/download/files/unprot/Itanium/slit.pdf */
|
||||
void acpi_create_slit(acpi_slit_t *slit)
|
||||
{
|
||||
acpi_header_t *header = &(slit->header);
|
||||
unsigned long current = (unsigned long)slit + sizeof(acpi_slit_t);
|
||||
|
||||
memset((void *)slit, 0, sizeof(acpi_slit_t));
|
||||
|
||||
/* Fill out header fields. */
|
||||
memcpy(header->signature, "SLIT", 4);
|
||||
memcpy(header->oem_id, OEM_ID, 6);
|
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
||||
memcpy(header->asl_compiler_id, ASLC, 4);
|
||||
|
||||
header->length = sizeof(acpi_slit_t);
|
||||
header->revision = 1; /* ACPI 1.0: N/A, ACPI 2.0/3.0/4.0: 1 */
|
||||
|
||||
current = acpi_fill_slit(current);
|
||||
|
||||
/* (Re)calculate length and checksum. */
|
||||
header->length = current - (unsigned long)slit;
|
||||
header->checksum = acpi_checksum((void *)slit, header->length);
|
||||
}
|
||||
|
||||
/* http://www.intel.com/hardwaredesign/hpetspec_1.pdf */
|
||||
void acpi_create_hpet(acpi_hpet_t *hpet)
|
||||
{
|
||||
acpi_header_t *header = &(hpet->header);
|
||||
acpi_addr_t *addr = &(hpet->addr);
|
||||
|
||||
memset((void *)hpet, 0, sizeof(acpi_hpet_t));
|
||||
|
||||
/* Fill out header fields. */
|
||||
memcpy(header->signature, "HPET", 4);
|
||||
memcpy(header->oem_id, OEM_ID, 6);
|
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
||||
memcpy(header->asl_compiler_id, ASLC, 4);
|
||||
|
||||
header->length = sizeof(acpi_hpet_t);
|
||||
header->revision = 1; /* Currently 1. Table added in ACPI 2.0. */
|
||||
|
||||
/* Fill out HPET address. */
|
||||
addr->space_id = 0; /* Memory */
|
||||
addr->bit_width = 64;
|
||||
addr->bit_offset = 0;
|
||||
addr->addrl = CONFIG_HPET_ADDRESS & 0xffffffff;
|
||||
addr->addrh = ((unsigned long long)CONFIG_HPET_ADDRESS) >> 32;
|
||||
|
||||
hpet->id = *(unsigned int*)CONFIG_HPET_ADDRESS;
|
||||
hpet->number = 0;
|
||||
hpet->min_tick = CONFIG_HPET_MIN_TICKS;
|
||||
|
||||
header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
|
||||
}
|
||||
|
||||
void acpi_create_facs(acpi_facs_t *facs)
|
||||
{
|
||||
memset((void *)facs, 0, sizeof(acpi_facs_t));
|
||||
|
||||
memcpy(facs->signature, "FACS", 4);
|
||||
facs->length = sizeof(acpi_facs_t);
|
||||
facs->hardware_signature = 0;
|
||||
facs->firmware_waking_vector = 0;
|
||||
facs->global_lock = 0;
|
||||
facs->flags = 0;
|
||||
facs->x_firmware_waking_vector_l = 0;
|
||||
facs->x_firmware_waking_vector_h = 0;
|
||||
facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */
|
||||
}
|
||||
|
||||
void acpi_write_rsdt(acpi_rsdt_t *rsdt)
|
||||
{
|
||||
acpi_header_t *header = &(rsdt->header);
|
||||
|
||||
/* Fill out header fields. */
|
||||
memcpy(header->signature, "RSDT", 4);
|
||||
memcpy(header->oem_id, OEM_ID, 6);
|
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
||||
memcpy(header->asl_compiler_id, ASLC, 4);
|
||||
|
||||
header->length = sizeof(acpi_rsdt_t);
|
||||
header->revision = 1; /* ACPI 1.0/2.0/3.0/4.0: 1 */
|
||||
|
||||
/* Entries are filled in later, we come with an empty set. */
|
||||
|
||||
/* Fix checksum. */
|
||||
header->checksum = acpi_checksum((void *)rsdt, sizeof(acpi_rsdt_t));
|
||||
}
|
||||
|
||||
void acpi_write_xsdt(acpi_xsdt_t *xsdt)
|
||||
{
|
||||
acpi_header_t *header = &(xsdt->header);
|
||||
|
||||
/* Fill out header fields. */
|
||||
memcpy(header->signature, "XSDT", 4);
|
||||
memcpy(header->oem_id, OEM_ID, 6);
|
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
||||
memcpy(header->asl_compiler_id, ASLC, 4);
|
||||
|
||||
header->length = sizeof(acpi_xsdt_t);
|
||||
header->revision = 1; /* ACPI 1.0: N/A, 2.0/3.0/4.0: 1 */
|
||||
|
||||
/* Entries are filled in later, we come with an empty set. */
|
||||
|
||||
/* Fix checksum. */
|
||||
header->checksum = acpi_checksum((void *)xsdt, sizeof(acpi_xsdt_t));
|
||||
}
|
||||
|
||||
void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt, acpi_xsdt_t *xsdt)
|
||||
{
|
||||
memset(rsdp, 0, sizeof(acpi_rsdp_t));
|
||||
|
||||
memcpy(rsdp->signature, RSDP_SIG, 8);
|
||||
memcpy(rsdp->oem_id, OEM_ID, 6);
|
||||
|
||||
rsdp->length = sizeof(acpi_rsdp_t);
|
||||
rsdp->rsdt_address = (u32)rsdt;
|
||||
|
||||
/*
|
||||
* Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2.
|
||||
*
|
||||
* Some OSes expect an XSDT to be present for RSD PTR revisions >= 2.
|
||||
* If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR
|
||||
* revision 0).
|
||||
*/
|
||||
if (xsdt == NULL) {
|
||||
rsdp->revision = 0;
|
||||
} else {
|
||||
rsdp->xsdt_address = (u64)(u32)xsdt;
|
||||
rsdp->revision = 2;
|
||||
}
|
||||
|
||||
/* Calculate checksums. */
|
||||
rsdp->checksum = acpi_checksum((void *)rsdp, 20);
|
||||
rsdp->ext_checksum = acpi_checksum((void *)rsdp, sizeof(acpi_rsdp_t));
|
||||
}
|
||||
|
||||
unsigned long __attribute__((weak)) acpi_fill_hest(acpi_hest_t *hest)
|
||||
{
|
||||
return (unsigned long)hest;
|
||||
}
|
||||
|
||||
unsigned long acpi_create_hest_error_source(acpi_hest_t *hest, acpi_hest_esd_t *esd, u16 type, void *data, u16 data_len)
|
||||
{
|
||||
acpi_header_t *header = &(hest->header);
|
||||
acpi_hest_hen_t *hen;
|
||||
void *pos;
|
||||
u16 len;
|
||||
|
||||
pos = esd;
|
||||
memset(pos, 0, sizeof(acpi_hest_esd_t));
|
||||
len = 0;
|
||||
esd->type = type; /* MCE */
|
||||
esd->source_id = hest->error_source_count;
|
||||
esd->flags = 0; /* FIRMWARE_FIRST */
|
||||
esd->enabled = 1;
|
||||
esd->prealloc_erecords = 1;
|
||||
esd->max_section_per_record = 0x1;
|
||||
|
||||
len += sizeof(acpi_hest_esd_t);
|
||||
pos = esd + 1;
|
||||
|
||||
switch (type) {
|
||||
case 0: /* MCE */
|
||||
break;
|
||||
case 1: /* CMC */
|
||||
hen = (acpi_hest_hen_t *) (pos);
|
||||
memset(pos, 0, sizeof(acpi_hest_hen_t));
|
||||
hen->type = 3; /* SCI? */
|
||||
hen->length = sizeof(acpi_hest_hen_t);
|
||||
hen->conf_we = 0; /* Configuration Write Enable. */
|
||||
hen->poll_interval = 0;
|
||||
hen->vector = 0;
|
||||
hen->sw2poll_threshold_val = 0;
|
||||
hen->sw2poll_threshold_win = 0;
|
||||
hen->error_threshold_val = 0;
|
||||
hen->error_threshold_win = 0;
|
||||
len += sizeof(acpi_hest_hen_t);
|
||||
pos = hen + 1;
|
||||
break;
|
||||
case 2: /* NMI */
|
||||
case 6: /* AER Root Port */
|
||||
case 7: /* AER Endpoint */
|
||||
case 8: /* AER Bridge */
|
||||
case 9: /* Generic Hardware Error Source. */
|
||||
/* TODO: */
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "Invalid type of Error Source.");
|
||||
break;
|
||||
}
|
||||
hest->error_source_count ++;
|
||||
|
||||
memcpy(pos, data, data_len);
|
||||
len += data_len;
|
||||
header->length += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ACPI 4.0 */
|
||||
void acpi_write_hest(acpi_hest_t *hest)
|
||||
{
|
||||
acpi_header_t *header = &(hest->header);
|
||||
|
||||
memset(hest, 0, sizeof(acpi_hest_t));
|
||||
|
||||
memcpy(header->signature, "HEST", 4);
|
||||
memcpy(header->oem_id, OEM_ID, 6);
|
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
||||
memcpy(header->asl_compiler_id, ASLC, 4);
|
||||
header->length += sizeof(acpi_hest_t);
|
||||
header->revision = 1;
|
||||
|
||||
acpi_fill_hest(hest);
|
||||
|
||||
/* Calculate checksums. */
|
||||
header->checksum = acpi_checksum((void *)hest, header->length);
|
||||
}
|
||||
|
||||
#if CONFIG_HAVE_ACPI_RESUME
|
||||
void suspend_resume(void)
|
||||
{
|
||||
void *wake_vec;
|
||||
|
||||
/* If we happen to be resuming find wakeup vector and jump to OS. */
|
||||
wake_vec = acpi_find_wakeup_vector();
|
||||
if (wake_vec) {
|
||||
#if CONFIG_HAVE_SMI_HANDLER
|
||||
u32 *gnvs_address = cbmem_find(CBMEM_ID_ACPI_GNVS);
|
||||
|
||||
/* Restore GNVS pointer in SMM if found */
|
||||
if (gnvs_address && *gnvs_address) {
|
||||
printk(BIOS_DEBUG, "Restore GNVS pointer to 0x%08x\n",
|
||||
*gnvs_address);
|
||||
smm_setup_structures((void *)*gnvs_address, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Call mainboard resume handler first, if defined. */
|
||||
if (mainboard_suspend_resume)
|
||||
mainboard_suspend_resume();
|
||||
post_code(POST_OS_RESUME);
|
||||
acpi_jump_to_wakeup(wake_vec);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is to be filled by SB code - startup value what was found. */
|
||||
u8 acpi_slp_type = 0;
|
||||
|
||||
static int acpi_is_wakeup(void)
|
||||
{
|
||||
/* Both resume from S2 and resume from S3 restart at CPU reset */
|
||||
return (acpi_slp_type == 3 || acpi_slp_type == 2);
|
||||
}
|
||||
|
||||
static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp)
|
||||
{
|
||||
if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0)
|
||||
return NULL;
|
||||
|
||||
printk(BIOS_DEBUG, "Looking on %p for valid checksum\n", rsdp);
|
||||
|
||||
if (acpi_checksum((void *)rsdp, 20) != 0)
|
||||
return NULL;
|
||||
printk(BIOS_DEBUG, "Checksum 1 passed\n");
|
||||
|
||||
if ((rsdp->revision > 1) && (acpi_checksum((void *)rsdp,
|
||||
rsdp->length) != 0))
|
||||
return NULL;
|
||||
printk(BIOS_DEBUG, "Checksum 2 passed all OK\n");
|
||||
|
||||
return rsdp;
|
||||
}
|
||||
|
||||
static acpi_rsdp_t *rsdp;
|
||||
|
||||
void *acpi_get_wakeup_rsdp(void)
|
||||
{
|
||||
return rsdp;
|
||||
}
|
||||
|
||||
void *acpi_find_wakeup_vector(void)
|
||||
{
|
||||
char *p, *end;
|
||||
acpi_rsdt_t *rsdt;
|
||||
acpi_facs_t *facs;
|
||||
acpi_fadt_t *fadt;
|
||||
void *wake_vec;
|
||||
int i;
|
||||
|
||||
rsdp = NULL;
|
||||
|
||||
if (!acpi_is_wakeup())
|
||||
return NULL;
|
||||
|
||||
printk(BIOS_DEBUG, "Trying to find the wakeup vector...\n");
|
||||
|
||||
/* Find RSDP. */
|
||||
for (p = (char *)0xe0000; p < (char *)0xfffff; p += 16) {
|
||||
if ((rsdp = valid_rsdp((acpi_rsdp_t *)p)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rsdp == NULL)
|
||||
return NULL;
|
||||
|
||||
printk(BIOS_DEBUG, "RSDP found at %p\n", rsdp);
|
||||
rsdt = (acpi_rsdt_t *) rsdp->rsdt_address;
|
||||
|
||||
end = (char *)rsdt + rsdt->header.length;
|
||||
printk(BIOS_DEBUG, "RSDT found at %p ends at %p\n", rsdt, end);
|
||||
|
||||
for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) {
|
||||
fadt = (acpi_fadt_t *)rsdt->entry[i];
|
||||
if (strncmp((char *)fadt, "FACP", 4) == 0)
|
||||
break;
|
||||
fadt = NULL;
|
||||
}
|
||||
|
||||
if (fadt == NULL)
|
||||
return NULL;
|
||||
|
||||
printk(BIOS_DEBUG, "FADT found at %p\n", fadt);
|
||||
facs = (acpi_facs_t *)fadt->firmware_ctrl;
|
||||
|
||||
if (facs == NULL) {
|
||||
printk(BIOS_DEBUG, "No FACS found, wake up from S3 not "
|
||||
"possible.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "FACS found at %p\n", facs);
|
||||
wake_vec = (void *)facs->firmware_waking_vector;
|
||||
printk(BIOS_DEBUG, "OS waking vector is %p\n", wake_vec);
|
||||
|
||||
return wake_vec;
|
||||
}
|
||||
|
||||
#if CONFIG_SMP
|
||||
extern char *lowmem_backup;
|
||||
extern char *lowmem_backup_ptr;
|
||||
extern int lowmem_backup_size;
|
||||
#endif
|
||||
|
||||
#define WAKEUP_BASE 0x600
|
||||
|
||||
void (*acpi_do_wakeup)(u32 vector, u32 backup_source, u32 backup_target,
|
||||
u32 backup_size) __attribute__((regparm(0))) = (void *)WAKEUP_BASE;
|
||||
|
||||
extern unsigned char __wakeup, __wakeup_size;
|
||||
|
||||
void acpi_jump_to_wakeup(void *vector)
|
||||
{
|
||||
u32 acpi_backup_memory = (u32)cbmem_find(CBMEM_ID_RESUME);
|
||||
|
||||
if (!acpi_backup_memory) {
|
||||
printk(BIOS_WARNING, "ACPI: Backup memory missing. "
|
||||
"No S3 resume.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#if CONFIG_SMP
|
||||
// FIXME: This should go into the ACPI backup memory, too. No pork saussages.
|
||||
/*
|
||||
* Just restore the SMP trampoline and continue with wakeup on
|
||||
* assembly level.
|
||||
*/
|
||||
memcpy(lowmem_backup_ptr, lowmem_backup, lowmem_backup_size);
|
||||
#endif
|
||||
|
||||
/* Copy wakeup trampoline in place. */
|
||||
memcpy((void *)WAKEUP_BASE, &__wakeup, (size_t)&__wakeup_size);
|
||||
|
||||
#if CONFIG_COLLECT_TIMESTAMPS
|
||||
timestamp_add_now(TS_ACPI_WAKE_JUMP);
|
||||
#endif
|
||||
|
||||
acpi_do_wakeup((u32)vector, acpi_backup_memory, CONFIG_RAMBASE,
|
||||
HIGH_MEMORY_SAVE);
|
||||
}
|
||||
#endif
|
||||
|
||||
void acpi_save_gnvs(u32 gnvs_address)
|
||||
{
|
||||
u32 *gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
|
||||
if (gnvs)
|
||||
*gnvs = gnvs_address;
|
||||
}
|
729
src/arch/armv7/boot/acpigen.c
Normal file
729
src/arch/armv7/boot/acpigen.c
Normal file
@ -0,0 +1,729 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* how many nesting we support */
|
||||
#define ACPIGEN_LENSTACK_SIZE 10
|
||||
|
||||
/* if you need to change this, change the acpigen_write_f and
|
||||
acpigen_patch_len */
|
||||
|
||||
#define ACPIGEN_MAXLEN 0xfff
|
||||
|
||||
#include <string.h>
|
||||
#include <arch/acpigen.h>
|
||||
#include <console/console.h>
|
||||
#include <device/device.h>
|
||||
|
||||
static char *gencurrent;
|
||||
|
||||
char *len_stack[ACPIGEN_LENSTACK_SIZE];
|
||||
int ltop = 0;
|
||||
|
||||
int acpigen_write_len_f(void)
|
||||
{
|
||||
ASSERT(ltop < (ACPIGEN_LENSTACK_SIZE - 1))
|
||||
len_stack[ltop++] = gencurrent;
|
||||
acpigen_emit_byte(0);
|
||||
acpigen_emit_byte(0);
|
||||
return 2;
|
||||
}
|
||||
|
||||
void acpigen_patch_len(int len)
|
||||
{
|
||||
ASSERT(len <= ACPIGEN_MAXLEN)
|
||||
ASSERT(ltop > 0)
|
||||
char *p = len_stack[--ltop];
|
||||
/* generate store length for 0xfff max */
|
||||
p[0] = (0x40 | (len & 0xf));
|
||||
p[1] = (len >> 4 & 0xff);
|
||||
|
||||
}
|
||||
|
||||
void acpigen_set_current(char *curr)
|
||||
{
|
||||
gencurrent = curr;
|
||||
}
|
||||
|
||||
char *acpigen_get_current(void)
|
||||
{
|
||||
return gencurrent;
|
||||
}
|
||||
|
||||
int acpigen_emit_byte(unsigned char b)
|
||||
{
|
||||
(*gencurrent++) = b;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int acpigen_write_package(int nr_el)
|
||||
{
|
||||
int len;
|
||||
/* package op */
|
||||
acpigen_emit_byte(0x12);
|
||||
len = acpigen_write_len_f();
|
||||
acpigen_emit_byte(nr_el);
|
||||
return len + 2;
|
||||
}
|
||||
|
||||
int acpigen_write_byte(unsigned int data)
|
||||
{
|
||||
/* byte op */
|
||||
acpigen_emit_byte(0xa);
|
||||
acpigen_emit_byte(data & 0xff);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int acpigen_write_dword(unsigned int data)
|
||||
{
|
||||
/* dword op */
|
||||
acpigen_emit_byte(0xc);
|
||||
acpigen_emit_byte(data & 0xff);
|
||||
acpigen_emit_byte((data >> 8) & 0xff);
|
||||
acpigen_emit_byte((data >> 16) & 0xff);
|
||||
acpigen_emit_byte((data >> 24) & 0xff);
|
||||
return 5;
|
||||
}
|
||||
|
||||
int acpigen_write_qword(uint64_t data)
|
||||
{
|
||||
/* qword op */
|
||||
acpigen_emit_byte(0xe);
|
||||
acpigen_emit_byte(data & 0xff);
|
||||
acpigen_emit_byte((data >> 8) & 0xff);
|
||||
acpigen_emit_byte((data >> 16) & 0xff);
|
||||
acpigen_emit_byte((data >> 24) & 0xff);
|
||||
acpigen_emit_byte((data >> 32) & 0xff);
|
||||
acpigen_emit_byte((data >> 40) & 0xff);
|
||||
acpigen_emit_byte((data >> 48) & 0xff);
|
||||
acpigen_emit_byte((data >> 56) & 0xff);
|
||||
return 9;
|
||||
}
|
||||
|
||||
int acpigen_write_name_byte(const char *name, uint8_t val)
|
||||
{
|
||||
int len;
|
||||
len = acpigen_write_name(name);
|
||||
len += acpigen_write_byte(val);
|
||||
return len;
|
||||
}
|
||||
|
||||
int acpigen_write_name_dword(const char *name, uint32_t val)
|
||||
{
|
||||
int len;
|
||||
len = acpigen_write_name(name);
|
||||
len += acpigen_write_dword(val);
|
||||
return len;
|
||||
}
|
||||
|
||||
int acpigen_write_name_qword(const char *name, uint64_t val)
|
||||
{
|
||||
int len;
|
||||
len = acpigen_write_name(name);
|
||||
len += acpigen_write_qword(val);
|
||||
return len;
|
||||
}
|
||||
|
||||
int acpigen_emit_stream(const char *data, int size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
acpigen_emit_byte(data[i]);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/* The NameString are bit tricky, each element can be 4 chars, if
|
||||
less its padded with underscore. Check 18.2.2 and 18.4
|
||||
and 5.3 of ACPI specs 3.0 for details
|
||||
*/
|
||||
|
||||
static int acpigen_emit_simple_namestring(const char *name) {
|
||||
int i, len = 0;
|
||||
char ud[] = "____";
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((name[i] == '\0') || (name[i] == '.')) {
|
||||
len += acpigen_emit_stream(ud, 4 - i);
|
||||
break;
|
||||
} else {
|
||||
len += acpigen_emit_byte(name[i]);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int acpigen_emit_double_namestring(const char *name, int dotpos) {
|
||||
int len = 0;
|
||||
/* mark dual name prefix */
|
||||
len += acpigen_emit_byte(0x2e);
|
||||
len += acpigen_emit_simple_namestring(name);
|
||||
len += acpigen_emit_simple_namestring(&name[dotpos + 1]);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int acpigen_emit_multi_namestring(const char *name) {
|
||||
int len = 0, count = 0;
|
||||
unsigned char *pathlen;
|
||||
/* mark multi name prefix */
|
||||
len += acpigen_emit_byte(0x2f);
|
||||
len += acpigen_emit_byte(0x0);
|
||||
pathlen = ((unsigned char *) acpigen_get_current()) - 1;
|
||||
|
||||
while (name[0] != '\0') {
|
||||
len += acpigen_emit_simple_namestring(name);
|
||||
/* find end or next entity */
|
||||
while ((name[0] != '.') && (name[0] != '\0'))
|
||||
name++;
|
||||
/* forward to next */
|
||||
if (name[0] == '.')
|
||||
name++;
|
||||
count++;
|
||||
}
|
||||
|
||||
pathlen[0] = count;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
int acpigen_emit_namestring(const char *namepath) {
|
||||
int dotcount = 0, i;
|
||||
int dotpos = 0;
|
||||
int len = 0;
|
||||
|
||||
/* we can start with a \ */
|
||||
if (namepath[0] == '\\') {
|
||||
len += acpigen_emit_byte('\\');
|
||||
namepath++;
|
||||
}
|
||||
|
||||
/* and there can be any number of ^ */
|
||||
while (namepath[0] == '^') {
|
||||
len += acpigen_emit_byte('^');
|
||||
namepath++;
|
||||
}
|
||||
|
||||
ASSERT(namepath[0] != '\0');
|
||||
|
||||
i = 0;
|
||||
while (namepath[i] != '\0') {
|
||||
if (namepath[i] == '.') {
|
||||
dotcount++;
|
||||
dotpos = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (dotcount == 0) {
|
||||
len += acpigen_emit_simple_namestring(namepath);
|
||||
} else if (dotcount == 1) {
|
||||
len += acpigen_emit_double_namestring(namepath, dotpos);
|
||||
} else {
|
||||
len += acpigen_emit_multi_namestring(namepath);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int acpigen_write_name(const char *name)
|
||||
{
|
||||
int len;
|
||||
/* name op */
|
||||
len = acpigen_emit_byte(0x8);
|
||||
return len + acpigen_emit_namestring(name);
|
||||
}
|
||||
|
||||
int acpigen_write_scope(const char *name)
|
||||
{
|
||||
int len;
|
||||
/* scope op */
|
||||
len = acpigen_emit_byte(0x10);
|
||||
len += acpigen_write_len_f();
|
||||
return len + acpigen_emit_namestring(name);
|
||||
}
|
||||
|
||||
int acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len)
|
||||
{
|
||||
/*
|
||||
Processor (\_PR.CPUcpuindex, cpuindex, pblock_addr, pblock_len)
|
||||
{
|
||||
*/
|
||||
char pscope[16];
|
||||
int len;
|
||||
/* processor op */
|
||||
acpigen_emit_byte(0x5b);
|
||||
acpigen_emit_byte(0x83);
|
||||
len = acpigen_write_len_f();
|
||||
|
||||
sprintf(pscope, "\\_PR.CPU%x", (unsigned int) cpuindex);
|
||||
len += acpigen_emit_namestring(pscope);
|
||||
acpigen_emit_byte(cpuindex);
|
||||
acpigen_emit_byte(pblock_addr & 0xff);
|
||||
acpigen_emit_byte((pblock_addr >> 8) & 0xff);
|
||||
acpigen_emit_byte((pblock_addr >> 16) & 0xff);
|
||||
acpigen_emit_byte((pblock_addr >> 24) & 0xff);
|
||||
acpigen_emit_byte(pblock_len);
|
||||
return 6 + 2 + len;
|
||||
}
|
||||
|
||||
int acpigen_write_empty_PCT(void)
|
||||
{
|
||||
/*
|
||||
Name (_PCT, Package (0x02)
|
||||
{
|
||||
ResourceTemplate ()
|
||||
{
|
||||
Register (FFixedHW,
|
||||
0x00, // Bit Width
|
||||
0x00, // Bit Offset
|
||||
0x0000000000000000, // Address
|
||||
,)
|
||||
},
|
||||
|
||||
ResourceTemplate ()
|
||||
{
|
||||
Register (FFixedHW,
|
||||
0x00, // Bit Width
|
||||
0x00, // Bit Offset
|
||||
0x0000000000000000, // Address
|
||||
,)
|
||||
}
|
||||
})
|
||||
*/
|
||||
static char stream[] = {
|
||||
0x08, 0x5F, 0x50, 0x43, 0x54, 0x12, 0x2C, /* 00000030 "0._PCT.," */
|
||||
0x02, 0x11, 0x14, 0x0A, 0x11, 0x82, 0x0C, 0x00, /* 00000038 "........" */
|
||||
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000040 "........" */
|
||||
0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x11, 0x14, /* 00000048 "....y..." */
|
||||
0x0A, 0x11, 0x82, 0x0C, 0x00, 0x7F, 0x00, 0x00, /* 00000050 "........" */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000058 "........" */
|
||||
0x00, 0x79, 0x00
|
||||
};
|
||||
return acpigen_emit_stream(stream, ARRAY_SIZE(stream));
|
||||
}
|
||||
|
||||
int acpigen_write_empty_PTC(void)
|
||||
{
|
||||
/*
|
||||
Name (_PTC, Package (0x02)
|
||||
{
|
||||
ResourceTemplate ()
|
||||
{
|
||||
Register (FFixedHW,
|
||||
0x00, // Bit Width
|
||||
0x00, // Bit Offset
|
||||
0x0000000000000000, // Address
|
||||
,)
|
||||
},
|
||||
|
||||
ResourceTemplate ()
|
||||
{
|
||||
Register (FFixedHW,
|
||||
0x00, // Bit Width
|
||||
0x00, // Bit Offset
|
||||
0x0000000000000000, // Address
|
||||
,)
|
||||
}
|
||||
})
|
||||
*/
|
||||
int len, nlen, rlen;
|
||||
acpi_addr_t addr = {
|
||||
.space_id = ACPI_ADDRESS_SPACE_FIXED,
|
||||
.bit_width = 0,
|
||||
.bit_offset = 0,
|
||||
{
|
||||
.resv = 0
|
||||
},
|
||||
.addrl = 0,
|
||||
.addrh = 0,
|
||||
};
|
||||
|
||||
nlen = acpigen_write_name("_PTC");
|
||||
len = acpigen_write_package(2);
|
||||
|
||||
/* ControlRegister */
|
||||
rlen = acpigen_write_resourcetemplate_header();
|
||||
rlen += acpigen_write_register(&addr);
|
||||
len += acpigen_write_resourcetemplate_footer(rlen);
|
||||
len += rlen;
|
||||
|
||||
/* StatusRegister */
|
||||
rlen = acpigen_write_resourcetemplate_header();
|
||||
rlen += acpigen_write_register(&addr);
|
||||
len += acpigen_write_resourcetemplate_footer(rlen);
|
||||
len += rlen;
|
||||
|
||||
acpigen_patch_len(len - 1);
|
||||
return len + nlen;
|
||||
}
|
||||
|
||||
/* generates a func with max supported P states */
|
||||
int acpigen_write_PPC(u8 nr)
|
||||
{
|
||||
/*
|
||||
Method (_PPC, 0, NotSerialized)
|
||||
{
|
||||
Return (nr)
|
||||
}
|
||||
*/
|
||||
int len;
|
||||
/* method op */
|
||||
acpigen_emit_byte(0x14);
|
||||
len = acpigen_write_len_f();
|
||||
len += acpigen_emit_namestring("_PPC");
|
||||
/* no fnarg */
|
||||
acpigen_emit_byte(0x00);
|
||||
/* return */
|
||||
acpigen_emit_byte(0xa4);
|
||||
/* arg */
|
||||
len += acpigen_write_byte(nr);
|
||||
/* add all single bytes */
|
||||
len += 3;
|
||||
acpigen_patch_len(len - 1);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* generates a func with max supported P states */
|
||||
int acpigen_write_PPC_NVS(void)
|
||||
{
|
||||
/*
|
||||
Method (_PPC, 0, NotSerialized)
|
||||
{
|
||||
Return (PPCM)
|
||||
}
|
||||
*/
|
||||
int len;
|
||||
/* method op */
|
||||
acpigen_emit_byte(0x14);
|
||||
len = acpigen_write_len_f();
|
||||
len += acpigen_emit_namestring("_PPC");
|
||||
/* no fnarg */
|
||||
acpigen_emit_byte(0x00);
|
||||
/* return */
|
||||
acpigen_emit_byte(0xa4);
|
||||
/* arg */
|
||||
len += acpigen_emit_namestring("PPCM");
|
||||
/* add all single bytes */
|
||||
len += 3;
|
||||
acpigen_patch_len(len - 1);
|
||||
return len;
|
||||
}
|
||||
|
||||
int acpigen_write_TPC(const char *gnvs_tpc_limit)
|
||||
{
|
||||
/*
|
||||
// Sample _TPC method
|
||||
Method (_TPC, 0, NotSerialized)
|
||||
{
|
||||
Return (\TLVL)
|
||||
}
|
||||
*/
|
||||
int len;
|
||||
|
||||
len = acpigen_emit_byte(0x14); /* MethodOp */
|
||||
len += acpigen_write_len_f(); /* PkgLength */
|
||||
len += acpigen_emit_namestring("_TPC");
|
||||
len += acpigen_emit_byte(0x00); /* No Arguments */
|
||||
len += acpigen_emit_byte(0xa4); /* ReturnOp */
|
||||
len += acpigen_emit_namestring(gnvs_tpc_limit);
|
||||
acpigen_patch_len(len - 1);
|
||||
return len;
|
||||
}
|
||||
|
||||
int acpigen_write_PSS_package(u32 coreFreq, u32 power, u32 transLat,
|
||||
u32 busmLat, u32 control, u32 status)
|
||||
{
|
||||
int len;
|
||||
len = acpigen_write_package(6);
|
||||
len += acpigen_write_dword(coreFreq);
|
||||
len += acpigen_write_dword(power);
|
||||
len += acpigen_write_dword(transLat);
|
||||
len += acpigen_write_dword(busmLat);
|
||||
len += acpigen_write_dword(control);
|
||||
len += acpigen_write_dword(status);
|
||||
// pkglen without the len opcode
|
||||
acpigen_patch_len(len - 1);
|
||||
|
||||
printk(BIOS_DEBUG, "PSS: %uMHz power %u control 0x%x status 0x%x\n",
|
||||
coreFreq, power, control, status);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype)
|
||||
{
|
||||
int len, lenh, lenp;
|
||||
lenh = acpigen_write_name("_PSD");
|
||||
lenp = acpigen_write_package(1);
|
||||
len = acpigen_write_package(5);
|
||||
len += acpigen_write_byte(5); // 5 values
|
||||
len += acpigen_write_byte(0); // revision 0
|
||||
len += acpigen_write_dword(domain);
|
||||
len += acpigen_write_dword(coordtype);
|
||||
len += acpigen_write_dword(numprocs);
|
||||
acpigen_patch_len(len - 1);
|
||||
len += lenp;
|
||||
acpigen_patch_len(len - 1);
|
||||
return len + lenh;
|
||||
}
|
||||
|
||||
int acpigen_write_CST_package_entry(acpi_cstate_t *cstate)
|
||||
{
|
||||
int len, len0;
|
||||
char *start, *end;
|
||||
|
||||
len0 = acpigen_write_package(4);
|
||||
len = acpigen_write_resourcetemplate_header();
|
||||
start = acpigen_get_current();
|
||||
acpigen_write_register(&cstate->resource);
|
||||
end = acpigen_get_current();
|
||||
len += end - start;
|
||||
len += acpigen_write_resourcetemplate_footer(len);
|
||||
len += len0;
|
||||
len += acpigen_write_dword(cstate->ctype);
|
||||
len += acpigen_write_dword(cstate->latency);
|
||||
len += acpigen_write_dword(cstate->power);
|
||||
acpigen_patch_len(len - 1);
|
||||
return len;
|
||||
}
|
||||
|
||||
int acpigen_write_CST_package(acpi_cstate_t *cstate, int nentries)
|
||||
{
|
||||
int len, lenh, lenp, i;
|
||||
lenh = acpigen_write_name("_CST");
|
||||
lenp = acpigen_write_package(nentries+1);
|
||||
len = acpigen_write_dword(nentries);
|
||||
|
||||
for (i = 0; i < nentries; i++)
|
||||
len += acpigen_write_CST_package_entry(cstate + i);
|
||||
|
||||
len += lenp;
|
||||
acpigen_patch_len(len - 1);
|
||||
return len + lenh;
|
||||
}
|
||||
|
||||
int acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list)
|
||||
{
|
||||
/*
|
||||
Sample _TSS package with 100% and 50% duty cycles
|
||||
Name (_TSS, Package (0x02)
|
||||
{
|
||||
Package(){100, 1000, 0, 0x00, 0)
|
||||
Package(){50, 520, 0, 0x18, 0)
|
||||
})
|
||||
*/
|
||||
int i, len, plen, nlen;
|
||||
acpi_tstate_t *tstate = tstate_list;
|
||||
|
||||
nlen = acpigen_write_name("_TSS");
|
||||
plen = acpigen_write_package(entries);
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
len = acpigen_write_package(5);
|
||||
len += acpigen_write_dword(tstate->percent);
|
||||
len += acpigen_write_dword(tstate->power);
|
||||
len += acpigen_write_dword(tstate->latency);
|
||||
len += acpigen_write_dword(tstate->control);
|
||||
len += acpigen_write_dword(tstate->status);
|
||||
acpigen_patch_len(len - 1);
|
||||
tstate++;
|
||||
plen += len;
|
||||
}
|
||||
|
||||
acpigen_patch_len(plen - 1);
|
||||
return plen + nlen;
|
||||
}
|
||||
|
||||
int acpigen_write_TSD_package(u32 domain, u32 numprocs, PSD_coord coordtype)
|
||||
{
|
||||
int len, lenh, lenp;
|
||||
lenh = acpigen_write_name("_TSD");
|
||||
lenp = acpigen_write_package(1);
|
||||
len = acpigen_write_package(5);
|
||||
len += acpigen_write_byte(5); // 5 values
|
||||
len += acpigen_write_byte(0); // revision 0
|
||||
len += acpigen_write_dword(domain);
|
||||
len += acpigen_write_dword(coordtype);
|
||||
len += acpigen_write_dword(numprocs);
|
||||
acpigen_patch_len(len - 1);
|
||||
len += lenp;
|
||||
acpigen_patch_len(len - 1);
|
||||
return len + lenh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int acpigen_write_mem32fixed(int readwrite, u32 base, u32 size)
|
||||
{
|
||||
/*
|
||||
* acpi 4.0 section 6.4.3.4: 32-Bit Fixed Memory Range Descriptor
|
||||
* Byte 0:
|
||||
* Bit7 : 1 => big item
|
||||
* Bit6-0: 0000110 (0x6) => 32-bit fixed memory
|
||||
*/
|
||||
acpigen_emit_byte(0x86);
|
||||
/* Byte 1+2: length (0x0009) */
|
||||
acpigen_emit_byte(0x09);
|
||||
acpigen_emit_byte(0x00);
|
||||
/* bit1-7 are ignored */
|
||||
acpigen_emit_byte(readwrite ? 0x01 : 0x00);
|
||||
acpigen_emit_byte(base & 0xff);
|
||||
acpigen_emit_byte((base >> 8) & 0xff);
|
||||
acpigen_emit_byte((base >> 16) & 0xff);
|
||||
acpigen_emit_byte((base >> 24) & 0xff);
|
||||
acpigen_emit_byte(size & 0xff);
|
||||
acpigen_emit_byte((size >> 8) & 0xff);
|
||||
acpigen_emit_byte((size >> 16) & 0xff);
|
||||
acpigen_emit_byte((size >> 24) & 0xff);
|
||||
return 12;
|
||||
}
|
||||
|
||||
int acpigen_write_register(acpi_addr_t *addr)
|
||||
{
|
||||
acpigen_emit_byte(0x82); /* Register Descriptor */
|
||||
acpigen_emit_byte(0x0c); /* Register Length 7:0 */
|
||||
acpigen_emit_byte(0x00); /* Register Length 15:8 */
|
||||
acpigen_emit_byte(addr->space_id); /* Address Space ID */
|
||||
acpigen_emit_byte(addr->bit_width); /* Register Bit Width */
|
||||
acpigen_emit_byte(addr->bit_offset); /* Register Bit Offset */
|
||||
acpigen_emit_byte(addr->resv); /* Register Access Size */
|
||||
acpigen_emit_byte(addr->addrl & 0xff); /* Register Address Low */
|
||||
acpigen_emit_byte((addr->addrl >> 8) & 0xff);
|
||||
acpigen_emit_byte((addr->addrl >> 16) & 0xff);
|
||||
acpigen_emit_byte((addr->addrl >> 24) & 0xff);
|
||||
acpigen_emit_byte(addr->addrh & 0xff); /* Register Address High */
|
||||
acpigen_emit_byte((addr->addrh >> 8) & 0xff);
|
||||
acpigen_emit_byte((addr->addrh >> 16) & 0xff);
|
||||
acpigen_emit_byte((addr->addrh >> 24) & 0xff);
|
||||
return 15;
|
||||
}
|
||||
|
||||
int acpigen_write_io16(u16 min, u16 max, u8 align, u8 len, u8 decode16)
|
||||
{
|
||||
/*
|
||||
* acpi 4.0 section 6.4.2.6: I/O Port Descriptor
|
||||
* Byte 0:
|
||||
* Bit7 : 0 => small item
|
||||
* Bit6-3: 1000 (0x8) => I/O port descriptor
|
||||
* Bit2-0: 111 (0x7) => 7 Bytes long
|
||||
*/
|
||||
acpigen_emit_byte(0x47);
|
||||
/* does the device decode all 16 or just 10 bits? */
|
||||
/* bit1-7 are ignored */
|
||||
acpigen_emit_byte(decode16 ? 0x01 : 0x00);
|
||||
/* minimum base address the device may be configured for */
|
||||
acpigen_emit_byte(min & 0xff);
|
||||
acpigen_emit_byte((min >> 8) & 0xff);
|
||||
/* maximum base address the device may be configured for */
|
||||
acpigen_emit_byte(max & 0xff);
|
||||
acpigen_emit_byte((max >> 8) & 0xff);
|
||||
/* alignment for min base */
|
||||
acpigen_emit_byte(align & 0xff);
|
||||
acpigen_emit_byte(len & 0xff);
|
||||
return 8;
|
||||
}
|
||||
|
||||
int acpigen_write_resourcetemplate_header(void)
|
||||
{
|
||||
int len;
|
||||
/*
|
||||
* A ResourceTemplate() is a Buffer() with a
|
||||
* (Byte|Word|DWord) containing the length, followed by one or more
|
||||
* resource items, terminated by the end tag
|
||||
* (small item 0xf, len 1)
|
||||
*/
|
||||
len = acpigen_emit_byte(0x11); /* Buffer opcode */
|
||||
len += acpigen_write_len_f();
|
||||
len += acpigen_emit_byte(0x0b); /* Word opcode */
|
||||
len_stack[ltop++] = acpigen_get_current();
|
||||
len += acpigen_emit_byte(0x00);
|
||||
len += acpigen_emit_byte(0x00);
|
||||
return len;
|
||||
}
|
||||
|
||||
int acpigen_write_resourcetemplate_footer(int len)
|
||||
{
|
||||
char *p = len_stack[--ltop];
|
||||
/*
|
||||
* end tag (acpi 4.0 Section 6.4.2.8)
|
||||
* 0x79 <checksum>
|
||||
* 0x00 is treated as a good checksum according to the spec
|
||||
* and is what iasl generates.
|
||||
*/
|
||||
len += acpigen_emit_byte(0x79);
|
||||
len += acpigen_emit_byte(0x00);
|
||||
/* patch len word */
|
||||
p[0] = (len-6) & 0xff;
|
||||
p[1] = ((len-6) >> 8) & 0xff;
|
||||
/* patch len field */
|
||||
acpigen_patch_len(len-1);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static void acpigen_add_mainboard_rsvd_mem32(void *gp, struct device *dev,
|
||||
struct resource *res)
|
||||
{
|
||||
acpigen_write_mem32fixed(0, res->base, res->size);
|
||||
}
|
||||
|
||||
static void acpigen_add_mainboard_rsvd_io(void *gp, struct device *dev,
|
||||
struct resource *res)
|
||||
{
|
||||
resource_t base = res->base;
|
||||
resource_t size = res->size;
|
||||
while (size > 0) {
|
||||
resource_t sz = size > 255 ? 255 : size;
|
||||
acpigen_write_io16(base, base, 0, sz, 1);
|
||||
size -= sz;
|
||||
base += sz;
|
||||
}
|
||||
}
|
||||
|
||||
int acpigen_write_mainboard_resource_template(void)
|
||||
{
|
||||
int len;
|
||||
char *start;
|
||||
char *end;
|
||||
len = acpigen_write_resourcetemplate_header();
|
||||
start = acpigen_get_current();
|
||||
|
||||
/* Add reserved memory ranges */
|
||||
search_global_resources(
|
||||
IORESOURCE_MEM | IORESOURCE_RESERVE,
|
||||
IORESOURCE_MEM | IORESOURCE_RESERVE,
|
||||
acpigen_add_mainboard_rsvd_mem32, 0);
|
||||
|
||||
/* Add reserved io ranges */
|
||||
search_global_resources(
|
||||
IORESOURCE_IO | IORESOURCE_RESERVE,
|
||||
IORESOURCE_IO | IORESOURCE_RESERVE,
|
||||
acpigen_add_mainboard_rsvd_io, 0);
|
||||
|
||||
end = acpigen_get_current();
|
||||
len += end-start;
|
||||
len += acpigen_write_resourcetemplate_footer(len);
|
||||
return len;
|
||||
}
|
||||
|
||||
int acpigen_write_mainboard_resources(const char *scope, const char *name)
|
||||
{
|
||||
int len;
|
||||
len = acpigen_write_scope(scope);
|
||||
len += acpigen_write_name(name);
|
||||
len += acpigen_write_mainboard_resource_template();
|
||||
acpigen_patch_len(len - 1);
|
||||
return len;
|
||||
}
|
189
src/arch/armv7/boot/boot.c
Normal file
189
src/arch/armv7/boot/boot.c
Normal file
@ -0,0 +1,189 @@
|
||||
#include <console/console.h>
|
||||
#include <ip_checksum.h>
|
||||
#include <boot/elf.h>
|
||||
#include <boot/elf_boot.h>
|
||||
#include <string.h>
|
||||
#include <cpu/x86/multiboot.h>
|
||||
|
||||
|
||||
#ifndef CMD_LINE
|
||||
#define CMD_LINE ""
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define UPSZ(X) ((sizeof(X) + 3) &~3)
|
||||
|
||||
static struct {
|
||||
Elf_Bhdr hdr;
|
||||
Elf_Nhdr ft_hdr;
|
||||
unsigned char ft_desc[UPSZ(FIRMWARE_TYPE)];
|
||||
Elf_Nhdr bl_hdr;
|
||||
unsigned char bl_desc[UPSZ(BOOTLOADER)];
|
||||
Elf_Nhdr blv_hdr;
|
||||
unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
|
||||
Elf_Nhdr cmd_hdr;
|
||||
unsigned char cmd_desc[UPSZ(CMD_LINE)];
|
||||
} elf_boot_notes = {
|
||||
.hdr = {
|
||||
.b_signature = 0x0E1FB007,
|
||||
.b_size = sizeof(elf_boot_notes),
|
||||
.b_checksum = 0,
|
||||
.b_records = 4,
|
||||
},
|
||||
.ft_hdr = {
|
||||
.n_namesz = 0,
|
||||
.n_descsz = sizeof(FIRMWARE_TYPE),
|
||||
.n_type = EBN_FIRMWARE_TYPE,
|
||||
},
|
||||
.ft_desc = FIRMWARE_TYPE,
|
||||
.bl_hdr = {
|
||||
.n_namesz = 0,
|
||||
.n_descsz = sizeof(BOOTLOADER),
|
||||
.n_type = EBN_BOOTLOADER_NAME,
|
||||
},
|
||||
.bl_desc = BOOTLOADER,
|
||||
.blv_hdr = {
|
||||
.n_namesz = 0,
|
||||
.n_descsz = sizeof(BOOTLOADER_VERSION),
|
||||
.n_type = EBN_BOOTLOADER_VERSION,
|
||||
},
|
||||
.blv_desc = BOOTLOADER_VERSION,
|
||||
.cmd_hdr = {
|
||||
.n_namesz = 0,
|
||||
.n_descsz = sizeof(CMD_LINE),
|
||||
.n_type = EBN_COMMAND_LINE,
|
||||
},
|
||||
.cmd_desc = CMD_LINE,
|
||||
};
|
||||
|
||||
|
||||
int elf_check_arch(Elf_ehdr *ehdr)
|
||||
{
|
||||
return (
|
||||
((ehdr->e_machine == EM_386) || (ehdr->e_machine == EM_486)) &&
|
||||
(ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
|
||||
(ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void jmp_to_elf_entry(void *entry, unsigned long buffer, unsigned long size)
|
||||
{
|
||||
extern unsigned char _ram_seg, _eram_seg;
|
||||
unsigned long lb_start, lb_size;
|
||||
unsigned long adjust, adjusted_boot_notes;
|
||||
|
||||
elf_boot_notes.hdr.b_checksum =
|
||||
compute_ip_checksum(&elf_boot_notes, sizeof(elf_boot_notes));
|
||||
|
||||
lb_start = (unsigned long)&_ram_seg;
|
||||
lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
|
||||
adjust = buffer + size - lb_start;
|
||||
|
||||
adjusted_boot_notes = (unsigned long)&elf_boot_notes;
|
||||
adjusted_boot_notes += adjust;
|
||||
|
||||
printk(BIOS_SPEW, "entry = 0x%08lx\n", (unsigned long)entry);
|
||||
printk(BIOS_SPEW, "lb_start = 0x%08lx\n", lb_start);
|
||||
printk(BIOS_SPEW, "lb_size = 0x%08lx\n", lb_size);
|
||||
printk(BIOS_SPEW, "adjust = 0x%08lx\n", adjust);
|
||||
printk(BIOS_SPEW, "buffer = 0x%08lx\n", buffer);
|
||||
printk(BIOS_SPEW, " elf_boot_notes = 0x%08lx\n", (unsigned long)&elf_boot_notes);
|
||||
printk(BIOS_SPEW, "adjusted_boot_notes = 0x%08lx\n", adjusted_boot_notes);
|
||||
|
||||
/* FIXME(dhendrix): port code to jump to kernel here... */
|
||||
#if 0
|
||||
/* Jump to kernel */
|
||||
__asm__ __volatile__(
|
||||
" cld \n\t"
|
||||
/* Save the callee save registers... */
|
||||
" pushl %%esi\n\t"
|
||||
" pushl %%edi\n\t"
|
||||
" pushl %%ebx\n\t"
|
||||
/* Save the parameters I was passed */
|
||||
" pushl $0\n\t" /* 20 adjust */
|
||||
" pushl %0\n\t" /* 16 lb_start */
|
||||
" pushl %1\n\t" /* 12 buffer */
|
||||
" pushl %2\n\t" /* 8 lb_size */
|
||||
" pushl %3\n\t" /* 4 entry */
|
||||
" pushl %4\n\t" /* 0 elf_boot_notes */
|
||||
/* Compute the adjustment */
|
||||
" xorl %%eax, %%eax\n\t"
|
||||
" subl 16(%%esp), %%eax\n\t"
|
||||
" addl 12(%%esp), %%eax\n\t"
|
||||
" addl 8(%%esp), %%eax\n\t"
|
||||
" movl %%eax, 20(%%esp)\n\t"
|
||||
/* Place a copy of coreboot in its new location */
|
||||
/* Move ``longs'' the coreboot size is 4 byte aligned */
|
||||
" movl 12(%%esp), %%edi\n\t"
|
||||
" addl 8(%%esp), %%edi\n\t"
|
||||
" movl 16(%%esp), %%esi\n\t"
|
||||
" movl 8(%%esp), %%ecx\n\n"
|
||||
" shrl $2, %%ecx\n\t"
|
||||
" rep movsl\n\t"
|
||||
|
||||
/* Adjust the stack pointer to point into the new coreboot image */
|
||||
" addl 20(%%esp), %%esp\n\t"
|
||||
/* Adjust the instruction pointer to point into the new coreboot image */
|
||||
" movl $1f, %%eax\n\t"
|
||||
" addl 20(%%esp), %%eax\n\t"
|
||||
" jmp *%%eax\n\t"
|
||||
"1: \n\t"
|
||||
|
||||
/* Copy the coreboot bounce buffer over coreboot */
|
||||
/* Move ``longs'' the coreboot size is 4 byte aligned */
|
||||
" movl 16(%%esp), %%edi\n\t"
|
||||
" movl 12(%%esp), %%esi\n\t"
|
||||
" movl 8(%%esp), %%ecx\n\t"
|
||||
" shrl $2, %%ecx\n\t"
|
||||
" rep movsl\n\t"
|
||||
|
||||
/* Now jump to the loaded image */
|
||||
" movl %5, %%eax\n\t"
|
||||
" movl 0(%%esp), %%ebx\n\t"
|
||||
" call *4(%%esp)\n\t"
|
||||
|
||||
/* The loaded image returned? */
|
||||
" cli \n\t"
|
||||
" cld \n\t"
|
||||
|
||||
/* Copy the saved copy of coreboot where coreboot runs */
|
||||
/* Move ``longs'' the coreboot size is 4 byte aligned */
|
||||
" movl 16(%%esp), %%edi\n\t"
|
||||
" movl 12(%%esp), %%esi\n\t"
|
||||
" addl 8(%%esp), %%esi\n\t"
|
||||
" movl 8(%%esp), %%ecx\n\t"
|
||||
" shrl $2, %%ecx\n\t"
|
||||
" rep movsl\n\t"
|
||||
|
||||
/* Adjust the stack pointer to point into the old coreboot image */
|
||||
" subl 20(%%esp), %%esp\n\t"
|
||||
|
||||
/* Adjust the instruction pointer to point into the old coreboot image */
|
||||
" movl $1f, %%eax\n\t"
|
||||
" subl 20(%%esp), %%eax\n\t"
|
||||
" jmp *%%eax\n\t"
|
||||
"1: \n\t"
|
||||
|
||||
/* Drop the parameters I was passed */
|
||||
" addl $24, %%esp\n\t"
|
||||
|
||||
/* Restore the callee save registers */
|
||||
" popl %%ebx\n\t"
|
||||
" popl %%edi\n\t"
|
||||
" popl %%esi\n\t"
|
||||
|
||||
::
|
||||
"ri" (lb_start), "ri" (buffer), "ri" (lb_size),
|
||||
"ri" (entry),
|
||||
#if CONFIG_MULTIBOOT
|
||||
"ri"(mbi), "ri" (MB_MAGIC2)
|
||||
#else
|
||||
"ri"(adjusted_boot_notes), "ri" (0x0E1FB007)
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
711
src/arch/armv7/boot/coreboot_table.c
Normal file
711
src/arch/armv7/boot/coreboot_table.c
Normal file
@ -0,0 +1,711 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2003-2004 Eric Biederman
|
||||
* Copyright (C) 2005-2010 coresystems GmbH
|
||||
*
|
||||
* 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; version 2 of
|
||||
* the License.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <ip_checksum.h>
|
||||
#include <boot/tables.h>
|
||||
#include <boot/coreboot_tables.h>
|
||||
#include <arch/coreboot_tables.h>
|
||||
#include <string.h>
|
||||
#include <version.h>
|
||||
#include <device/device.h>
|
||||
#include <stdlib.h>
|
||||
#include <cbfs.h>
|
||||
#include <cbmem.h>
|
||||
#if CONFIG_USE_OPTION_TABLE
|
||||
#include <option_table.h>
|
||||
#endif
|
||||
#if CONFIG_CHROMEOS
|
||||
#include <arch/acpi.h>
|
||||
#include <vendorcode/google/chromeos/gnvs.h>
|
||||
#endif
|
||||
|
||||
static struct lb_header *lb_table_init(unsigned long addr)
|
||||
{
|
||||
struct lb_header *header;
|
||||
|
||||
/* 16 byte align the address */
|
||||
addr += 15;
|
||||
addr &= ~15;
|
||||
|
||||
header = (void *)addr;
|
||||
header->signature[0] = 'L';
|
||||
header->signature[1] = 'B';
|
||||
header->signature[2] = 'I';
|
||||
header->signature[3] = 'O';
|
||||
header->header_bytes = sizeof(*header);
|
||||
header->header_checksum = 0;
|
||||
header->table_bytes = 0;
|
||||
header->table_checksum = 0;
|
||||
header->table_entries = 0;
|
||||
return header;
|
||||
}
|
||||
|
||||
static struct lb_record *lb_first_record(struct lb_header *header)
|
||||
{
|
||||
struct lb_record *rec;
|
||||
rec = (void *)(((char *)header) + sizeof(*header));
|
||||
return rec;
|
||||
}
|
||||
|
||||
static struct lb_record *lb_last_record(struct lb_header *header)
|
||||
{
|
||||
struct lb_record *rec;
|
||||
rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes);
|
||||
return rec;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static struct lb_record *lb_next_record(struct lb_record *rec)
|
||||
{
|
||||
rec = (void *)(((char *)rec) + rec->size);
|
||||
return rec;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct lb_record *lb_new_record(struct lb_header *header)
|
||||
{
|
||||
struct lb_record *rec;
|
||||
rec = lb_last_record(header);
|
||||
if (header->table_entries) {
|
||||
header->table_bytes += rec->size;
|
||||
}
|
||||
rec = lb_last_record(header);
|
||||
header->table_entries++;
|
||||
rec->tag = LB_TAG_UNUSED;
|
||||
rec->size = sizeof(*rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
|
||||
static struct lb_memory *lb_memory(struct lb_header *header)
|
||||
{
|
||||
struct lb_record *rec;
|
||||
struct lb_memory *mem;
|
||||
rec = lb_new_record(header);
|
||||
mem = (struct lb_memory *)rec;
|
||||
mem->tag = LB_TAG_MEMORY;
|
||||
mem->size = sizeof(*mem);
|
||||
return mem;
|
||||
}
|
||||
|
||||
static struct lb_serial *lb_serial(struct lb_header *header)
|
||||
{
|
||||
#if CONFIG_CONSOLE_SERIAL8250
|
||||
struct lb_record *rec;
|
||||
struct lb_serial *serial;
|
||||
rec = lb_new_record(header);
|
||||
serial = (struct lb_serial *)rec;
|
||||
serial->tag = LB_TAG_SERIAL;
|
||||
serial->size = sizeof(*serial);
|
||||
serial->type = LB_SERIAL_TYPE_IO_MAPPED;
|
||||
serial->baseaddr = CONFIG_TTYS0_BASE;
|
||||
serial->baud = CONFIG_TTYS0_BAUD;
|
||||
return serial;
|
||||
#elif CONFIG_CONSOLE_SERIAL8250MEM
|
||||
if (uartmem_getbaseaddr()) {
|
||||
struct lb_record *rec;
|
||||
struct lb_serial *serial;
|
||||
rec = lb_new_record(header);
|
||||
serial = (struct lb_serial *)rec;
|
||||
serial->tag = LB_TAG_SERIAL;
|
||||
serial->size = sizeof(*serial);
|
||||
serial->type = LB_SERIAL_TYPE_MEMORY_MAPPED;
|
||||
serial->baseaddr = uartmem_getbaseaddr();
|
||||
serial->baud = CONFIG_TTYS0_BAUD;
|
||||
return serial;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_CONSOLE_SERIAL8250 || CONFIG_CONSOLE_SERIAL8250MEM || \
|
||||
CONFIG_CONSOLE_LOGBUF || CONFIG_USBDEBUG
|
||||
static void add_console(struct lb_header *header, u16 consoletype)
|
||||
{
|
||||
struct lb_console *console;
|
||||
|
||||
console = (struct lb_console *)lb_new_record(header);
|
||||
console->tag = LB_TAG_CONSOLE;
|
||||
console->size = sizeof(*console);
|
||||
console->type = consoletype;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void lb_console(struct lb_header *header)
|
||||
{
|
||||
#if CONFIG_CONSOLE_SERIAL8250
|
||||
add_console(header, LB_TAG_CONSOLE_SERIAL8250);
|
||||
#endif
|
||||
#if CONFIG_CONSOLE_SERIAL8250MEM
|
||||
add_console(header, LB_TAG_CONSOLE_SERIAL8250MEM);
|
||||
#endif
|
||||
#if CONFIG_CONSOLE_LOGBUF
|
||||
add_console(header, LB_TAG_CONSOLE_LOGBUF);
|
||||
#endif
|
||||
#if CONFIG_USBDEBUG
|
||||
add_console(header, LB_TAG_CONSOLE_EHCI);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void lb_framebuffer(struct lb_header *header)
|
||||
{
|
||||
#if CONFIG_FRAMEBUFFER_KEEP_VESA_MODE
|
||||
void fill_lb_framebuffer(struct lb_framebuffer *framebuffer);
|
||||
int vbe_mode_info_valid(void);
|
||||
|
||||
// If there isn't any mode info to put in the table, don't ask for it
|
||||
// to be filled with junk.
|
||||
if (!vbe_mode_info_valid())
|
||||
return;
|
||||
struct lb_framebuffer *framebuffer;
|
||||
framebuffer = (struct lb_framebuffer *)lb_new_record(header);
|
||||
framebuffer->tag = LB_TAG_FRAMEBUFFER;
|
||||
framebuffer->size = sizeof(*framebuffer);
|
||||
fill_lb_framebuffer(framebuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_CHROMEOS
|
||||
static void lb_gpios(struct lb_header *header)
|
||||
{
|
||||
struct lb_gpios *gpios;
|
||||
gpios = (struct lb_gpios *)lb_new_record(header);
|
||||
gpios->tag = LB_TAG_GPIO;
|
||||
gpios->size = sizeof(*gpios);
|
||||
gpios->count = 0;
|
||||
fill_lb_gpios(gpios);
|
||||
}
|
||||
|
||||
static void lb_vdat(struct lb_header *header)
|
||||
{
|
||||
struct lb_vdat* vdat;
|
||||
|
||||
vdat = (struct lb_vdat *)lb_new_record(header);
|
||||
vdat->tag = LB_TAG_VDAT;
|
||||
vdat->size = sizeof(*vdat);
|
||||
acpi_get_vdat_info(&vdat->vdat_addr, &vdat->vdat_size);
|
||||
}
|
||||
|
||||
static void lb_vbnv(struct lb_header *header)
|
||||
{
|
||||
struct lb_vbnv* vbnv;
|
||||
|
||||
vbnv = (struct lb_vbnv *)lb_new_record(header);
|
||||
vbnv->tag = LB_TAG_VBNV;
|
||||
vbnv->size = sizeof(*vbnv);
|
||||
vbnv->vbnv_start = CONFIG_VBNV_OFFSET + 14;
|
||||
vbnv->vbnv_size = CONFIG_VBNV_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void add_cbmem_pointers(struct lb_header *header)
|
||||
{
|
||||
/*
|
||||
* These CBMEM sections' addresses are included in the coreboot table
|
||||
* with the appropriate tags.
|
||||
*/
|
||||
const struct section_id {
|
||||
int cbmem_id;
|
||||
int table_tag;
|
||||
} section_ids[] = {
|
||||
{CBMEM_ID_TIMESTAMP, LB_TAG_TIMESTAMPS},
|
||||
{CBMEM_ID_CONSOLE, LB_TAG_CBMEM_CONSOLE}
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(section_ids); i++) {
|
||||
const struct section_id *sid = section_ids + i;
|
||||
struct lb_cbmem_ref *cbmem_ref;
|
||||
void *cbmem_addr = cbmem_find(sid->cbmem_id);
|
||||
|
||||
if (!cbmem_addr)
|
||||
continue; /* This section is not present */
|
||||
|
||||
cbmem_ref = (struct lb_cbmem_ref *)lb_new_record(header);
|
||||
if (!cbmem_ref) {
|
||||
printk(BIOS_ERR, "No more room in coreboot table!\n");
|
||||
break;
|
||||
}
|
||||
cbmem_ref->tag = sid->table_tag;
|
||||
cbmem_ref->size = sizeof(*cbmem_ref);
|
||||
cbmem_ref->cbmem_addr = cbmem_addr;
|
||||
}
|
||||
}
|
||||
|
||||
static struct lb_mainboard *lb_mainboard(struct lb_header *header)
|
||||
{
|
||||
struct lb_record *rec;
|
||||
struct lb_mainboard *mainboard;
|
||||
rec = lb_new_record(header);
|
||||
mainboard = (struct lb_mainboard *)rec;
|
||||
mainboard->tag = LB_TAG_MAINBOARD;
|
||||
|
||||
mainboard->size = (sizeof(*mainboard) +
|
||||
strlen(mainboard_vendor) + 1 +
|
||||
strlen(mainboard_part_number) + 1 +
|
||||
3) & ~3;
|
||||
|
||||
mainboard->vendor_idx = 0;
|
||||
mainboard->part_number_idx = strlen(mainboard_vendor) + 1;
|
||||
|
||||
memcpy(mainboard->strings + mainboard->vendor_idx,
|
||||
mainboard_vendor, strlen(mainboard_vendor) + 1);
|
||||
memcpy(mainboard->strings + mainboard->part_number_idx,
|
||||
mainboard_part_number, strlen(mainboard_part_number) + 1);
|
||||
|
||||
return mainboard;
|
||||
}
|
||||
|
||||
#if CONFIG_USE_OPTION_TABLE
|
||||
static struct cmos_checksum *lb_cmos_checksum(struct lb_header *header)
|
||||
{
|
||||
struct lb_record *rec;
|
||||
struct cmos_checksum *cmos_checksum;
|
||||
rec = lb_new_record(header);
|
||||
cmos_checksum = (struct cmos_checksum *)rec;
|
||||
cmos_checksum->tag = LB_TAG_OPTION_CHECKSUM;
|
||||
|
||||
cmos_checksum->size = (sizeof(*cmos_checksum));
|
||||
|
||||
cmos_checksum->range_start = LB_CKS_RANGE_START * 8;
|
||||
cmos_checksum->range_end = ( LB_CKS_RANGE_END * 8 ) + 7;
|
||||
cmos_checksum->location = LB_CKS_LOC * 8;
|
||||
cmos_checksum->type = CHECKSUM_PCBIOS;
|
||||
|
||||
return cmos_checksum;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void lb_strings(struct lb_header *header)
|
||||
{
|
||||
static const struct {
|
||||
uint32_t tag;
|
||||
const char *string;
|
||||
} strings[] = {
|
||||
{ LB_TAG_VERSION, coreboot_version, },
|
||||
{ LB_TAG_EXTRA_VERSION, coreboot_extra_version, },
|
||||
{ LB_TAG_BUILD, coreboot_build, },
|
||||
{ LB_TAG_COMPILE_TIME, coreboot_compile_time, },
|
||||
{ LB_TAG_COMPILE_BY, coreboot_compile_by, },
|
||||
{ LB_TAG_COMPILE_HOST, coreboot_compile_host, },
|
||||
{ LB_TAG_COMPILE_DOMAIN, coreboot_compile_domain, },
|
||||
{ LB_TAG_COMPILER, coreboot_compiler, },
|
||||
{ LB_TAG_LINKER, coreboot_linker, },
|
||||
{ LB_TAG_ASSEMBLER, coreboot_assembler, },
|
||||
};
|
||||
unsigned int i;
|
||||
for(i = 0; i < ARRAY_SIZE(strings); i++) {
|
||||
struct lb_string *rec;
|
||||
size_t len;
|
||||
rec = (struct lb_string *)lb_new_record(header);
|
||||
len = strlen(strings[i].string);
|
||||
rec->tag = strings[i].tag;
|
||||
rec->size = (sizeof(*rec) + len + 1 + 3) & ~3;
|
||||
memcpy(rec->string, strings[i].string, len+1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if CONFIG_WRITE_HIGH_TABLES
|
||||
static struct lb_forward *lb_forward(struct lb_header *header, struct lb_header *next_header)
|
||||
{
|
||||
struct lb_record *rec;
|
||||
struct lb_forward *forward;
|
||||
rec = lb_new_record(header);
|
||||
forward = (struct lb_forward *)rec;
|
||||
forward->tag = LB_TAG_FORWARD;
|
||||
forward->size = sizeof(*forward);
|
||||
forward->forward = (uint64_t)(unsigned long)next_header;
|
||||
return forward;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* FIXME(dhendrix): used to be static void lb_memory_range(), but compiler
|
||||
started complaining since it shares a name with a non-static struct. ugh. */
|
||||
static void new_lb_memory_range(struct lb_memory *mem,
|
||||
uint32_t type, uint64_t start, uint64_t size)
|
||||
{
|
||||
int entries;
|
||||
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
|
||||
mem->map[entries].start = pack_lb64(start);
|
||||
mem->map[entries].size = pack_lb64(size);
|
||||
mem->map[entries].type = type;
|
||||
mem->size += sizeof(mem->map[0]);
|
||||
}
|
||||
|
||||
static void lb_reserve_table_memory(struct lb_header *head)
|
||||
{
|
||||
struct lb_record *last_rec;
|
||||
struct lb_memory *mem;
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
int i, entries;
|
||||
|
||||
last_rec = lb_last_record(head);
|
||||
mem = get_lb_mem();
|
||||
start = (unsigned long)head;
|
||||
end = (unsigned long)last_rec;
|
||||
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
|
||||
/* Resize the right two memory areas so this table is in
|
||||
* a reserved area of memory. Everything has been carefully
|
||||
* setup so that is all we need to do.
|
||||
*/
|
||||
for(i = 0; i < entries; i++ ) {
|
||||
uint64_t map_start = unpack_lb64(mem->map[i].start);
|
||||
uint64_t map_end = map_start + unpack_lb64(mem->map[i].size);
|
||||
/* Does this area need to be expanded? */
|
||||
if (map_end == start) {
|
||||
mem->map[i].size = pack_lb64(end - map_start);
|
||||
}
|
||||
/* Does this area need to be contracted? */
|
||||
else if (map_start == start) {
|
||||
mem->map[i].start = pack_lb64(end);
|
||||
mem->map[i].size = pack_lb64(map_end - end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long lb_table_fini(struct lb_header *head, int fixup)
|
||||
{
|
||||
struct lb_record *rec, *first_rec;
|
||||
rec = lb_last_record(head);
|
||||
if (head->table_entries) {
|
||||
head->table_bytes += rec->size;
|
||||
}
|
||||
|
||||
if (fixup)
|
||||
lb_reserve_table_memory(head);
|
||||
|
||||
first_rec = lb_first_record(head);
|
||||
head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes);
|
||||
head->header_checksum = 0;
|
||||
head->header_checksum = compute_ip_checksum(head, sizeof(*head));
|
||||
printk(BIOS_DEBUG,
|
||||
"Wrote coreboot table at: %p, 0x%x bytes, checksum %x\n",
|
||||
head, head->table_bytes, head->table_checksum);
|
||||
return (unsigned long)rec + rec->size;
|
||||
}
|
||||
|
||||
static void lb_cleanup_memory_ranges(struct lb_memory *mem)
|
||||
{
|
||||
int entries;
|
||||
int i, j;
|
||||
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
|
||||
|
||||
/* Sort the lb memory ranges */
|
||||
for(i = 0; i < entries; i++) {
|
||||
uint64_t entry_start = unpack_lb64(mem->map[i].start);
|
||||
for(j = i; j < entries; j++) {
|
||||
uint64_t temp_start = unpack_lb64(mem->map[j].start);
|
||||
if (temp_start < entry_start) {
|
||||
struct lb_memory_range tmp;
|
||||
tmp = mem->map[i];
|
||||
mem->map[i] = mem->map[j];
|
||||
mem->map[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge adjacent entries */
|
||||
for(i = 0; (i + 1) < entries; i++) {
|
||||
uint64_t start, end, nstart, nend;
|
||||
if (mem->map[i].type != mem->map[i + 1].type) {
|
||||
continue;
|
||||
}
|
||||
start = unpack_lb64(mem->map[i].start);
|
||||
end = start + unpack_lb64(mem->map[i].size);
|
||||
nstart = unpack_lb64(mem->map[i + 1].start);
|
||||
nend = nstart + unpack_lb64(mem->map[i + 1].size);
|
||||
if ((start <= nstart) && (end > nstart)) {
|
||||
if (start > nstart) {
|
||||
start = nstart;
|
||||
}
|
||||
if (end < nend) {
|
||||
end = nend;
|
||||
}
|
||||
/* Record the new region size */
|
||||
mem->map[i].start = pack_lb64(start);
|
||||
mem->map[i].size = pack_lb64(end - start);
|
||||
|
||||
/* Delete the entry I have merged with */
|
||||
memmove(&mem->map[i + 1], &mem->map[i + 2],
|
||||
((entries - i - 2) * sizeof(mem->map[0])));
|
||||
mem->size -= sizeof(mem->map[0]);
|
||||
entries -= 1;
|
||||
/* See if I can merge with the next entry as well */
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void lb_remove_memory_range(struct lb_memory *mem,
|
||||
uint64_t start, uint64_t size)
|
||||
{
|
||||
uint64_t end;
|
||||
int entries;
|
||||
int i;
|
||||
|
||||
end = start + size;
|
||||
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
|
||||
|
||||
/* Remove a reserved area from the memory map */
|
||||
for(i = 0; i < entries; i++) {
|
||||
uint64_t map_start = unpack_lb64(mem->map[i].start);
|
||||
uint64_t map_end = map_start + unpack_lb64(mem->map[i].size);
|
||||
if ((start <= map_start) && (end >= map_end)) {
|
||||
/* Remove the completely covered range */
|
||||
memmove(&mem->map[i], &mem->map[i + 1],
|
||||
((entries - i - 1) * sizeof(mem->map[0])));
|
||||
mem->size -= sizeof(mem->map[0]);
|
||||
entries -= 1;
|
||||
/* Since the index will disappear revisit what will appear here */
|
||||
i -= 1;
|
||||
}
|
||||
else if ((start > map_start) && (end < map_end)) {
|
||||
/* Split the memory range */
|
||||
memmove(&mem->map[i + 1], &mem->map[i],
|
||||
((entries - i) * sizeof(mem->map[0])));
|
||||
mem->size += sizeof(mem->map[0]);
|
||||
entries += 1;
|
||||
/* Update the first map entry */
|
||||
mem->map[i].size = pack_lb64(start - map_start);
|
||||
/* Update the second map entry */
|
||||
mem->map[i + 1].start = pack_lb64(end);
|
||||
mem->map[i + 1].size = pack_lb64(map_end - end);
|
||||
/* Don't bother with this map entry again */
|
||||
i += 1;
|
||||
}
|
||||
else if ((start <= map_start) && (end > map_start)) {
|
||||
/* Shrink the start of the memory range */
|
||||
mem->map[i].start = pack_lb64(end);
|
||||
mem->map[i].size = pack_lb64(map_end - end);
|
||||
}
|
||||
else if ((start < map_end) && (start > map_start)) {
|
||||
/* Shrink the end of the memory range */
|
||||
mem->map[i].size = pack_lb64(start - map_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void lb_add_memory_range(struct lb_memory *mem,
|
||||
uint32_t type, uint64_t start, uint64_t size)
|
||||
{
|
||||
lb_remove_memory_range(mem, start, size);
|
||||
new_lb_memory_range(mem, type, start, size);
|
||||
lb_cleanup_memory_ranges(mem);
|
||||
}
|
||||
|
||||
static void lb_dump_memory_ranges(struct lb_memory *mem)
|
||||
{
|
||||
int entries;
|
||||
int i;
|
||||
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
|
||||
|
||||
printk(BIOS_DEBUG, "coreboot memory table:\n");
|
||||
for(i = 0; i < entries; i++) {
|
||||
uint64_t entry_start = unpack_lb64(mem->map[i].start);
|
||||
uint64_t entry_size = unpack_lb64(mem->map[i].size);
|
||||
const char *entry_type;
|
||||
|
||||
switch (mem->map[i].type) {
|
||||
case LB_MEM_RAM: entry_type="RAM"; break;
|
||||
case LB_MEM_RESERVED: entry_type="RESERVED"; break;
|
||||
case LB_MEM_ACPI: entry_type="ACPI"; break;
|
||||
case LB_MEM_NVS: entry_type="NVS"; break;
|
||||
case LB_MEM_UNUSABLE: entry_type="UNUSABLE"; break;
|
||||
case LB_MEM_VENDOR_RSVD: entry_type="VENDOR RESERVED"; break;
|
||||
case LB_MEM_TABLE: entry_type="CONFIGURATION TABLES"; break;
|
||||
default: entry_type="UNKNOWN!"; break;
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "%2d. %016llx-%016llx: %s\n",
|
||||
i, entry_start, entry_start+entry_size-1, entry_type);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Routines to extract part so the coreboot table or
|
||||
* information from the coreboot table after we have written it.
|
||||
* Currently get_lb_mem relies on a global we can change the
|
||||
* implementaiton.
|
||||
*/
|
||||
static struct lb_memory *mem_ranges = 0;
|
||||
struct lb_memory *get_lb_mem(void)
|
||||
{
|
||||
return mem_ranges;
|
||||
}
|
||||
|
||||
static void build_lb_mem_range(void *gp, struct device *dev, struct resource *res)
|
||||
{
|
||||
struct lb_memory *mem = gp;
|
||||
new_lb_memory_range(mem, LB_MEM_RAM, res->base, res->size);
|
||||
}
|
||||
|
||||
static struct lb_memory *build_lb_mem(struct lb_header *head)
|
||||
{
|
||||
struct lb_memory *mem;
|
||||
|
||||
/* Record where the lb memory ranges will live */
|
||||
mem = lb_memory(head);
|
||||
mem_ranges = mem;
|
||||
|
||||
/* Build the raw table of memory */
|
||||
search_global_resources(
|
||||
IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE,
|
||||
build_lb_mem_range, mem);
|
||||
lb_cleanup_memory_ranges(mem);
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void lb_add_rsvd_range(void *gp, struct device *dev, struct resource *res)
|
||||
{
|
||||
struct lb_memory *mem = gp;
|
||||
lb_add_memory_range(mem, LB_MEM_RESERVED, res->base, res->size);
|
||||
}
|
||||
|
||||
static void add_lb_reserved(struct lb_memory *mem)
|
||||
{
|
||||
/* Add reserved ranges */
|
||||
search_global_resources(
|
||||
IORESOURCE_MEM | IORESOURCE_RESERVE, IORESOURCE_MEM | IORESOURCE_RESERVE,
|
||||
lb_add_rsvd_range, mem);
|
||||
}
|
||||
|
||||
unsigned long write_coreboot_table(
|
||||
unsigned long low_table_start, unsigned long low_table_end,
|
||||
unsigned long rom_table_start, unsigned long rom_table_end)
|
||||
{
|
||||
struct lb_header *head;
|
||||
struct lb_memory *mem;
|
||||
|
||||
#if CONFIG_WRITE_HIGH_TABLES
|
||||
printk(BIOS_DEBUG, "Writing high table forward entry at 0x%08lx\n",
|
||||
low_table_end);
|
||||
head = lb_table_init(low_table_end);
|
||||
lb_forward(head, (struct lb_header*)rom_table_end);
|
||||
|
||||
low_table_end = (unsigned long) lb_table_fini(head, 0);
|
||||
printk(BIOS_DEBUG, "New low_table_end: 0x%08lx\n", low_table_end);
|
||||
printk(BIOS_DEBUG, "Now going to write high coreboot table at 0x%08lx\n",
|
||||
rom_table_end);
|
||||
|
||||
head = lb_table_init(rom_table_end);
|
||||
rom_table_end = (unsigned long)head;
|
||||
printk(BIOS_DEBUG, "rom_table_end = 0x%08lx\n", rom_table_end);
|
||||
#else
|
||||
if(low_table_end > (0x1000 - sizeof(struct lb_header))) { /* after 4K */
|
||||
/* We need to put lbtable on to [0xf0000,0x100000) */
|
||||
head = lb_table_init(rom_table_end);
|
||||
rom_table_end = (unsigned long)head;
|
||||
} else {
|
||||
head = lb_table_init(low_table_end);
|
||||
low_table_end = (unsigned long)head;
|
||||
}
|
||||
#endif
|
||||
|
||||
printk(BIOS_DEBUG, "Adjust low_table_end from 0x%08lx to ", low_table_end);
|
||||
low_table_end += 0xfff; // 4K aligned
|
||||
low_table_end &= ~0xfff;
|
||||
printk(BIOS_DEBUG, "0x%08lx \n", low_table_end);
|
||||
|
||||
/* The Linux kernel assumes this region is reserved */
|
||||
printk(BIOS_DEBUG, "Adjust rom_table_end from 0x%08lx to ", rom_table_end);
|
||||
rom_table_end += 0xffff; // 64K align
|
||||
rom_table_end &= ~0xffff;
|
||||
printk(BIOS_DEBUG, "0x%08lx \n", rom_table_end);
|
||||
|
||||
#if CONFIG_USE_OPTION_TABLE
|
||||
{
|
||||
struct cmos_option_table *option_table = cbfs_find_file("cmos_layout.bin", 0x1aa);
|
||||
if (option_table) {
|
||||
struct lb_record *rec_dest = lb_new_record(head);
|
||||
/* Copy the option config table, it's already a lb_record... */
|
||||
memcpy(rec_dest, option_table, option_table->size);
|
||||
/* Create cmos checksum entry in coreboot table */
|
||||
lb_cmos_checksum(head);
|
||||
} else {
|
||||
printk(BIOS_ERR, "cmos_layout.bin could not be found!\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Record where RAM is located */
|
||||
mem = build_lb_mem(head);
|
||||
|
||||
/* Record the mptable and the the lb_table (This will be adjusted later) */
|
||||
lb_add_memory_range(mem, LB_MEM_TABLE,
|
||||
low_table_start, low_table_end - low_table_start);
|
||||
|
||||
/* Record the pirq table, acpi tables, and maybe the mptable */
|
||||
lb_add_memory_range(mem, LB_MEM_TABLE,
|
||||
rom_table_start, rom_table_end-rom_table_start);
|
||||
|
||||
#if CONFIG_WRITE_HIGH_TABLES
|
||||
printk(BIOS_DEBUG, "Adding high table area\n");
|
||||
// should this be LB_MEM_ACPI?
|
||||
lb_add_memory_range(mem, LB_MEM_TABLE,
|
||||
high_tables_base, high_tables_size);
|
||||
#endif
|
||||
|
||||
/* Add reserved regions */
|
||||
add_lb_reserved(mem);
|
||||
|
||||
lb_dump_memory_ranges(mem);
|
||||
|
||||
/* Note:
|
||||
* I assume that there is always memory at immediately after
|
||||
* the low_table_end. This means that after I setup the coreboot table.
|
||||
* I can trivially fixup the reserved memory ranges to hold the correct
|
||||
* size of the coreboot table.
|
||||
*/
|
||||
|
||||
/* Record our motherboard */
|
||||
lb_mainboard(head);
|
||||
/* Record the serial port, if present */
|
||||
lb_serial(head);
|
||||
/* Record our console setup */
|
||||
lb_console(head);
|
||||
/* Record our various random string information */
|
||||
lb_strings(head);
|
||||
/* Record our framebuffer */
|
||||
lb_framebuffer(head);
|
||||
|
||||
#if CONFIG_CHROMEOS
|
||||
/* Record our GPIO settings (ChromeOS specific) */
|
||||
lb_gpios(head);
|
||||
|
||||
/* pass along the VDAT buffer adress */
|
||||
lb_vdat(head);
|
||||
|
||||
/* pass along VBNV offsets in CMOS */
|
||||
lb_vbnv(head);
|
||||
#endif
|
||||
add_cbmem_pointers(head);
|
||||
|
||||
/* Remember where my valid memory ranges are */
|
||||
return lb_table_fini(head, 1);
|
||||
|
||||
}
|
77
src/arch/armv7/boot/multiboot.c
Normal file
77
src/arch/armv7/boot/multiboot.c
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* support for Multiboot payloads
|
||||
*
|
||||
* Copyright (C) 2008 Robert Millan
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cpu/x86/multiboot.h>
|
||||
#include <string.h>
|
||||
#include <device/resource.h>
|
||||
#include <console/console.h>
|
||||
#include <boot/coreboot_tables.h>
|
||||
#include <arch/coreboot_tables.h>
|
||||
|
||||
struct multiboot_info *mbi = NULL;
|
||||
|
||||
unsigned long write_multiboot_info(unsigned long rom_table_end)
|
||||
{
|
||||
static struct multiboot_mmap_entry *mb_mem;
|
||||
struct lb_memory* coreboot_table;
|
||||
int entries;
|
||||
int i;
|
||||
|
||||
mbi = (struct multiboot_info *)rom_table_end;
|
||||
|
||||
memset(mbi, 0, sizeof(*mbi));
|
||||
rom_table_end += sizeof(*mbi);
|
||||
|
||||
mbi->mmap_addr = (u32) rom_table_end;
|
||||
mb_mem = (struct multiboot_mmap_entry *)rom_table_end;
|
||||
|
||||
/* copy regions from coreboot tables */
|
||||
coreboot_table = get_lb_mem();
|
||||
entries = (coreboot_table->size - sizeof(*coreboot_table))/sizeof(coreboot_table->map[0]);
|
||||
|
||||
if (coreboot_table == NULL || entries < 1) {
|
||||
printk(BIOS_INFO, "%s: Cannot find coreboot table.\n", __func__);
|
||||
return (unsigned long) mb_mem;
|
||||
}
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
uint64_t entry_start = unpack_lb64(coreboot_table->map[i].start);
|
||||
uint64_t entry_size = unpack_lb64(coreboot_table->map[i].size);
|
||||
mb_mem->addr = entry_start;
|
||||
mb_mem->len = entry_size;
|
||||
switch (coreboot_table->map[i].type) {
|
||||
case LB_MEM_RAM:
|
||||
mb_mem->type = MULTIBOOT_MEMORY_AVAILABLE;
|
||||
break;
|
||||
default: // anything other than usable RAM
|
||||
mb_mem->type = MULTIBOOT_MEMORY_RESERVED;
|
||||
break;
|
||||
}
|
||||
mb_mem->size = sizeof(*mb_mem) - sizeof(mb_mem->size);
|
||||
mb_mem++;
|
||||
}
|
||||
|
||||
mbi->mmap_length = ((u32) mb_mem) - mbi->mmap_addr;
|
||||
mbi->flags |= MB_INFO_MEM_MAP;
|
||||
|
||||
printk(BIOS_INFO, "Multiboot Information structure has been written.\n");
|
||||
|
||||
return (unsigned long)mb_mem;
|
||||
}
|
100
src/arch/armv7/boot/tables.c
Normal file
100
src/arch/armv7/boot/tables.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2003 Eric Biederman
|
||||
* Copyright (C) 2005 Steve Magnani
|
||||
* Copyright (C) 2008-2009 coresystems GmbH
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <boot/tables.h>
|
||||
#include <boot/coreboot_tables.h>
|
||||
#include <arch/coreboot_tables.h>
|
||||
#include <string.h>
|
||||
#include <cbmem.h>
|
||||
#include <lib.h>
|
||||
|
||||
uint64_t high_tables_base = 0;
|
||||
uint64_t high_tables_size;
|
||||
|
||||
void cbmem_arch_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
struct lb_memory *write_tables(void)
|
||||
{
|
||||
unsigned long low_table_start, low_table_end;
|
||||
unsigned long rom_table_start, rom_table_end;
|
||||
|
||||
/* Even if high tables are configured, some tables are copied both to
|
||||
* the low and the high area, so payloads and OSes don't need to know
|
||||
* about the high tables.
|
||||
*/
|
||||
unsigned long high_table_pointer;
|
||||
|
||||
if (!high_tables_base) {
|
||||
printk(BIOS_ERR, "ERROR: High Tables Base is not set.\n");
|
||||
// Are there any boards without?
|
||||
// Stepan thinks we should die() here!
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "High Tables Base is %llx.\n", high_tables_base);
|
||||
|
||||
rom_table_start = 0xf0000;
|
||||
rom_table_end = 0xf0000;
|
||||
|
||||
/* Start low addr at 0x500, so we don't run into conflicts with the BDA
|
||||
* in case our data structures grow beyound 0x400. Only multiboot, GDT
|
||||
* and the coreboot table use low_tables.
|
||||
*/
|
||||
low_table_start = 0;
|
||||
low_table_end = 0x500;
|
||||
|
||||
#define MAX_COREBOOT_TABLE_SIZE (8 * 1024)
|
||||
post_code(0x9d);
|
||||
|
||||
high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_CBTABLE, MAX_COREBOOT_TABLE_SIZE);
|
||||
|
||||
if (high_table_pointer) {
|
||||
unsigned long new_high_table_pointer;
|
||||
|
||||
/* Also put a forwarder entry into 0-4K */
|
||||
new_high_table_pointer = write_coreboot_table(low_table_start, low_table_end,
|
||||
high_tables_base, high_table_pointer);
|
||||
|
||||
if (new_high_table_pointer > (high_table_pointer +
|
||||
MAX_COREBOOT_TABLE_SIZE))
|
||||
printk(BIOS_ERR, "%s: coreboot table didn't fit (%lx)\n",
|
||||
__func__, new_high_table_pointer -
|
||||
high_table_pointer);
|
||||
|
||||
printk(BIOS_DEBUG, "coreboot table: %ld bytes.\n",
|
||||
new_high_table_pointer - high_table_pointer);
|
||||
} else {
|
||||
/* The coreboot table must be in 0-4K or 960K-1M */
|
||||
rom_table_end = write_coreboot_table(
|
||||
low_table_start, low_table_end,
|
||||
rom_table_start, rom_table_end);
|
||||
}
|
||||
|
||||
post_code(0x9e);
|
||||
|
||||
// Remove before sending upstream
|
||||
cbmem_list();
|
||||
|
||||
return get_lb_mem();
|
||||
}
|
94
src/arch/armv7/boot/wakeup.S
Normal file
94
src/arch/armv7/boot/wakeup.S
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define WAKEUP_BASE 0x600
|
||||
#define RELOCATED(x) (x - __wakeup + WAKEUP_BASE)
|
||||
|
||||
/* CR0 bits */
|
||||
#define PE (1 << 0)
|
||||
|
||||
.code32
|
||||
.globl __wakeup
|
||||
__wakeup:
|
||||
/* First prepare the jmp to the resume vector */
|
||||
mov 0x4(%esp), %eax /* vector */
|
||||
/* last 4 bits of linear addr are taken as offset */
|
||||
andw $0x0f, %ax
|
||||
movw %ax, (__wakeup_offset)
|
||||
mov 0x4(%esp), %eax
|
||||
/* the rest is taken as segment */
|
||||
shr $4, %eax
|
||||
movw %ax, (__wakeup_segment)
|
||||
|
||||
/* Then overwrite coreboot with our backed up memory */
|
||||
cld
|
||||
movl 8(%esp), %esi
|
||||
movl 12(%esp), %edi
|
||||
movl 16(%esp), %ecx
|
||||
shrl $2, %ecx
|
||||
rep movsl
|
||||
|
||||
/* Activate the right segment descriptor real mode. */
|
||||
ljmp $0x28, $RELOCATED(1f)
|
||||
1:
|
||||
.code16
|
||||
/* 16 bit code from here on... */
|
||||
|
||||
/* Load the segment registers w/ properly configured
|
||||
* segment descriptors. They will retain these
|
||||
* configurations (limits, writability, etc.) once
|
||||
* protected mode is turned off.
|
||||
*/
|
||||
mov $0x30, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
|
||||
/* Turn off protection */
|
||||
movl %cr0, %eax
|
||||
andl $~PE, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Now really going into real mode */
|
||||
ljmp $0, $RELOCATED(1f)
|
||||
1:
|
||||
movw $0x0, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %ss
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
|
||||
/* This is a FAR JMP to the OS waking vector. The C code changed
|
||||
* the address to be correct.
|
||||
*/
|
||||
.byte 0xea
|
||||
|
||||
__wakeup_offset = RELOCATED(.)
|
||||
.word 0x0000
|
||||
|
||||
__wakeup_segment = RELOCATED(.)
|
||||
.word 0x0000
|
||||
|
||||
.globl __wakeup_size
|
||||
__wakeup_size = ( . - __wakeup)
|
||||
|
51
src/arch/armv7/bootblock_simple.c
Normal file
51
src/arch/armv7/bootblock_simple.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Google Inc
|
||||
*
|
||||
* 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; version 2 of
|
||||
* the License.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <bootblock_common.h>
|
||||
|
||||
|
||||
#include "../../lib/uart8250.c"
|
||||
#include "lib/div.c"
|
||||
|
||||
struct uart8250 uart = {
|
||||
115200
|
||||
};
|
||||
|
||||
void main(unsigned long bist)
|
||||
{
|
||||
init_uart8250(CONFIG_TTYS0_BASE, &uart);
|
||||
uart8250_tx_byte(CONFIG_TTYS0_BASE, '@');
|
||||
|
||||
if (boot_cpu()) {
|
||||
bootblock_cpu_init();
|
||||
bootblock_northbridge_init();
|
||||
bootblock_southbridge_init();
|
||||
}
|
||||
const char* target1 = "fallback/romstage";
|
||||
unsigned long entry;
|
||||
entry = findstage(target1);
|
||||
if (entry) call(entry, bist);
|
||||
|
||||
hlt();
|
||||
}
|
||||
|
128
src/arch/armv7/coreboot_ram.ld
Normal file
128
src/arch/armv7/coreboot_ram.ld
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Memory map:
|
||||
*
|
||||
* CONFIG_RAMBASE : text segment
|
||||
* : rodata segment
|
||||
* : data segment
|
||||
* : bss segment
|
||||
* : stack
|
||||
* : heap
|
||||
*/
|
||||
/*
|
||||
* Bootstrap code for the STPC Consumer
|
||||
* Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Written by Johan Rydberg, based on work by Daniel Kahlin.
|
||||
* Rewritten by Eric Biederman
|
||||
* 2005.12 yhlu add coreboot_ram cross the vga font buffer handling
|
||||
*/
|
||||
|
||||
/* We use ELF as output format. So that we can debug the code in some form. */
|
||||
INCLUDE ldoptions
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = CONFIG_RAMBASE;
|
||||
/* First we place the code and read only data (typically const declared).
|
||||
* This could theoretically be placed in rom.
|
||||
*/
|
||||
.text : {
|
||||
_text = .;
|
||||
*(.text);
|
||||
*(.text.*);
|
||||
. = ALIGN(16);
|
||||
_etext = .;
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
_rodata = .;
|
||||
. = ALIGN(4);
|
||||
console_drivers = .;
|
||||
*(.rodata.console_drivers)
|
||||
econsole_drivers = . ;
|
||||
. = ALIGN(4);
|
||||
pci_drivers = . ;
|
||||
*(.rodata.pci_driver)
|
||||
epci_drivers = . ;
|
||||
cpu_drivers = . ;
|
||||
*(.rodata.cpu_driver)
|
||||
ecpu_drivers = . ;
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
/* kevinh/Ispiri - Added an align, because the objcopy tool
|
||||
* incorrectly converts sections that are not long word aligned.
|
||||
*/
|
||||
. = ALIGN(4);
|
||||
|
||||
_erodata = .;
|
||||
}
|
||||
/* After the code we place initialized data (typically initialized
|
||||
* global variables). This gets copied into ram by startup code.
|
||||
* __data_start and __data_end shows where in ram this should be placed,
|
||||
* whereas __data_loadstart and __data_loadend shows where in rom to
|
||||
* copy from.
|
||||
*/
|
||||
.data : {
|
||||
_data = .;
|
||||
*(.data)
|
||||
_edata = .;
|
||||
}
|
||||
|
||||
/* bss does not contain data, it is just a space that should be zero
|
||||
* initialized on startup. (typically uninitialized global variables)
|
||||
* crt0.S fills between _bss and _ebss with zeroes.
|
||||
*/
|
||||
_bss = .;
|
||||
.bss . : {
|
||||
*(.bss)
|
||||
*(.sbss)
|
||||
*(COMMON)
|
||||
}
|
||||
_ebss = .;
|
||||
_end = .;
|
||||
|
||||
/* coreboot really "ends" here. Only heap and stack are placed after
|
||||
* this line.
|
||||
*/
|
||||
|
||||
. = ALIGN(CONFIG_STACK_SIZE);
|
||||
|
||||
_stack = .;
|
||||
.stack . : {
|
||||
/* Reserve a stack for each possible cpu */
|
||||
. += CONFIG_MAX_CPUS*CONFIG_STACK_SIZE;
|
||||
}
|
||||
_estack = .;
|
||||
|
||||
_heap = .;
|
||||
.heap . : {
|
||||
/* Reserve CONFIG_HEAP_SIZE bytes for the heap */
|
||||
. = CONFIG_HEAP_SIZE ;
|
||||
. = ALIGN(4);
|
||||
}
|
||||
_eheap = .;
|
||||
|
||||
/* The ram segment. This includes all memory used by the memory
|
||||
* resident copy of coreboot, except the tables that are produced on
|
||||
* the fly, but including stack and heap.
|
||||
*/
|
||||
_ram_seg = _text;
|
||||
_eram_seg = _eheap;
|
||||
|
||||
/* CONFIG_RAMTOP is the upper address of cached memory (among other
|
||||
* things). We must not exceed beyond that address, there be dragons.
|
||||
*/
|
||||
_bogus = ASSERT( ( _eram_seg < (CONFIG_RAMTOP)) , "Please increase CONFIG_RAMTOP");
|
||||
|
||||
/* Discard the sections we don't need/want */
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment)
|
||||
*(.note)
|
||||
*(.note.*)
|
||||
}
|
||||
}
|
101
src/arch/armv7/cpu.c
Normal file
101
src/arch/armv7/cpu.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* (C) Copyright 2008 Texas Insturments
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@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
|
||||
*/
|
||||
|
||||
/*
|
||||
* CPU specific code
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/armv7.h>
|
||||
#ifdef CONFIG_EXYNOS_LCD
|
||||
#include <exynos-fb.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void save_boot_params_default(u32 r0, u32 r1, u32 r2, u32 r3)
|
||||
{
|
||||
}
|
||||
|
||||
void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3)
|
||||
__attribute__((weak, alias("save_boot_params_default")));
|
||||
|
||||
#if 0
|
||||
int cleanup_before_linux(void)
|
||||
{
|
||||
#ifdef CONFIG_BOOTSTAGE_REPORT
|
||||
bootstage_report();
|
||||
#endif
|
||||
#ifdef CONFIG_BOOTSTAGE_STASH
|
||||
bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH,
|
||||
CONFIG_BOOTSTAGE_STASH_SIZE);
|
||||
#endif
|
||||
/*
|
||||
* this function is called just before we call linux
|
||||
* it prepares the processor for linux
|
||||
*
|
||||
* we turn off caches etc ...
|
||||
*/
|
||||
disable_interrupts();
|
||||
|
||||
#ifdef CONFIG_EXYNOS_LCD
|
||||
exynos_fimd_disable();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Turn off I-cache and invalidate it
|
||||
*/
|
||||
icache_disable();
|
||||
invalidate_icache_all();
|
||||
|
||||
/*
|
||||
* turn off D-cache
|
||||
* dcache_disable() in turn flushes the d-cache and disables MMU
|
||||
*/
|
||||
dcache_disable();
|
||||
v7_outer_cache_disable();
|
||||
|
||||
/*
|
||||
* After D-cache is flushed and before it is disabled there may
|
||||
* be some new valid entries brought into the cache. We are sure
|
||||
* that these lines are not dirty and will not affect our execution.
|
||||
* (because unwinding the call-stack and setting a bit in CP15 SCTRL
|
||||
* is all we did during this. We have not pushed anything on to the
|
||||
* stack. Neither have we affected any static data)
|
||||
* So just invalidate the entire d-cache again to avoid coherency
|
||||
* problems for kernel
|
||||
*/
|
||||
invalidate_dcache_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
111
src/arch/armv7/include/arch/atomic.h
Normal file
111
src/arch/armv7/include/arch/atomic.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* linux/include/asm-arm/atomic.h
|
||||
*
|
||||
* Copyright (c) 1996 Russell King.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Changelog:
|
||||
* 27-06-1996 RMK Created
|
||||
* 13-04-1997 RMK Made functions atomic!
|
||||
* 07-12-1997 RMK Upgraded for v2.1.
|
||||
* 26-08-1998 PJB Added #ifdef __KERNEL__
|
||||
*/
|
||||
#ifndef __ASM_ARM_ATOMIC_H
|
||||
#define __ASM_ARM_ATOMIC_H
|
||||
|
||||
#include <linux/config.h>
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#error SMP not supported
|
||||
#endif
|
||||
|
||||
typedef struct { volatile int counter; } atomic_t;
|
||||
|
||||
#define ATOMIC_INIT(i) { (i) }
|
||||
|
||||
#include <asm/proc/system.h>
|
||||
|
||||
#define atomic_read(v) ((v)->counter)
|
||||
#define atomic_set(v,i) (((v)->counter) = (i))
|
||||
|
||||
static inline void atomic_add(int i, volatile atomic_t *v)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
v->counter += i;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static inline void atomic_sub(int i, volatile atomic_t *v)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
v->counter -= i;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static inline void atomic_inc(volatile atomic_t *v)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
v->counter += 1;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static inline void atomic_dec(volatile atomic_t *v)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
v->counter -= 1;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static inline int atomic_dec_and_test(volatile atomic_t *v)
|
||||
{
|
||||
unsigned long flags;
|
||||
int val;
|
||||
|
||||
local_irq_save(flags);
|
||||
val = v->counter;
|
||||
v->counter = val -= 1;
|
||||
local_irq_restore(flags);
|
||||
|
||||
return val == 0;
|
||||
}
|
||||
|
||||
static inline int atomic_add_negative(int i, volatile atomic_t *v)
|
||||
{
|
||||
unsigned long flags;
|
||||
int val;
|
||||
|
||||
local_irq_save(flags);
|
||||
val = v->counter;
|
||||
v->counter = val += i;
|
||||
local_irq_restore(flags);
|
||||
|
||||
return val < 0;
|
||||
}
|
||||
|
||||
static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
*addr &= ~mask;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/* Atomic operations are already serializing on ARM */
|
||||
#define smp_mb__before_atomic_dec() barrier()
|
||||
#define smp_mb__after_atomic_dec() barrier()
|
||||
#define smp_mb__before_atomic_inc() barrier()
|
||||
#define smp_mb__after_atomic_inc() barrier()
|
||||
|
||||
#endif
|
8
src/arch/armv7/include/arch/boot/boot.h
Normal file
8
src/arch/armv7/include/arch/boot/boot.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef ASM_ARM_BOOT_H
|
||||
#define ASM_ARM_BOOT_H
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#define ELF_ARCH EM_ARM
|
||||
|
||||
#endif /* ASM_ARM_BOOT_H */
|
27
src/arch/armv7/include/arch/byteorder.h
Normal file
27
src/arch/armv7/include/arch/byteorder.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef _BYTEORDER_H
|
||||
#define _BYTEORDER_H
|
||||
|
||||
#define __LITTLE_ENDIAN 1234
|
||||
|
||||
#include <stdint.h>
|
||||
#include <swab.h>
|
||||
|
||||
#define cpu_to_le64(x) ((uint64_t)(x))
|
||||
#define le64_to_cpu(x) ((uint64_t)(x))
|
||||
#define cpu_to_le32(x) ((uint32_t)(x))
|
||||
#define le32_to_cpu(x) ((uint32_t)(x))
|
||||
#define cpu_to_le16(x) ((uint16_t)(x))
|
||||
#define le16_to_cpu(x) ((uint16_t)(x))
|
||||
#define cpu_to_be64(x) swab64(x)
|
||||
#define be64_to_cpu(x) swab64(x)
|
||||
#define cpu_to_be32(x) swab32((x))
|
||||
#define be32_to_cpu(x) swab32((x))
|
||||
#define cpu_to_be16(x) swab16((x))
|
||||
#define be16_to_cpu(x) swab16((x))
|
||||
|
||||
#define ntohll(x) be64_to_cpu(x)
|
||||
#define htonll(x) cpu_to_be64(x)
|
||||
#define ntohl(x) be32_to_cpu(x)
|
||||
#define htonl(x) cpu_to_be32(x)
|
||||
|
||||
#endif /* _BYTEORDER_H */
|
25
src/arch/armv7/include/arch/coreboot_tables.h
Normal file
25
src/arch/armv7/include/arch/coreboot_tables.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef COREBOOT_TABLE_H
|
||||
#define COREBOOT_TABLE_H
|
||||
|
||||
#include <boot/coreboot_tables.h>
|
||||
|
||||
/* This file holds function prototypes for building the coreboot table. */
|
||||
unsigned long write_coreboot_table(
|
||||
unsigned long low_table_start, unsigned long low_table_end,
|
||||
unsigned long rom_table_start, unsigned long rom_table_end);
|
||||
|
||||
void lb_memory_range(struct lb_memory *mem,
|
||||
uint32_t type, uint64_t start, uint64_t size);
|
||||
|
||||
/* Routines to extract part so the coreboot table or information
|
||||
* from the coreboot table.
|
||||
*/
|
||||
struct lb_memory *get_lb_mem(void);
|
||||
|
||||
extern struct cmos_option_table option_table;
|
||||
|
||||
/* defined by mainboard.c if the mainboard requires extra resources */
|
||||
int add_mainboard_resources(struct lb_memory *mem);
|
||||
int add_northbridge_resources(struct lb_memory *mem);
|
||||
|
||||
#endif /* COREBOOT_TABLE_H */
|
@ -22,4 +22,25 @@
|
||||
|
||||
#define asmlinkage
|
||||
|
||||
#if !defined(__PRE_RAM__)
|
||||
#include <device/device.h>
|
||||
|
||||
struct cpu_driver {
|
||||
struct device_operations *ops;
|
||||
struct cpu_device_id *id_table;
|
||||
};
|
||||
|
||||
struct cpu_info {
|
||||
device_t cpu;
|
||||
unsigned long index;
|
||||
};
|
||||
|
||||
struct cpuinfo_arm {
|
||||
uint8_t arm; /* CPU family */
|
||||
uint8_t arm_vendor; /* CPU vendor */
|
||||
uint8_t arm_model;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_CPU_H__ */
|
||||
|
98
src/arch/armv7/include/arch/gpio.h
Normal file
98
src/arch/armv7/include/arch/gpio.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors.
|
||||
* Copyright (c) 2011, NVIDIA Corp. All rights reserved.
|
||||
* 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 _ASM_GENERIC_GPIO_H_
|
||||
#define _ASM_GENERIC_GPIO_H_
|
||||
|
||||
/*
|
||||
* Generic GPIO API for U-Boot
|
||||
*
|
||||
* GPIOs are numbered from 0 to GPIO_COUNT-1 which value is defined
|
||||
* by the SOC/architecture.
|
||||
*
|
||||
* Each GPIO can be an input or output. If an input then its value can
|
||||
* be read as 0 or 1. If an output then its value can be set to 0 or 1.
|
||||
* If you try to write an input then the value is undefined. If you try
|
||||
* to read an output, barring something very unusual, you will get
|
||||
* back the value of the output that you previously set.
|
||||
*
|
||||
* In some cases the operation may fail, for example if the GPIO number
|
||||
* is out of range, or the GPIO is not available because its pin is
|
||||
* being used by another function. In that case, functions may return
|
||||
* an error value of -1.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Stop using the GPIO. This function should not alter pin configuration.
|
||||
*
|
||||
* @param gpio GPIO number
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int gpio_free(unsigned gpio);
|
||||
|
||||
/**
|
||||
* Make a GPIO an input.
|
||||
*
|
||||
* @param gpio GPIO number
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int gpio_direction_input(unsigned gpio);
|
||||
|
||||
/**
|
||||
* Make a GPIO an output, and set its value.
|
||||
*
|
||||
* @param gpio GPIO number
|
||||
* @param value GPIO value (0 for low or 1 for high)
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int gpio_direction_output(unsigned gpio, int value);
|
||||
|
||||
/**
|
||||
* Get a GPIO's value. This will work whether the GPIO is an input
|
||||
* or an output.
|
||||
*
|
||||
* @param gpio GPIO number
|
||||
* @return 0 if low, 1 if high, -1 on error
|
||||
*/
|
||||
int gpio_get_value(unsigned gpio);
|
||||
|
||||
/**
|
||||
* Set an output GPIO's value. The GPIO must already be an output or
|
||||
* this function may have no effect.
|
||||
*
|
||||
* @param gpio GPIO number
|
||||
* @param value GPIO value (0 for low or 1 for high)
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int gpio_set_value(unsigned gpio, int value);
|
||||
|
||||
/**
|
||||
* Request ownership of a gpio. This should be called before any of the other
|
||||
* functions are used on this gpio.
|
||||
*
|
||||
* @param gp GPIO number
|
||||
* @param label User label for this GPIO
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int gpio_request(unsigned gpio, const char *label);
|
||||
|
||||
#endif /* _ASM_GENERIC_GPIO_H_ */
|
10
src/arch/armv7/include/arch/hlt.h
Normal file
10
src/arch/armv7/include/arch/hlt.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef ARCH_HLT_H
|
||||
#define ARCH_HLT_H
|
||||
|
||||
static inline __attribute__((always_inline)) void hlt(void)
|
||||
{
|
||||
for (;;) ;
|
||||
//asm("hlt");
|
||||
}
|
||||
|
||||
#endif /* ARCH_HLT_H */
|
427
src/arch/armv7/include/arch/io.h
Normal file
427
src/arch/armv7/include/arch/io.h
Normal file
@ -0,0 +1,427 @@
|
||||
/*
|
||||
* linux/include/asm-arm/io.h
|
||||
*
|
||||
* Copyright (C) 1996-2000 Russell King
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modifications:
|
||||
* 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both
|
||||
* constant addresses and variable addresses.
|
||||
* 04-Dec-1997 RMK Moved a lot of this stuff to the new architecture
|
||||
* specific IO header files.
|
||||
* 27-Mar-1999 PJB Second parameter of memcpy_toio is const..
|
||||
* 04-Apr-1999 PJB Added check_signature.
|
||||
* 12-Dec-1999 RMK More cleanups
|
||||
* 18-Jun-2000 RMK Removed virt_to_* and friends definitions
|
||||
*/
|
||||
#ifndef __ASM_ARM_IO_H
|
||||
#define __ASM_ARM_IO_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <types.h>
|
||||
#include <arch/byteorder.h>
|
||||
#if 0 /* XXX###XXX */
|
||||
#include <asm/arch/hardware.h>
|
||||
#endif /* XXX###XXX */
|
||||
|
||||
static inline void sync(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic virtual read/write. Note that we don't support half-word
|
||||
* read/writes. We define __arch_*[bl] here, and leave __arch_*w
|
||||
* to the architecture specific code.
|
||||
*/
|
||||
#define __arch_getb(a) (*(volatile unsigned char *)(a))
|
||||
#define __arch_getw(a) (*(volatile unsigned short *)(a))
|
||||
#define __arch_getl(a) (*(volatile unsigned int *)(a))
|
||||
|
||||
#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v))
|
||||
#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v))
|
||||
#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v))
|
||||
|
||||
#if 0
|
||||
extern inline void __raw_writesb(unsigned int addr, const void *data, int bytelen)
|
||||
{
|
||||
uint8_t *buf = (uint8_t *)data;
|
||||
while(bytelen--)
|
||||
__arch_putb(*buf++, addr);
|
||||
}
|
||||
|
||||
extern inline void __raw_writesw(unsigned int addr, const void *data, int wordlen)
|
||||
{
|
||||
uint16_t *buf = (uint16_t *)data;
|
||||
while(wordlen--)
|
||||
__arch_putw(*buf++, addr);
|
||||
}
|
||||
|
||||
extern inline void __raw_writesl(unsigned int addr, const void *data, int longlen)
|
||||
{
|
||||
uint32_t *buf = (uint32_t *)data;
|
||||
while(longlen--)
|
||||
__arch_putl(*buf++, addr);
|
||||
}
|
||||
|
||||
extern inline void __raw_readsb(unsigned int addr, void *data, int bytelen)
|
||||
{
|
||||
uint8_t *buf = (uint8_t *)data;
|
||||
while(bytelen--)
|
||||
*buf++ = __arch_getb(addr);
|
||||
}
|
||||
|
||||
extern inline void __raw_readsw(unsigned int addr, void *data, int wordlen)
|
||||
{
|
||||
uint16_t *buf = (uint16_t *)data;
|
||||
while(wordlen--)
|
||||
*buf++ = __arch_getw(addr);
|
||||
}
|
||||
|
||||
extern inline void __raw_readsl(unsigned int addr, void *data, int longlen)
|
||||
{
|
||||
uint32_t *buf = (uint32_t *)data;
|
||||
while(longlen--)
|
||||
*buf++ = __arch_getl(addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define __raw_writeb(v,a) __arch_putb(v,a)
|
||||
#define __raw_writew(v,a) __arch_putw(v,a)
|
||||
#define __raw_writel(v,a) __arch_putl(v,a)
|
||||
|
||||
#define __raw_readb(a) __arch_getb(a)
|
||||
#define __raw_readw(a) __arch_getw(a)
|
||||
#define __raw_readl(a) __arch_getl(a)
|
||||
|
||||
/*
|
||||
* TODO: The kernel offers some more advanced versions of barriers, it might
|
||||
* have some advantages to use them instead of the simple one here.
|
||||
*/
|
||||
#define dmb() __asm__ __volatile__ ("" : : : "memory")
|
||||
#define __iormb() dmb()
|
||||
#define __iowmb() dmb()
|
||||
|
||||
#define writeb(v,c) ({ u8 __v = v; __iowmb(); __arch_putb(__v,c); __v; })
|
||||
#define writew(v,c) ({ u16 __v = v; __iowmb(); __arch_putw(__v,c); __v; })
|
||||
#define writel(v,c) ({ u32 __v = v; __iowmb(); __arch_putl(__v,c); __v; })
|
||||
|
||||
#define readb(c) ({ u8 __v = __arch_getb(c); __iormb(); __v; })
|
||||
#define readw(c) ({ u16 __v = __arch_getw(c); __iormb(); __v; })
|
||||
#define readl(c) ({ u32 __v = __arch_getl(c); __iormb(); __v; })
|
||||
|
||||
/*
|
||||
* The compiler seems to be incapable of optimising constants
|
||||
* properly. Spell it out to the compiler in some cases.
|
||||
* These are only valid for small values of "off" (< 1<<12)
|
||||
*/
|
||||
#define __raw_base_writeb(val,base,off) __arch_base_putb(val,base,off)
|
||||
#define __raw_base_writew(val,base,off) __arch_base_putw(val,base,off)
|
||||
#define __raw_base_writel(val,base,off) __arch_base_putl(val,base,off)
|
||||
|
||||
#define __raw_base_readb(base,off) __arch_base_getb(base,off)
|
||||
#define __raw_base_readw(base,off) __arch_base_getw(base,off)
|
||||
#define __raw_base_readl(base,off) __arch_base_getl(base,off)
|
||||
|
||||
/*
|
||||
* Clear and set bits in one shot. These macros can be used to clear and
|
||||
* set multiple bits in a register using a single call. These macros can
|
||||
* also be used to set a multiple-bit bit pattern using a mask, by
|
||||
* specifying the mask in the 'clear' parameter and the new bit pattern
|
||||
* in the 'set' parameter.
|
||||
*/
|
||||
|
||||
#define out_arch(type,endian,a,v) __raw_write##type(cpu_to_##endian(v),a)
|
||||
#define in_arch(type,endian,a) endian##_to_cpu(__raw_read##type(a))
|
||||
|
||||
#define out_le32(a,v) out_arch(l,le32,a,v)
|
||||
#define out_le16(a,v) out_arch(w,le16,a,v)
|
||||
|
||||
#define in_le32(a) in_arch(l,le32,a)
|
||||
#define in_le16(a) in_arch(w,le16,a)
|
||||
|
||||
#define out_be32(a,v) out_arch(l,be32,a,v)
|
||||
#define out_be16(a,v) out_arch(w,be16,a,v)
|
||||
|
||||
#define in_be32(a) in_arch(l,be32,a)
|
||||
#define in_be16(a) in_arch(w,be16,a)
|
||||
|
||||
#define out_8(a,v) __raw_writeb(v,a)
|
||||
#define in_8(a) __raw_readb(a)
|
||||
|
||||
#define clrbits(type, addr, clear) \
|
||||
out_##type((addr), in_##type(addr) & ~(clear))
|
||||
|
||||
#define setbits(type, addr, set) \
|
||||
out_##type((addr), in_##type(addr) | (set))
|
||||
|
||||
#define clrsetbits(type, addr, clear, set) \
|
||||
out_##type((addr), (in_##type(addr) & ~(clear)) | (set))
|
||||
|
||||
#define clrbits_be32(addr, clear) clrbits(be32, addr, clear)
|
||||
#define setbits_be32(addr, set) setbits(be32, addr, set)
|
||||
#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set)
|
||||
|
||||
#define clrbits_le32(addr, clear) clrbits(le32, addr, clear)
|
||||
#define setbits_le32(addr, set) setbits(le32, addr, set)
|
||||
#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set)
|
||||
|
||||
#define clrbits_be16(addr, clear) clrbits(be16, addr, clear)
|
||||
#define setbits_be16(addr, set) setbits(be16, addr, set)
|
||||
#define clrsetbits_be16(addr, clear, set) clrsetbits(be16, addr, clear, set)
|
||||
|
||||
#define clrbits_le16(addr, clear) clrbits(le16, addr, clear)
|
||||
#define setbits_le16(addr, set) setbits(le16, addr, set)
|
||||
#define clrsetbits_le16(addr, clear, set) clrsetbits(le16, addr, clear, set)
|
||||
|
||||
#define clrbits_8(addr, clear) clrbits(8, addr, clear)
|
||||
#define setbits_8(addr, set) setbits(8, addr, set)
|
||||
#define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set)
|
||||
|
||||
/*
|
||||
* Now, pick up the machine-defined IO definitions
|
||||
*/
|
||||
#if 0 /* XXX###XXX */
|
||||
#include <asm/arch/io.h>
|
||||
#endif /* XXX###XXX */
|
||||
|
||||
/*
|
||||
* IO port access primitives
|
||||
* -------------------------
|
||||
*
|
||||
* The ARM doesn't have special IO access instructions; all IO is memory
|
||||
* mapped. Note that these are defined to perform little endian accesses
|
||||
* only. Their primary purpose is to access PCI and ISA peripherals.
|
||||
*
|
||||
* Note that for a big endian machine, this implies that the following
|
||||
* big endian mode connectivity is in place, as described by numerous
|
||||
* ARM documents:
|
||||
*
|
||||
* PCI: D0-D7 D8-D15 D16-D23 D24-D31
|
||||
* ARM: D24-D31 D16-D23 D8-D15 D0-D7
|
||||
*
|
||||
* The machine specific io.h include defines __io to translate an "IO"
|
||||
* address to a memory address.
|
||||
*
|
||||
* Note that we prevent GCC re-ordering or caching values in expressions
|
||||
* by introducing sequence points into the in*() definitions. Note that
|
||||
* __raw_* do not guarantee this behaviour.
|
||||
*
|
||||
* The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space.
|
||||
*/
|
||||
#ifdef __io
|
||||
#define outb(v,p) __raw_writeb(v,__io(p))
|
||||
#define outw(v,p) __raw_writew(cpu_to_le16(v),__io(p))
|
||||
#define outl(v,p) __raw_writel(cpu_to_le32(v),__io(p))
|
||||
|
||||
#define inb(p) ({ unsigned int __v = __raw_readb(__io(p)); __v; })
|
||||
#define inw(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; })
|
||||
#define inl(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; })
|
||||
|
||||
#define outsb(p,d,l) __raw_writesb(__io(p),d,l)
|
||||
#define outsw(p,d,l) __raw_writesw(__io(p),d,l)
|
||||
#define outsl(p,d,l) __raw_writesl(__io(p),d,l)
|
||||
|
||||
#define insb(p,d,l) __raw_readsb(__io(p),d,l)
|
||||
#define insw(p,d,l) __raw_readsw(__io(p),d,l)
|
||||
#define insl(p,d,l) __raw_readsl(__io(p),d,l)
|
||||
#endif
|
||||
|
||||
#define outb_p(val,port) outb((val),(port))
|
||||
#define outw_p(val,port) outw((val),(port))
|
||||
#define outl_p(val,port) outl((val),(port))
|
||||
#define inb_p(port) inb((port))
|
||||
#define inw_p(port) inw((port))
|
||||
#define inl_p(port) inl((port))
|
||||
|
||||
#define outsb_p(port,from,len) outsb(port,from,len)
|
||||
#define outsw_p(port,from,len) outsw(port,from,len)
|
||||
#define outsl_p(port,from,len) outsl(port,from,len)
|
||||
#define insb_p(port,to,len) insb(port,to,len)
|
||||
#define insw_p(port,to,len) insw(port,to,len)
|
||||
#define insl_p(port,to,len) insl(port,to,len)
|
||||
|
||||
/*
|
||||
* ioremap and friends.
|
||||
*
|
||||
* ioremap takes a PCI memory address, as specified in
|
||||
* linux/Documentation/IO-mapping.txt. If you want a
|
||||
* physical address, use __ioremap instead.
|
||||
*/
|
||||
extern void * __ioremap(unsigned long offset, size_t size, unsigned long flags);
|
||||
extern void __iounmap(void *addr);
|
||||
|
||||
/*
|
||||
* Generic ioremap support.
|
||||
*
|
||||
* Define:
|
||||
* iomem_valid_addr(off,size)
|
||||
* iomem_to_phys(off)
|
||||
*/
|
||||
#ifdef iomem_valid_addr
|
||||
#define __arch_ioremap(off,sz,nocache) \
|
||||
({ \
|
||||
unsigned long _off = (off), _size = (sz); \
|
||||
void *_ret = (void *)0; \
|
||||
if (iomem_valid_addr(_off, _size)) \
|
||||
_ret = __ioremap(iomem_to_phys(_off),_size,nocache); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define __arch_iounmap __iounmap
|
||||
#endif
|
||||
|
||||
/*
|
||||
* String version of IO memory access ops:
|
||||
*/
|
||||
extern void _memcpy_fromio(void *, unsigned long, size_t);
|
||||
extern void _memcpy_toio(unsigned long, const void *, size_t);
|
||||
extern void _memset_io(unsigned long, int, size_t);
|
||||
|
||||
extern void __readwrite_bug(const char *fn);
|
||||
|
||||
/*
|
||||
* If this architecture has PCI memory IO, then define the read/write
|
||||
* macros. These should only be used with the cookie passed from
|
||||
* ioremap.
|
||||
*/
|
||||
#ifdef __mem_pci
|
||||
|
||||
#define readb(c) ({ unsigned int __v = __raw_readb(__mem_pci(c)); __v; })
|
||||
#define readw(c) ({ unsigned int __v = le16_to_cpu(__raw_readw(__mem_pci(c))); __v; })
|
||||
#define readl(c) ({ unsigned int __v = le32_to_cpu(__raw_readl(__mem_pci(c))); __v; })
|
||||
|
||||
#define writeb(v,c) __raw_writeb(v,__mem_pci(c))
|
||||
#define writew(v,c) __raw_writew(cpu_to_le16(v),__mem_pci(c))
|
||||
#define writel(v,c) __raw_writel(cpu_to_le32(v),__mem_pci(c))
|
||||
|
||||
#define memset_io(c,v,l) _memset_io(__mem_pci(c),(v),(l))
|
||||
#define memcpy_fromio(a,c,l) _memcpy_fromio((a),__mem_pci(c),(l))
|
||||
#define memcpy_toio(c,a,l) _memcpy_toio(__mem_pci(c),(a),(l))
|
||||
|
||||
#define eth_io_copy_and_sum(s,c,l,b) \
|
||||
eth_copy_and_sum((s),__mem_pci(c),(l),(b))
|
||||
|
||||
static inline int
|
||||
check_signature(unsigned long io_addr, const unsigned char *signature,
|
||||
int length)
|
||||
{
|
||||
int retval = 0;
|
||||
do {
|
||||
if (readb(io_addr) != *signature)
|
||||
goto out;
|
||||
io_addr++;
|
||||
signature++;
|
||||
length--;
|
||||
} while (length);
|
||||
retval = 1;
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
#elif !defined(readb)
|
||||
|
||||
#define readb(addr) (__readwrite_bug("readb"),0)
|
||||
#define readw(addr) (__readwrite_bug("readw"),0)
|
||||
#define readl(addr) (__readwrite_bug("readl"),0)
|
||||
#define writeb(v,addr) __readwrite_bug("writeb")
|
||||
#define writew(v,addr) __readwrite_bug("writew")
|
||||
#define writel(v,addr) __readwrite_bug("writel")
|
||||
|
||||
#define eth_io_copy_and_sum(a,b,c,d) __readwrite_bug("eth_io_copy_and_sum")
|
||||
|
||||
#define check_signature(io,sig,len) (0)
|
||||
|
||||
#endif /* __mem_pci */
|
||||
|
||||
/* FIXME(dhendrix): added to make uart8250_mem code happy. Note: lL */
|
||||
static inline __attribute__((always_inline)) uint8_t read8(unsigned long addr)
|
||||
{
|
||||
return readb(addr);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) uint16_t read16(unsigned long addr)
|
||||
{
|
||||
return readw(addr);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) uint32_t read32(unsigned long addr)
|
||||
{
|
||||
return readl(addr);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void write8(unsigned long addr, uint8_t value)
|
||||
{
|
||||
writeb(value, addr);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void write16(unsigned long addr, uint16_t value)
|
||||
{
|
||||
writew(value, addr);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void write32(unsigned long addr, uint32_t value)
|
||||
{
|
||||
writel(value, addr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If this architecture has ISA IO, then define the isa_read/isa_write
|
||||
* macros.
|
||||
*/
|
||||
#ifdef __mem_isa
|
||||
|
||||
#define isa_readb(addr) __raw_readb(__mem_isa(addr))
|
||||
#define isa_readw(addr) __raw_readw(__mem_isa(addr))
|
||||
#define isa_readl(addr) __raw_readl(__mem_isa(addr))
|
||||
#define isa_writeb(val,addr) __raw_writeb(val,__mem_isa(addr))
|
||||
#define isa_writew(val,addr) __raw_writew(val,__mem_isa(addr))
|
||||
#define isa_writel(val,addr) __raw_writel(val,__mem_isa(addr))
|
||||
#define isa_memset_io(a,b,c) _memset_io(__mem_isa(a),(b),(c))
|
||||
#define isa_memcpy_fromio(a,b,c) _memcpy_fromio((a),__mem_isa(b),(c))
|
||||
#define isa_memcpy_toio(a,b,c) _memcpy_toio(__mem_isa((a)),(b),(c))
|
||||
|
||||
#define isa_eth_io_copy_and_sum(a,b,c,d) \
|
||||
eth_copy_and_sum((a),__mem_isa(b),(c),(d))
|
||||
|
||||
static inline int
|
||||
isa_check_signature(unsigned long io_addr, const unsigned char *signature,
|
||||
int length)
|
||||
{
|
||||
int retval = 0;
|
||||
do {
|
||||
if (isa_readb(io_addr) != *signature)
|
||||
goto out;
|
||||
io_addr++;
|
||||
signature++;
|
||||
length--;
|
||||
} while (length);
|
||||
retval = 1;
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
#else /* __mem_isa */
|
||||
|
||||
#define isa_readb(addr) (__readwrite_bug("isa_readb"),0)
|
||||
#define isa_readw(addr) (__readwrite_bug("isa_readw"),0)
|
||||
#define isa_readl(addr) (__readwrite_bug("isa_readl"),0)
|
||||
#define isa_writeb(val,addr) __readwrite_bug("isa_writeb")
|
||||
#define isa_writew(val,addr) __readwrite_bug("isa_writew")
|
||||
#define isa_writel(val,addr) __readwrite_bug("isa_writel")
|
||||
#define isa_memset_io(a,b,c) __readwrite_bug("isa_memset_io")
|
||||
#define isa_memcpy_fromio(a,b,c) __readwrite_bug("isa_memcpy_fromio")
|
||||
#define isa_memcpy_toio(a,b,c) __readwrite_bug("isa_memcpy_toio")
|
||||
|
||||
#define isa_eth_io_copy_and_sum(a,b,c,d) \
|
||||
__readwrite_bug("isa_eth_io_copy_and_sum")
|
||||
|
||||
#define isa_check_signature(io,sig,len) (0)
|
||||
|
||||
#endif /* __mem_isa */
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* __ASM_ARM_IO_H */
|
19
src/arch/armv7/include/arch/pci_ops.h
Normal file
19
src/arch/armv7/include/arch/pci_ops.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef ARCH_I386_PCI_OPS_H
|
||||
#define ARCH_I386_PCI_OPS_H
|
||||
|
||||
extern const struct pci_bus_operations pci_cf8_conf1;
|
||||
|
||||
#if CONFIG_MMCONF_SUPPORT
|
||||
extern const struct pci_bus_operations pci_ops_mmconf;
|
||||
#endif
|
||||
|
||||
static inline const struct pci_bus_operations *pci_config_default(void)
|
||||
{
|
||||
return &pci_cf8_conf1;
|
||||
}
|
||||
|
||||
static inline void pci_set_method(device_t dev)
|
||||
{
|
||||
dev->ops->ops_pci_bus = pci_config_default();
|
||||
}
|
||||
#endif /* ARCH_I386_PCI_OPS_H */
|
53
src/arch/armv7/include/arch/types.h
Normal file
53
src/arch/armv7/include/arch/types.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef __ASM_ARM_TYPES_H
|
||||
#define __ASM_ARM_TYPES_H
|
||||
|
||||
typedef unsigned short umode_t;
|
||||
|
||||
/*
|
||||
* __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
|
||||
* header files exported to user space
|
||||
*/
|
||||
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
|
||||
typedef __signed__ int __s32;
|
||||
typedef unsigned int __u32;
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__extension__ typedef __signed__ long long __s64;
|
||||
__extension__ typedef unsigned long long __u64;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These aren't exported outside the kernel to avoid name space clashes
|
||||
*/
|
||||
#ifdef __KERNEL__
|
||||
|
||||
typedef signed char s8;
|
||||
typedef unsigned char u8;
|
||||
|
||||
typedef signed short s16;
|
||||
typedef unsigned short u16;
|
||||
|
||||
typedef signed int s32;
|
||||
typedef unsigned int u32;
|
||||
|
||||
typedef signed long long s64;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
#define BITS_PER_LONG 32
|
||||
|
||||
/* Dma addresses are 32-bits wide. */
|
||||
|
||||
typedef u32 dma_addr_t;
|
||||
|
||||
typedef unsigned long phys_addr_t;
|
||||
typedef unsigned long phys_size_t;
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif
|
76
src/arch/armv7/include/armv7.h
Normal file
76
src/arch/armv7/include/armv7.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
* Aneesh V <aneesh@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
|
||||
*/
|
||||
#ifndef ARMV7_H
|
||||
#define ARMV7_H
|
||||
#include <types.h>
|
||||
|
||||
/* Cortex-A9 revisions */
|
||||
#define MIDR_CORTEX_A9_R0P1 0x410FC091
|
||||
#define MIDR_CORTEX_A9_R1P2 0x411FC092
|
||||
#define MIDR_CORTEX_A9_R1P3 0x411FC093
|
||||
#define MIDR_CORTEX_A9_R2P10 0x412FC09A
|
||||
|
||||
/* Cortex-A15 revisions */
|
||||
#define MIDR_CORTEX_A15_R0P0 0x410FC0F0
|
||||
|
||||
/* CCSIDR */
|
||||
#define CCSIDR_LINE_SIZE_OFFSET 0
|
||||
#define CCSIDR_LINE_SIZE_MASK 0x7
|
||||
#define CCSIDR_ASSOCIATIVITY_OFFSET 3
|
||||
#define CCSIDR_ASSOCIATIVITY_MASK (0x3FF << 3)
|
||||
#define CCSIDR_NUM_SETS_OFFSET 13
|
||||
#define CCSIDR_NUM_SETS_MASK (0x7FFF << 13)
|
||||
|
||||
/*
|
||||
* Values for InD field in CSSELR
|
||||
* Selects the type of cache
|
||||
*/
|
||||
#define ARMV7_CSSELR_IND_DATA_UNIFIED 0
|
||||
#define ARMV7_CSSELR_IND_INSTRUCTION 1
|
||||
|
||||
/* Values for Ctype fields in CLIDR */
|
||||
#define ARMV7_CLIDR_CTYPE_NO_CACHE 0
|
||||
#define ARMV7_CLIDR_CTYPE_INSTRUCTION_ONLY 1
|
||||
#define ARMV7_CLIDR_CTYPE_DATA_ONLY 2
|
||||
#define ARMV7_CLIDR_CTYPE_INSTRUCTION_DATA 3
|
||||
#define ARMV7_CLIDR_CTYPE_UNIFIED 4
|
||||
|
||||
/*
|
||||
* CP15 Barrier instructions
|
||||
* Please note that we have separate barrier instructions in ARMv7
|
||||
* However, we use the CP15 based instructtions because we use
|
||||
* -march=armv5 in U-Boot
|
||||
*/
|
||||
#define CP15ISB asm volatile ("mcr p15, 0, %0, c7, c5, 4" : : "r" (0))
|
||||
#define CP15DSB asm volatile ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0))
|
||||
#define CP15DMB asm volatile ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0))
|
||||
|
||||
void v7_outer_cache_enable(void);
|
||||
void v7_outer_cache_disable(void);
|
||||
void v7_outer_cache_flush_all(void);
|
||||
void v7_outer_cache_inval_all(void);
|
||||
void v7_outer_cache_flush_range(u32 start, u32 end);
|
||||
void v7_outer_cache_inval_range(u32 start, u32 end);
|
||||
|
||||
#endif
|
60
src/arch/armv7/include/assembler.h
Normal file
60
src/arch/armv7/include/assembler.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* arch/arm/include/asm/assembler.h
|
||||
*
|
||||
* Copyright (C) 1996-2000 Russell King
|
||||
*
|
||||
* 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 file contains arm architecture specific defines
|
||||
* for the different processors.
|
||||
*
|
||||
* Do not include any C declarations in this file - it is included by
|
||||
* assembler source.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Endian independent macros for shifting bytes within registers.
|
||||
*/
|
||||
#ifndef __ARMEB__
|
||||
#define pull lsr
|
||||
#define push lsl
|
||||
#define get_byte_0 lsl #0
|
||||
#define get_byte_1 lsr #8
|
||||
#define get_byte_2 lsr #16
|
||||
#define get_byte_3 lsr #24
|
||||
#define put_byte_0 lsl #0
|
||||
#define put_byte_1 lsl #8
|
||||
#define put_byte_2 lsl #16
|
||||
#define put_byte_3 lsl #24
|
||||
#else
|
||||
#define pull lsl
|
||||
#define push lsr
|
||||
#define get_byte_0 lsr #24
|
||||
#define get_byte_1 lsr #16
|
||||
#define get_byte_2 lsr #8
|
||||
#define get_byte_3 lsl #0
|
||||
#define put_byte_0 lsl #24
|
||||
#define put_byte_1 lsl #16
|
||||
#define put_byte_2 lsl #8
|
||||
#define put_byte_3 lsl #0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Data preload for architectures that support it
|
||||
*/
|
||||
#if defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) || \
|
||||
defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
|
||||
defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || \
|
||||
defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_7A__) || \
|
||||
defined(__ARM_ARCH_7R__)
|
||||
#define PLD(code...) code
|
||||
#else
|
||||
#define PLD(code...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Cache alligned
|
||||
*/
|
||||
#define CALGN(code...) code
|
69
src/arch/armv7/include/bootblock_common.h
Normal file
69
src/arch/armv7/include/bootblock_common.h
Normal file
@ -0,0 +1,69 @@
|
||||
#include <types.h>
|
||||
#include <cbfs.h>
|
||||
#include <string.h>
|
||||
#include <arch/byteorder.h>
|
||||
|
||||
|
||||
#define boot_cpu(x) 1
|
||||
|
||||
#ifdef CONFIG_BOOTBLOCK_CPU_INIT
|
||||
#include CONFIG_BOOTBLOCK_CPU_INIT
|
||||
#else
|
||||
static void bootblock_cpu_init(void) { }
|
||||
#endif
|
||||
#ifdef CONFIG_BOOTBLOCK_NORTHBRIDGE_INIT
|
||||
#include CONFIG_BOOTBLOCK_NORTHBRIDGE_INIT
|
||||
#else
|
||||
static void bootblock_northbridge_init(void) { }
|
||||
#endif
|
||||
#ifdef CONFIG_BOOTBLOCK_SOUTHBRIDGE_INIT
|
||||
#include CONFIG_BOOTBLOCK_SOUTHBRIDGE_INIT
|
||||
#else
|
||||
static void bootblock_southbridge_init(void) { }
|
||||
#endif
|
||||
|
||||
static int cbfs_check_magic(struct cbfs_file *file)
|
||||
{
|
||||
return !strcmp(file->magic, CBFS_FILE_MAGIC) ? 1 : 0;
|
||||
}
|
||||
|
||||
static unsigned long findstage(const char* target)
|
||||
{
|
||||
unsigned long offset;
|
||||
|
||||
void *ptr = (void *)*((unsigned long *) CBFS_HEADPTR_ADDR);
|
||||
struct cbfs_header *header = (struct cbfs_header *) ptr;
|
||||
// if (ntohl(header->magic) != CBFS_HEADER_MAGIC)
|
||||
// printk(BIOS_ERR, "ERROR: No valid CBFS header found!\n");
|
||||
|
||||
offset = 0 - ntohl(header->romsize) + ntohl(header->offset);
|
||||
int align = ntohl(header->align);
|
||||
while(1) {
|
||||
struct cbfs_file *file = (struct cbfs_file *) offset;
|
||||
if (!cbfs_check_magic(file))
|
||||
return 0;
|
||||
if (!strcmp(CBFS_NAME(file), target))
|
||||
return (unsigned long)CBFS_SUBHEADER(file);
|
||||
int flen = ntohl(file->len);
|
||||
int foffset = ntohl(file->offset);
|
||||
unsigned long oldoffset = offset;
|
||||
offset = ALIGN(offset + foffset + flen, align);
|
||||
if (offset <= oldoffset)
|
||||
return 0;
|
||||
if (offset < 0xFFFFFFFF - ntohl(header->romsize))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void call(unsigned long addr, unsigned long bist)
|
||||
{
|
||||
asm volatile ("mov r0, %1\nbx %0\n" : : "r" (addr), "r" (bist));
|
||||
}
|
||||
|
||||
static void hlt(void)
|
||||
{
|
||||
/* is there such a thing as hlt on ARM? */
|
||||
// asm volatile ("1:\n\thlt\n\tjmp 1b\n\t");
|
||||
asm volatile ("1:\nb 1b\n\t");
|
||||
}
|
56
src/arch/armv7/include/cache.h
Normal file
56
src/arch/armv7/include/cache.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* (C) Copyright 2009
|
||||
* Marvell Semiconductor <www.marvell.com>
|
||||
* Written-by: Prafulla Wadaskar <prafulla@marvell.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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _ASM_CACHE_H
|
||||
#define _ASM_CACHE_H
|
||||
|
||||
/*
|
||||
* Invalidate L2 Cache using co-proc instruction
|
||||
*/
|
||||
static inline void invalidate_l2_cache(void)
|
||||
{
|
||||
unsigned int val=0;
|
||||
|
||||
asm volatile("mcr p15, 1, %0, c15, c11, 0 @ invl l2 cache"
|
||||
: : "r" (val) : "cc");
|
||||
isb();
|
||||
}
|
||||
|
||||
void l2_cache_enable(void);
|
||||
void l2_cache_disable(void);
|
||||
|
||||
/*
|
||||
* The current upper bound for ARM L1 data cache line sizes is 64 bytes. We
|
||||
* use that value for aligning DMA buffers unless the board config has specified
|
||||
* an alternate cache line size.
|
||||
*/
|
||||
#ifdef CONFIG_SYS_CACHELINE_SIZE
|
||||
#define ARCH_DMA_MINALIGN CONFIG_SYS_CACHELINE_SIZE
|
||||
#else
|
||||
#define ARCH_DMA_MINALIGN 64
|
||||
#endif
|
||||
|
||||
inline void dram_bank_mmu_setup(unsigned long start, unsigned long size);
|
||||
|
||||
#endif /* _ASM_CACHE_H */
|
44
src/arch/armv7/include/clocks.h
Normal file
44
src/arch/armv7/include/clocks.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* Standard clock speeds */
|
||||
|
||||
/*
|
||||
* We define some commonly-used clock speeds to avoid error since long
|
||||
* numbers are hard to read.
|
||||
*
|
||||
* The format of the label is
|
||||
* CLK_x_yU where:
|
||||
* x is the integer speed
|
||||
* y is the fractional part which can be omitted if 0
|
||||
* U is the units (blank for Hz, K or M for KHz and MHz)
|
||||
*
|
||||
* Please order the items by increasing Hz
|
||||
*/
|
||||
enum {
|
||||
CLK_32768 = 32768,
|
||||
CLK_20M = 20000000,
|
||||
CLK_24M = 24000000,
|
||||
CLK_144M = 144000000,
|
||||
CLK_216M = 216000000,
|
||||
CLK_300M = 300000000,
|
||||
};
|
||||
|
494
src/arch/armv7/include/common.h
Normal file
494
src/arch/armv7/include/common.h
Normal file
@ -0,0 +1,494 @@
|
||||
/*
|
||||
* (C) Copyright 2000-2009
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __COMMON_H_
|
||||
#define __COMMON_H_ 1
|
||||
|
||||
#undef _LINUX_CONFIG_H
|
||||
#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
|
||||
|
||||
#ifndef __ASSEMBLER__ /* put C only stuff in this section */
|
||||
|
||||
typedef unsigned char uchar;
|
||||
typedef volatile unsigned long vu_long;
|
||||
typedef volatile unsigned short vu_short;
|
||||
typedef volatile unsigned char vu_char;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned int uint;
|
||||
|
||||
//#include <config.h>
|
||||
//#include <asm-offsets.h>
|
||||
//#include <linux/bitops.h>
|
||||
//#include <linux/string.h>
|
||||
//#include <asm/ptrace.h>
|
||||
#include <types.h>
|
||||
//#include <stdarg.h>
|
||||
|
||||
//#include <part.h>
|
||||
//#include <flash.h>
|
||||
//#include <image.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(fmt,args...) printf (fmt ,##args)
|
||||
#define debugX(level,fmt,args...) if (DEBUG>=level) printf(fmt,##args);
|
||||
#else
|
||||
#define debug(fmt,args...)
|
||||
#define debugX(level,fmt,args...)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#ifdef DEBUG
|
||||
# define _DEBUG 1
|
||||
#else
|
||||
# define _DEBUG 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* An assertion is run-time check done in debug mode only. If DEBUG is not
|
||||
* defined then it is skipped. If DEBUG is defined and the assertion fails,
|
||||
* then it calls panic*( which may or may not reset/halt U-Boot (see
|
||||
* CONFIG_PANIC_HANG), It is hoped that all failing assertions are found
|
||||
* before release, and after release it is hoped that they don't matter. But
|
||||
* in any case these failing assertions cannot be fixed with a reset (which
|
||||
* may just do the same assertion again).
|
||||
*/
|
||||
void __assert_fail(const char *assertion, const char *file, unsigned line,
|
||||
const char *function);
|
||||
#define assert(x) \
|
||||
({ if (!(x) && _DEBUG) \
|
||||
__assert_fail(#x, __FILE__, __LINE__, __func__); })
|
||||
|
||||
#define error(fmt, args...) do { \
|
||||
printf("ERROR: " fmt "\nat %s:%d/%s()\n", \
|
||||
##args, __FILE__, __LINE__, __func__); \
|
||||
} while (0)
|
||||
|
||||
#ifndef BUG
|
||||
#define BUG() do { \
|
||||
printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \
|
||||
panic("BUG!"); \
|
||||
} while (0)
|
||||
#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
|
||||
#endif /* BUG */
|
||||
|
||||
/* Force a compilation error if condition is true */
|
||||
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
|
||||
|
||||
typedef void (interrupt_handler_t)(void *);
|
||||
|
||||
//#include <asm/u-boot.h> /* boot information for Linux kernel */
|
||||
#include <global_data.h> /* global data used for startup functions */
|
||||
|
||||
/*
|
||||
* Return the time since boot in microseconds, This is needed for bootstage
|
||||
* and should be defined in CPU- or board-specific code. If undefined then
|
||||
* millisecond resolution will be used (the standard get_timer()).
|
||||
*/
|
||||
ulong timer_get_boot_us(void);
|
||||
|
||||
/*
|
||||
* Return the current value of a monotonically increasing microsecond timer.
|
||||
* Granularity may be larger than 1us if hardware does not support this.
|
||||
*/
|
||||
ulong timer_get_us(void);
|
||||
|
||||
/*
|
||||
* General Purpose Utilities
|
||||
*/
|
||||
#if 0
|
||||
#define min(X, Y) \
|
||||
({ typeof (X) __x = (X); \
|
||||
typeof (Y) __y = (Y); \
|
||||
(__x < __y) ? __x : __y; })
|
||||
|
||||
#define max(X, Y) \
|
||||
({ typeof (X) __x = (X); \
|
||||
typeof (Y) __y = (Y); \
|
||||
(__x > __y) ? __x : __y; })
|
||||
#define MIN(x, y) min(x, y)
|
||||
#define MAX(x, y) max(x, y)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* container_of - cast a member of a structure out to the containing structure
|
||||
* @ptr: the pointer to the member.
|
||||
* @type: the type of the container struct this is embedded in.
|
||||
* @member: the name of the member within the struct.
|
||||
*
|
||||
*/
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
||||
/*
|
||||
* Function Prototypes
|
||||
*/
|
||||
|
||||
void hang (void) __attribute__ ((noreturn));
|
||||
|
||||
int init_timer(void); /* FIXME(dhendrix): used to be timer_init() */
|
||||
int cpu_init(void);
|
||||
|
||||
/* */
|
||||
unsigned long long initdram (int);
|
||||
int display_options (void);
|
||||
void print_size(unsigned long long, const char *);
|
||||
int print_buffer (ulong addr, void* data, uint width, uint count, uint linelen);
|
||||
|
||||
/* common/main.c */
|
||||
void main_loop (void);
|
||||
int run_command (const char *cmd, int flag);
|
||||
int readline (const char *const prompt);
|
||||
int readline_into_buffer (const char *const prompt, char * buffer);
|
||||
int parse_line (char *, char *[]);
|
||||
void init_cmd_timeout(void);
|
||||
void reset_cmd_timeout(void);
|
||||
|
||||
/* arch/$(ARCH)/lib/board.c */
|
||||
void board_init_f (ulong);
|
||||
//void board_init_f (ulong) __attribute__ ((noreturn));
|
||||
void board_init_r (gd_t *, ulong) __attribute__ ((noreturn));
|
||||
int checkboard (void);
|
||||
int checkflash (void);
|
||||
int checkdram (void);
|
||||
int last_stage_init(void);
|
||||
extern ulong monitor_flash_len;
|
||||
int mac_read_from_eeprom(void);
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
# include <asm/mach-types.h>
|
||||
# include <asm/setup.h>
|
||||
# include <asm/u-boot-arm.h> /* ARM version to be fixed! */
|
||||
#endif /* CONFIG_ARM */
|
||||
|
||||
int misc_init_f (void);
|
||||
int misc_init_r (void);
|
||||
|
||||
/* common/exports.c */
|
||||
void jumptable_init(void);
|
||||
|
||||
/* common/kallsysm.c */
|
||||
const char *symbol_lookup(unsigned long addr, unsigned long *caddr);
|
||||
|
||||
/* api/api.c */
|
||||
void api_init (void);
|
||||
|
||||
/* common/memsize.c */
|
||||
long get_ram_size (long *, long);
|
||||
|
||||
/* $(BOARD)/$(BOARD).c */
|
||||
void reset_phy (void);
|
||||
void fdc_hw_init (void);
|
||||
|
||||
/* $(BOARD)/eeprom.c */
|
||||
void eeprom_init (void);
|
||||
#ifndef CONFIG_SPI
|
||||
int eeprom_probe (unsigned dev_addr, unsigned offset);
|
||||
#endif
|
||||
int eeprom_read (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt);
|
||||
int eeprom_write (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt);
|
||||
|
||||
/*
|
||||
* Set this up regardless of board
|
||||
* type, to prevent errors.
|
||||
*/
|
||||
#if defined(CONFIG_SPI) || !defined(CONFIG_SYS_I2C_EEPROM_ADDR)
|
||||
# define CONFIG_SYS_DEF_EEPROM_ADDR 0
|
||||
#else
|
||||
#if !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
|
||||
# define CONFIG_SYS_DEF_EEPROM_ADDR CONFIG_SYS_I2C_EEPROM_ADDR
|
||||
#endif
|
||||
#endif /* CONFIG_SPI || !defined(CONFIG_SYS_I2C_EEPROM_ADDR) */
|
||||
|
||||
#if defined(CONFIG_SPI)
|
||||
extern void spi_init_f (void);
|
||||
extern void spi_init_r (void);
|
||||
extern ssize_t spi_read (uchar *, int, uchar *, int);
|
||||
extern ssize_t spi_write (uchar *, int, uchar *, int);
|
||||
#endif
|
||||
|
||||
/* $(BOARD)/$(BOARD).c */
|
||||
int board_early_init_f (void);
|
||||
int board_late_init (void);
|
||||
int board_postclk_init (void); /* after clocks/timebase, before env/serial */
|
||||
int board_early_init_r (void);
|
||||
void board_poweroff (void);
|
||||
|
||||
#if defined(CONFIG_SYS_DRAM_TEST)
|
||||
int testdram(void);
|
||||
#endif /* CONFIG_SYS_DRAM_TEST */
|
||||
|
||||
/* $(CPU)/start.S */
|
||||
#if defined(CONFIG_5xx) || \
|
||||
defined(CONFIG_8xx)
|
||||
uint get_immr (uint);
|
||||
#endif
|
||||
uint get_pir (void);
|
||||
#if defined(CONFIG_MPC5xxx)
|
||||
uint get_svr (void);
|
||||
#endif
|
||||
uint get_pvr (void);
|
||||
uint get_svr (void);
|
||||
uint rd_ic_cst (void);
|
||||
void wr_ic_cst (uint);
|
||||
void wr_ic_adr (uint);
|
||||
uint rd_dc_cst (void);
|
||||
void wr_dc_cst (uint);
|
||||
void wr_dc_adr (uint);
|
||||
int icache_status (void);
|
||||
void icache_enable (void);
|
||||
void icache_disable(void);
|
||||
int dcache_status (void);
|
||||
void dcache_enable (void);
|
||||
void dcache_disable(void);
|
||||
void mmu_disable(void);
|
||||
void relocate_code (ulong, gd_t *, ulong) __attribute__ ((noreturn));
|
||||
ulong get_endaddr (void);
|
||||
void trap_init (ulong);
|
||||
#if defined (CONFIG_4xx) || \
|
||||
defined (CONFIG_MPC5xxx) || \
|
||||
defined (CONFIG_74xx_7xx) || \
|
||||
defined (CONFIG_74x) || \
|
||||
defined (CONFIG_75x) || \
|
||||
defined (CONFIG_74xx) || \
|
||||
defined (CONFIG_MPC8220) || \
|
||||
defined (CONFIG_MPC85xx) || \
|
||||
defined (CONFIG_MPC86xx) || \
|
||||
defined (CONFIG_MPC83xx)
|
||||
unsigned char in8(unsigned int);
|
||||
void out8(unsigned int, unsigned char);
|
||||
unsigned short in16(unsigned int);
|
||||
unsigned short in16r(unsigned int);
|
||||
void out16(unsigned int, unsigned short value);
|
||||
void out16r(unsigned int, unsigned short value);
|
||||
unsigned long in32(unsigned int);
|
||||
unsigned long in32r(unsigned int);
|
||||
void out32(unsigned int, unsigned long value);
|
||||
void out32r(unsigned int, unsigned long value);
|
||||
void ppcDcbf(unsigned long value);
|
||||
void ppcDcbi(unsigned long value);
|
||||
void ppcSync(void);
|
||||
void ppcDcbz(unsigned long value);
|
||||
#endif
|
||||
|
||||
/* $(CPU)/cpu.c */
|
||||
static inline int cpumask_next(int cpu, unsigned int mask)
|
||||
{
|
||||
for (cpu++; !((1 << cpu) & mask); cpu++)
|
||||
;
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
#define for_each_cpu(iter, cpu, num_cpus, mask) \
|
||||
for (iter = 0, cpu = cpumask_next(-1, mask); \
|
||||
iter < num_cpus; \
|
||||
iter++, cpu = cpumask_next(cpu, mask)) \
|
||||
|
||||
int cpu_numcores (void);
|
||||
u32 cpu_mask (void);
|
||||
int is_core_valid (unsigned int);
|
||||
int probecpu (void);
|
||||
int checkcpu (void);
|
||||
int checkicache (void);
|
||||
int checkdcache (void);
|
||||
void upmconfig (unsigned int, unsigned int *, unsigned int);
|
||||
ulong get_tbclk (void);
|
||||
void reset_cpu (ulong addr);
|
||||
#if defined (CONFIG_OF_LIBFDT) && defined (CONFIG_OF_BOARD_SETUP)
|
||||
void ft_cpu_setup(void *blob, bd_t *bd);
|
||||
#endif
|
||||
|
||||
|
||||
/* $(CPU)/serial.c */
|
||||
int serial_init (void);
|
||||
void serial_setbrg (void);
|
||||
void serial_putc (const char);
|
||||
void serial_putc_raw(const char);
|
||||
void serial_puts (const char *);
|
||||
int serial_getc (void);
|
||||
int serial_tstc (void);
|
||||
|
||||
void _serial_setbrg (const int);
|
||||
void _serial_putc (const char, const int);
|
||||
void _serial_putc_raw(const char, const int);
|
||||
void _serial_puts (const char *, const int);
|
||||
int _serial_getc (const int);
|
||||
int _serial_tstc (const int);
|
||||
|
||||
/* $(CPU)/speed.c */
|
||||
int get_clocks (void);
|
||||
int get_clocks_866 (void);
|
||||
int sdram_adjust_866 (void);
|
||||
int adjust_sdram_tbs_8xx (void);
|
||||
#if defined(CONFIG_8260)
|
||||
int prt_8260_clks (void);
|
||||
#elif defined(CONFIG_MPC5xxx)
|
||||
int prt_mpc5xxx_clks (void);
|
||||
#endif
|
||||
#if defined(CONFIG_MPC512X)
|
||||
int prt_mpc512xxx_clks (void);
|
||||
#endif
|
||||
#if defined(CONFIG_MPC8220)
|
||||
int prt_mpc8220_clks (void);
|
||||
#endif
|
||||
#ifdef CONFIG_4xx
|
||||
ulong get_OPB_freq (void);
|
||||
ulong get_PCI_freq (void);
|
||||
#endif
|
||||
#if defined(CONFIG_S3C24X0) || \
|
||||
defined(CONFIG_LH7A40X) || \
|
||||
defined(CONFIG_S3C6400) || \
|
||||
defined(CONFIG_EP93XX)
|
||||
ulong get_FCLK (void);
|
||||
ulong get_HCLK (void);
|
||||
ulong get_PCLK (void);
|
||||
ulong get_UCLK (void);
|
||||
#endif
|
||||
#if defined(CONFIG_LH7A40X)
|
||||
ulong get_PLLCLK (void);
|
||||
#endif
|
||||
#if defined CONFIG_INCA_IP
|
||||
uint incaip_get_cpuclk (void);
|
||||
#endif
|
||||
#if defined(CONFIG_IMX)
|
||||
ulong get_systemPLLCLK(void);
|
||||
ulong get_FCLK(void);
|
||||
ulong get_HCLK(void);
|
||||
ulong get_BCLK(void);
|
||||
ulong get_PERCLK1(void);
|
||||
ulong get_PERCLK2(void);
|
||||
ulong get_PERCLK3(void);
|
||||
#endif
|
||||
ulong get_bus_freq (ulong);
|
||||
int get_serial_clock(void);
|
||||
|
||||
struct pt_regs;
|
||||
/* $(CPU)/interrupts.c */
|
||||
int interrupt_init (void);
|
||||
void timer_interrupt (struct pt_regs *);
|
||||
void external_interrupt (struct pt_regs *);
|
||||
void irq_install_handler(int, interrupt_handler_t *, void *);
|
||||
void irq_free_handler (int);
|
||||
void reset_timer (void);
|
||||
ulong get_timer (ulong base);
|
||||
void enable_interrupts (void);
|
||||
int disable_interrupts (void);
|
||||
|
||||
/* $(CPU)/.../commproc.c */
|
||||
int dpram_init (void);
|
||||
uint dpram_base(void);
|
||||
uint dpram_base_align(uint align);
|
||||
uint dpram_alloc(uint size);
|
||||
uint dpram_alloc_align(uint size,uint align);
|
||||
void bootcount_store (ulong);
|
||||
ulong bootcount_load (void);
|
||||
#define BOOTCOUNT_MAGIC 0xB001C041
|
||||
|
||||
/* $(CPU)/.../<eth> */
|
||||
void mii_init (void);
|
||||
|
||||
/* $(CPU)/.../lcd.c */
|
||||
ulong lcd_setmem (ulong);
|
||||
|
||||
/* $(CPU)/.../video.c */
|
||||
ulong video_setmem (ulong);
|
||||
|
||||
/* arch/$(ARCH)/lib/cache.c */
|
||||
ulong dcache_get_line_size(void);
|
||||
void enable_caches(void);
|
||||
void flush_cache (unsigned long, unsigned long);
|
||||
void flush_dcache_all(void);
|
||||
void flush_dcache_range(unsigned long start, unsigned long stop);
|
||||
void invalidate_dcache_range(unsigned long start, unsigned long stop);
|
||||
void invalidate_dcache_all(void);
|
||||
void invalidate_icache_all(void);
|
||||
|
||||
/* arch/$(ARCH)/lib/ticks.S */
|
||||
unsigned long long get_ticks(void);
|
||||
void wait_ticks (unsigned long);
|
||||
|
||||
/* arch/$(ARCH)/lib/time.c */
|
||||
void __udelay (unsigned long);
|
||||
ulong usec2ticks (unsigned long usec);
|
||||
ulong ticks2usec (unsigned long ticks);
|
||||
int init_timebase (void);
|
||||
|
||||
/* lib/qsort.c */
|
||||
void qsort(void *base, size_t nmemb, size_t size,
|
||||
int(*compar)(const void *, const void *));
|
||||
int strcmp_compar(const void *, const void *);
|
||||
|
||||
/* lib/time.c */
|
||||
void udelay (unsigned long);
|
||||
|
||||
#if 0
|
||||
/* lib/vsprintf.c */
|
||||
ulong simple_strtoul(const char *cp,char **endp,unsigned int base);
|
||||
int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
|
||||
unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base);
|
||||
long simple_strtol(const char *cp,char **endp,unsigned int base);
|
||||
void panic(const char *fmt, ...)
|
||||
__attribute__ ((format (__printf__, 1, 2), noreturn));
|
||||
int sprintf(char * buf, const char *fmt, ...)
|
||||
__attribute__ ((format (__printf__, 2, 3)));
|
||||
int vsprintf(char *buf, const char *fmt, va_list args);
|
||||
#endif
|
||||
|
||||
/* lib/strmhz.c */
|
||||
char * strmhz(char *buf, unsigned long hz);
|
||||
|
||||
/* Multicore arch functions */
|
||||
#ifdef CONFIG_MP
|
||||
int cpu_status(int nr);
|
||||
int cpu_reset(int nr);
|
||||
int cpu_disable(int nr);
|
||||
int cpu_release(int nr, int argc, char * const argv[]);
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
/* Put only stuff here that the assembler can digest */
|
||||
|
||||
#ifdef CONFIG_POST
|
||||
#define CONFIG_HAS_POST
|
||||
#ifndef CONFIG_POST_ALT_LIST
|
||||
#define CONFIG_POST_STD_LIST
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INIT_CRITICAL
|
||||
#error CONFIG_INIT_CRITICAL is deprecated!
|
||||
#error Read section CONFIG_SKIP_LOWLEVEL_INIT in README.
|
||||
#endif
|
||||
|
||||
//#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#define ROUND(a,b) (((a) + (b) - 1) & ~((b) - 1))
|
||||
#define DIV_ROUND(n,d) (((n) + ((d)/2)) / (d))
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
|
||||
|
||||
//#define ALIGN(x,a) __ALIGN_MASK((x),(typeof(x))(a)-1)
|
||||
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
|
||||
|
||||
#endif /* __COMMON_H_ */
|
233
src/arch/armv7/include/div64.h
Normal file
233
src/arch/armv7/include/div64.h
Normal file
@ -0,0 +1,233 @@
|
||||
/* taken from linux 2.6.31.14 */
|
||||
|
||||
#ifndef __ASM_ARM_DIV64
|
||||
#define __ASM_ARM_DIV64
|
||||
|
||||
//#include <asm/system.h>
|
||||
//#include <linux/types.h>
|
||||
// FIXME
|
||||
|
||||
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
|
||||
#define __LINUX_ARM_ARCH__ 7
|
||||
|
||||
/*
|
||||
* The semantics of do_div() are:
|
||||
*
|
||||
* uint32_t do_div(uint64_t *n, uint32_t base)
|
||||
* {
|
||||
* uint32_t remainder = *n % base;
|
||||
* *n = *n / base;
|
||||
* return remainder;
|
||||
* }
|
||||
*
|
||||
* In other words, a 64-bit dividend with a 32-bit divisor producing
|
||||
* a 64-bit result and a 32-bit remainder. To accomplish this optimally
|
||||
* we call a special __do_div64 helper with completely non standard
|
||||
* calling convention for arguments and results (beware).
|
||||
*/
|
||||
|
||||
#ifdef __ARMEB__
|
||||
#define __xh "r0"
|
||||
#define __xl "r1"
|
||||
#else
|
||||
#define __xl "r0"
|
||||
#define __xh "r1"
|
||||
#endif
|
||||
|
||||
#define __do_div_asm(n, base) \
|
||||
({ \
|
||||
register unsigned int __base asm("r4") = base; \
|
||||
register unsigned long long __n asm("r0") = n; \
|
||||
register unsigned long long __res asm("r2"); \
|
||||
register unsigned int __rem asm(__xh); \
|
||||
asm( __asmeq("%0", __xh) \
|
||||
__asmeq("%1", "r2") \
|
||||
__asmeq("%2", "r0") \
|
||||
__asmeq("%3", "r4") \
|
||||
"bl __do_div64" \
|
||||
: "=r" (__rem), "=r" (__res) \
|
||||
: "r" (__n), "r" (__base) \
|
||||
: "ip", "lr", "cc"); \
|
||||
n = __res; \
|
||||
__rem; \
|
||||
})
|
||||
|
||||
#if __GNUC__ < 4
|
||||
|
||||
/*
|
||||
* gcc versions earlier than 4.0 are simply too problematic for the
|
||||
* optimized implementation below. First there is gcc PR 15089 that
|
||||
* tend to trig on more complex constructs, spurious .global __udivsi3
|
||||
* are inserted even if none of those symbols are referenced in the
|
||||
* generated code, and those gcc versions are not able to do constant
|
||||
* propagation on long long values anyway.
|
||||
*/
|
||||
#define do_div(n, base) __do_div_asm(n, base)
|
||||
|
||||
#elif __GNUC__ >= 4
|
||||
|
||||
//#include <asm/bug.h>
|
||||
|
||||
/*
|
||||
* If the divisor happens to be constant, we determine the appropriate
|
||||
* inverse at compile time to turn the division into a few inline
|
||||
* multiplications instead which is much faster. And yet only if compiling
|
||||
* for ARMv4 or higher (we need umull/umlal) and if the gcc version is
|
||||
* sufficiently recent to perform proper long long constant propagation.
|
||||
* (It is unfortunate that gcc doesn't perform all this internally.)
|
||||
*/
|
||||
#define do_div(n, base) \
|
||||
({ \
|
||||
unsigned int __r, __b = (base); \
|
||||
if (!__builtin_constant_p(__b) || __b == 0 || \
|
||||
(__LINUX_ARM_ARCH__ < 4 && (__b & (__b - 1)) != 0)) { \
|
||||
/* non-constant divisor (or zero): slow path */ \
|
||||
__r = __do_div_asm(n, __b); \
|
||||
} else if ((__b & (__b - 1)) == 0) { \
|
||||
/* Trivial: __b is constant and a power of 2 */ \
|
||||
/* gcc does the right thing with this code. */ \
|
||||
__r = n; \
|
||||
__r &= (__b - 1); \
|
||||
n /= __b; \
|
||||
} else { \
|
||||
/* Multiply by inverse of __b: n/b = n*(p/b)/p */ \
|
||||
/* We rely on the fact that most of this code gets */ \
|
||||
/* optimized away at compile time due to constant */ \
|
||||
/* propagation and only a couple inline assembly */ \
|
||||
/* instructions should remain. Better avoid any */ \
|
||||
/* code construct that might prevent that. */ \
|
||||
unsigned long long __res, __x, __t, __m, __n = n; \
|
||||
unsigned int __c, __p, __z = 0; \
|
||||
/* preserve low part of n for reminder computation */ \
|
||||
__r = __n; \
|
||||
/* determine number of bits to represent __b */ \
|
||||
__p = 1 << __div64_fls(__b); \
|
||||
/* compute __m = ((__p << 64) + __b - 1) / __b */ \
|
||||
__m = (~0ULL / __b) * __p; \
|
||||
__m += (((~0ULL % __b + 1) * __p) + __b - 1) / __b; \
|
||||
/* compute __res = __m*(~0ULL/__b*__b-1)/(__p << 64) */ \
|
||||
__x = ~0ULL / __b * __b - 1; \
|
||||
__res = (__m & 0xffffffff) * (__x & 0xffffffff); \
|
||||
__res >>= 32; \
|
||||
__res += (__m & 0xffffffff) * (__x >> 32); \
|
||||
__t = __res; \
|
||||
__res += (__x & 0xffffffff) * (__m >> 32); \
|
||||
__t = (__res < __t) ? (1ULL << 32) : 0; \
|
||||
__res = (__res >> 32) + __t; \
|
||||
__res += (__m >> 32) * (__x >> 32); \
|
||||
__res /= __p; \
|
||||
/* Now sanitize and optimize what we've got. */ \
|
||||
if (~0ULL % (__b / (__b & -__b)) == 0) { \
|
||||
/* those cases can be simplified with: */ \
|
||||
__n /= (__b & -__b); \
|
||||
__m = ~0ULL / (__b / (__b & -__b)); \
|
||||
__p = 1; \
|
||||
__c = 1; \
|
||||
} else if (__res != __x / __b) { \
|
||||
/* We can't get away without a correction */ \
|
||||
/* to compensate for bit truncation errors. */ \
|
||||
/* To avoid it we'd need an additional bit */ \
|
||||
/* to represent __m which would overflow it. */ \
|
||||
/* Instead we do m=p/b and n/b=(n*m+m)/p. */ \
|
||||
__c = 1; \
|
||||
/* Compute __m = (__p << 64) / __b */ \
|
||||
__m = (~0ULL / __b) * __p; \
|
||||
__m += ((~0ULL % __b + 1) * __p) / __b; \
|
||||
} else { \
|
||||
/* Reduce __m/__p, and try to clear bit 31 */ \
|
||||
/* of __m when possible otherwise that'll */ \
|
||||
/* need extra overflow handling later. */ \
|
||||
unsigned int __bits = -(__m & -__m); \
|
||||
__bits |= __m >> 32; \
|
||||
__bits = (~__bits) << 1; \
|
||||
/* If __bits == 0 then setting bit 31 is */ \
|
||||
/* unavoidable. Simply apply the maximum */ \
|
||||
/* possible reduction in that case. */ \
|
||||
/* Otherwise the MSB of __bits indicates the */ \
|
||||
/* best reduction we should apply. */ \
|
||||
if (!__bits) { \
|
||||
__p /= (__m & -__m); \
|
||||
__m /= (__m & -__m); \
|
||||
} else { \
|
||||
__p >>= __div64_fls(__bits); \
|
||||
__m >>= __div64_fls(__bits); \
|
||||
} \
|
||||
/* No correction needed. */ \
|
||||
__c = 0; \
|
||||
} \
|
||||
/* Now we have a combination of 2 conditions: */ \
|
||||
/* 1) whether or not we need a correction (__c), and */ \
|
||||
/* 2) whether or not there might be an overflow in */ \
|
||||
/* the cross product (__m & ((1<<63) | (1<<31))) */ \
|
||||
/* Select the best insn combination to perform the */ \
|
||||
/* actual __m * __n / (__p << 64) operation. */ \
|
||||
if (!__c) { \
|
||||
asm ( "umull %Q0, %R0, %1, %Q2\n\t" \
|
||||
"mov %Q0, #0" \
|
||||
: "=&r" (__res) \
|
||||
: "r" (__m), "r" (__n) \
|
||||
: "cc" ); \
|
||||
} else if (!(__m & ((1ULL << 63) | (1ULL << 31)))) { \
|
||||
__res = __m; \
|
||||
asm ( "umlal %Q0, %R0, %Q1, %Q2\n\t" \
|
||||
"mov %Q0, #0" \
|
||||
: "+&r" (__res) \
|
||||
: "r" (__m), "r" (__n) \
|
||||
: "cc" ); \
|
||||
} else { \
|
||||
asm ( "umull %Q0, %R0, %Q1, %Q2\n\t" \
|
||||
"cmn %Q0, %Q1\n\t" \
|
||||
"adcs %R0, %R0, %R1\n\t" \
|
||||
"adc %Q0, %3, #0" \
|
||||
: "=&r" (__res) \
|
||||
: "r" (__m), "r" (__n), "r" (__z) \
|
||||
: "cc" ); \
|
||||
} \
|
||||
if (!(__m & ((1ULL << 63) | (1ULL << 31)))) { \
|
||||
asm ( "umlal %R0, %Q0, %R1, %Q2\n\t" \
|
||||
"umlal %R0, %Q0, %Q1, %R2\n\t" \
|
||||
"mov %R0, #0\n\t" \
|
||||
"umlal %Q0, %R0, %R1, %R2" \
|
||||
: "+&r" (__res) \
|
||||
: "r" (__m), "r" (__n) \
|
||||
: "cc" ); \
|
||||
} else { \
|
||||
asm ( "umlal %R0, %Q0, %R2, %Q3\n\t" \
|
||||
"umlal %R0, %1, %Q2, %R3\n\t" \
|
||||
"mov %R0, #0\n\t" \
|
||||
"adds %Q0, %1, %Q0\n\t" \
|
||||
"adc %R0, %R0, #0\n\t" \
|
||||
"umlal %Q0, %R0, %R2, %R3" \
|
||||
: "+&r" (__res), "+&r" (__z) \
|
||||
: "r" (__m), "r" (__n) \
|
||||
: "cc" ); \
|
||||
} \
|
||||
__res /= __p; \
|
||||
/* The reminder can be computed with 32-bit regs */ \
|
||||
/* only, and gcc is good at that. */ \
|
||||
{ \
|
||||
unsigned int __res0 = __res; \
|
||||
unsigned int __b0 = __b; \
|
||||
__r -= __res0 * __b0; \
|
||||
} \
|
||||
/* BUG_ON(__r >= __b || __res * __b + __r != n); */ \
|
||||
n = __res; \
|
||||
} \
|
||||
__r; \
|
||||
})
|
||||
|
||||
/* our own fls implementation to make sure constant propagation is fine */
|
||||
#define __div64_fls(bits) \
|
||||
({ \
|
||||
unsigned int __left = (bits), __nr = 0; \
|
||||
if (__left & 0xffff0000) __nr += 16, __left >>= 16; \
|
||||
if (__left & 0x0000ff00) __nr += 8, __left >>= 8; \
|
||||
if (__left & 0x000000f0) __nr += 4, __left >>= 4; \
|
||||
if (__left & 0x0000000c) __nr += 2, __left >>= 2; \
|
||||
if (__left & 0x00000002) __nr += 1; \
|
||||
__nr; \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
108
src/arch/armv7/include/global_data.h
Normal file
108
src/arch/armv7/include/global_data.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* (C) Copyright 2002-2010
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __ASM_GBL_DATA_H
|
||||
#define __ASM_GBL_DATA_H
|
||||
|
||||
/*
|
||||
* The following data structure is placed in some memory which is
|
||||
* available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
|
||||
* some locked parts of the data cache) to allow for a minimum set of
|
||||
* global variables during system initialization (until we have set
|
||||
* up the memory controller so that we can use RAM).
|
||||
*
|
||||
* Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
|
||||
*/
|
||||
|
||||
typedef struct global_data {
|
||||
// bd_t *bd;
|
||||
unsigned long flags;
|
||||
unsigned long baudrate;
|
||||
unsigned long have_console; /* serial_init() was called */
|
||||
#ifdef CONFIG_PRE_CONSOLE_BUFFER
|
||||
unsigned long precon_buf_idx; /* Pre-Console buffer index */
|
||||
#endif
|
||||
unsigned long env_addr; /* Address of Environment struct */
|
||||
unsigned long env_valid; /* Checksum of Environment valid? */
|
||||
unsigned long fb_base; /* base address of frame buffer */
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
unsigned long sdhc_clk;
|
||||
#endif
|
||||
#ifdef CONFIG_AT91FAMILY
|
||||
/* "static data" needed by at91's clock.c */
|
||||
unsigned long cpu_clk_rate_hz;
|
||||
unsigned long main_clk_rate_hz;
|
||||
unsigned long mck_rate_hz;
|
||||
unsigned long plla_rate_hz;
|
||||
unsigned long pllb_rate_hz;
|
||||
unsigned long at91_pllb_usb_init;
|
||||
#endif
|
||||
#ifdef CONFIG_ARM
|
||||
/* "static data" needed by most of timer.c on ARM platforms */
|
||||
unsigned long timer_rate_hz;
|
||||
unsigned long tbl;
|
||||
unsigned long tbu;
|
||||
unsigned long long timer_reset_value;
|
||||
unsigned long lastinc;
|
||||
#endif
|
||||
#ifdef CONFIG_IXP425
|
||||
unsigned long timestamp;
|
||||
#endif
|
||||
unsigned long relocaddr; /* Start address of U-Boot in RAM */
|
||||
unsigned long long ram_size; /* RAM size */
|
||||
unsigned long mon_len; /* monitor len */
|
||||
unsigned long irq_sp; /* irq stack pointer */
|
||||
unsigned long start_addr_sp; /* start_addr_stackpointer */
|
||||
unsigned long reloc_off;
|
||||
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
|
||||
unsigned long tlb_addr;
|
||||
unsigned long tlb_size;
|
||||
#endif
|
||||
const void *fdt_blob; /* Our device tree, NULL if none */
|
||||
#ifdef CONFIG_SYS_SKIP_ARM_RELOCATION
|
||||
ulong malloc_end; /* End of malloc region (addr + 1) */
|
||||
#endif
|
||||
void **jt; /* jump table */
|
||||
char env_buf[32]; /* buffer for getenv() before reloc. */
|
||||
#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
|
||||
unsigned long post_log_word; /* Record POST activities */
|
||||
unsigned long post_log_res; /* success of POST test */
|
||||
unsigned long post_init_f_time; /* When post_init_f started */
|
||||
#endif
|
||||
} gd_t;
|
||||
|
||||
/*
|
||||
* Global Data Flags
|
||||
*/
|
||||
#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
|
||||
#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
|
||||
#define GD_FLG_SILENT 0x00004 /* Silent mode */
|
||||
#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
|
||||
#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
|
||||
#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
|
||||
#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
|
||||
#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
|
||||
|
||||
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
|
||||
|
||||
#endif /* __ASM_GBL_DATA_H */
|
20
src/arch/armv7/include/hang.h
Normal file
20
src/arch/armv7/include/hang.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
void hang(void);
|
6
src/arch/armv7/include/mmio_conf.h
Normal file
6
src/arch/armv7/include/mmio_conf.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef ARCH_MMIO_H
|
||||
#define ARCH_MMIO_H 1
|
||||
|
||||
// Nut'n'Bitch
|
||||
|
||||
#endif /* ARCH_MMIO_H */
|
30
src/arch/armv7/include/ptrace.h
Normal file
30
src/arch/armv7/include/ptrace.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef __ASM_ARM_PTRACE_H
|
||||
#define __ASM_ARM_PTRACE_H
|
||||
|
||||
#define PTRACE_GETREGS 12
|
||||
#define PTRACE_SETREGS 13
|
||||
#define PTRACE_GETFPREGS 14
|
||||
#define PTRACE_SETFPREGS 15
|
||||
|
||||
#define PTRACE_SETOPTIONS 21
|
||||
|
||||
/* options set using PTRACE_SETOPTIONS */
|
||||
#define PTRACE_O_TRACESYSGOOD 0x00000001
|
||||
|
||||
#include <asm/proc/ptrace.h>
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#define pc_pointer(v) \
|
||||
((v) & ~PCMASK)
|
||||
|
||||
#define instruction_pointer(regs) \
|
||||
(pc_pointer((regs)->ARM_pc))
|
||||
|
||||
extern void show_regs(struct pt_regs *);
|
||||
|
||||
#define predicate(x) (x & 0xf0000000)
|
||||
#define PREDICATE_ALWAYS 0xe0000000
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif
|
52
src/arch/armv7/include/smp/spinlock.h
Normal file
52
src/arch/armv7/include/smp/spinlock.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef ARCH_SMP_SPINLOCK_H
|
||||
#define ARCH_SMP_SPINLOCK_H
|
||||
|
||||
/* FIXME: implement this for ARM */
|
||||
#error "implement this for ARM"
|
||||
#if 0
|
||||
/*
|
||||
* Your basic SMP spinlocks, allowing only a single CPU anywhere
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
volatile unsigned int lock;
|
||||
} spinlock_t;
|
||||
|
||||
|
||||
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
|
||||
#define DECLARE_SPIN_LOCK(x) static spinlock_t x = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
#define barrier() __asm__ __volatile__("": : :"memory")
|
||||
#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) != 0)
|
||||
#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
|
||||
|
||||
static inline __attribute__((always_inline)) void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
unsigned long tmp;
|
||||
__asm__ __volatile__ (
|
||||
"1: ldrex %0, [%1]\n"
|
||||
" teq %0, #0\n"
|
||||
" strexeq %0, %2, [%1]\n"
|
||||
" teqeq %0, #0\n"
|
||||
" bne 1b\n"
|
||||
: "=&r" (tmp)
|
||||
: "r" (&lock->lock), "r" (1)
|
||||
: "cc"
|
||||
);
|
||||
barrier();
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
" str %1, [%0]\n"
|
||||
:
|
||||
: "r" (&lock->lock), "r" (0)
|
||||
: "cc"
|
||||
);
|
||||
}
|
||||
|
||||
#define cpu_relax() barrier()
|
||||
|
||||
#endif
|
||||
#endif /* ARCH_SMP_SPINLOCK_H */
|
81
src/arch/armv7/include/stdint.h
Normal file
81
src/arch/armv7/include/stdint.h
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef ARM_STDINT_H
|
||||
#define ARM_STDINT_H
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define __HAVE_LONG_LONG__ 1
|
||||
#else
|
||||
#define __HAVE_LONG_LONG__ 0
|
||||
#endif
|
||||
|
||||
/* Exact integral types */
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed char int8_t;
|
||||
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed short int16_t;
|
||||
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed int int32_t;
|
||||
|
||||
#if __HAVE_LONG_LONG__
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef signed long long int64_t;
|
||||
#endif
|
||||
|
||||
/* Small types */
|
||||
typedef unsigned char uint_least8_t;
|
||||
typedef signed char int_least8_t;
|
||||
|
||||
typedef unsigned short uint_least16_t;
|
||||
typedef signed short int_least16_t;
|
||||
|
||||
typedef unsigned int uint_least32_t;
|
||||
typedef signed int int_least32_t;
|
||||
|
||||
#if __HAVE_LONG_LONG__
|
||||
typedef unsigned long long uint_least64_t;
|
||||
typedef signed long long int_least64_t;
|
||||
#endif
|
||||
|
||||
/* Fast Types */
|
||||
typedef unsigned char uint_fast8_t;
|
||||
typedef signed char int_fast8_t;
|
||||
|
||||
typedef unsigned int uint_fast16_t;
|
||||
typedef signed int int_fast16_t;
|
||||
|
||||
typedef unsigned int uint_fast32_t;
|
||||
typedef signed int int_fast32_t;
|
||||
|
||||
#if __HAVE_LONG_LONG__
|
||||
typedef unsigned long long uint_fast64_t;
|
||||
typedef signed long long int_fast64_t;
|
||||
#endif
|
||||
|
||||
/* Types for `void *' pointers. */
|
||||
typedef int intptr_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
|
||||
/* Largest integral types */
|
||||
#if __HAVE_LONG_LONG__
|
||||
typedef long long int intmax_t;
|
||||
typedef unsigned long long uintmax_t;
|
||||
#else
|
||||
typedef long int intmax_t;
|
||||
typedef unsigned long int uintmax_t;
|
||||
#endif
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
#if __HAVE_LONG_LONG__
|
||||
typedef uint64_t u64;
|
||||
#endif
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
|
||||
|
||||
#undef __HAVE_LONG_LONG__
|
||||
|
||||
#endif /* ARM_STDINT_H */
|
123
src/arch/armv7/include/system.h
Normal file
123
src/arch/armv7/include/system.h
Normal file
@ -0,0 +1,123 @@
|
||||
/* FIXME(dhendrix): This is split out from asm/system.h. */
|
||||
#ifndef SYSTEM_H_
|
||||
#define SYSTEM_H_
|
||||
|
||||
#define CPU_ARCH_UNKNOWN 0
|
||||
#define CPU_ARCH_ARMv3 1
|
||||
#define CPU_ARCH_ARMv4 2
|
||||
#define CPU_ARCH_ARMv4T 3
|
||||
#define CPU_ARCH_ARMv5 4
|
||||
#define CPU_ARCH_ARMv5T 5
|
||||
#define CPU_ARCH_ARMv5TE 6
|
||||
#define CPU_ARCH_ARMv5TEJ 7
|
||||
#define CPU_ARCH_ARMv6 8
|
||||
#define CPU_ARCH_ARMv7 9
|
||||
|
||||
/*
|
||||
* CR1 bits (CP#15 CR1)
|
||||
*/
|
||||
#define CR_M (1 << 0) /* MMU enable */
|
||||
#define CR_A (1 << 1) /* Alignment abort enable */
|
||||
#define CR_C (1 << 2) /* Dcache enable */
|
||||
#define CR_W (1 << 3) /* Write buffer enable */
|
||||
#define CR_P (1 << 4) /* 32-bit exception handler */
|
||||
#define CR_D (1 << 5) /* 32-bit data address range */
|
||||
#define CR_L (1 << 6) /* Implementation defined */
|
||||
#define CR_B (1 << 7) /* Big endian */
|
||||
#define CR_S (1 << 8) /* System MMU protection */
|
||||
#define CR_R (1 << 9) /* ROM MMU protection */
|
||||
#define CR_F (1 << 10) /* Implementation defined */
|
||||
#define CR_Z (1 << 11) /* Implementation defined */
|
||||
#define CR_I (1 << 12) /* Icache enable */
|
||||
#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */
|
||||
#define CR_RR (1 << 14) /* Round Robin cache replacement */
|
||||
#define CR_L4 (1 << 15) /* LDR pc can set T bit */
|
||||
#define CR_DT (1 << 16)
|
||||
#define CR_IT (1 << 18)
|
||||
#define CR_ST (1 << 19)
|
||||
#define CR_FI (1 << 21) /* Fast interrupt (lower latency mode) */
|
||||
#define CR_U (1 << 22) /* Unaligned access operation */
|
||||
#define CR_XP (1 << 23) /* Extended page tables */
|
||||
#define CR_VE (1 << 24) /* Vectored interrupts */
|
||||
#define CR_EE (1 << 25) /* Exception (Big) Endian */
|
||||
#define CR_TRE (1 << 28) /* TEX remap enable */
|
||||
#define CR_AFE (1 << 29) /* Access flag enable */
|
||||
#define CR_TE (1 << 30) /* Thumb exception enable */
|
||||
|
||||
/*
|
||||
* This is used to ensure the compiler did actually allocate the register we
|
||||
* asked it for some inline assembly sequences. Apparently we can't trust
|
||||
* the compiler from one version to another so a bit of paranoia won't hurt.
|
||||
* This string is meant to be concatenated with the inline asm string and
|
||||
* will cause compilation to stop on mismatch.
|
||||
* (for details, see gcc PR 15089)
|
||||
*/
|
||||
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
|
||||
|
||||
#define isb() __asm__ __volatile__ ("" : : : "memory")
|
||||
|
||||
#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
|
||||
|
||||
#define arch_align_stack(x) (x)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
static inline unsigned int get_cr(void)
|
||||
{
|
||||
unsigned int val;
|
||||
asm("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val) : : "cc");
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void set_cr(unsigned int val)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR"
|
||||
: : "r" (val) : "cc");
|
||||
isb();
|
||||
}
|
||||
|
||||
/* options available for data cache on each page */
|
||||
enum dcache_option {
|
||||
DCACHE_OFF,
|
||||
DCACHE_WRITETHROUGH,
|
||||
DCACHE_WRITEBACK,
|
||||
};
|
||||
|
||||
/* Size of an MMU section */
|
||||
enum {
|
||||
MMU_SECTION_SHIFT = 20,
|
||||
MMU_SECTION_SIZE = 1 << MMU_SECTION_SHIFT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the cache settings for a region.
|
||||
*
|
||||
* \param start start address of memory region to change
|
||||
* \param size size of memory region to change
|
||||
* \param option dcache option to select
|
||||
*/
|
||||
void mmu_set_region_dcache(unsigned long start, int size,
|
||||
enum dcache_option option);
|
||||
|
||||
/**
|
||||
* Register an update to the page tables, and flush the TLB
|
||||
*
|
||||
* \param start start address of update in page table
|
||||
* \param stop stop address of update in page table
|
||||
*/
|
||||
void mmu_page_table_flush(unsigned long start, unsigned long stop);
|
||||
|
||||
void dram_bank_mmu_setup(unsigned long start, unsigned long size);
|
||||
|
||||
void arm_init_before_mmu(void);
|
||||
|
||||
/*
|
||||
* FIXME: sdelay, sr32, and wait_on_value originally came from
|
||||
* arch/arm/cpu/armv7/exynos5/setup.h in u-boot but do not seem
|
||||
* specific to exynos5...
|
||||
*/
|
||||
void sdelay(unsigned long loops);
|
||||
void sr32(void *addr, u32 start_bit, u32 num_bits, u32 value);
|
||||
u32 wait_on_value(u32 read_bit_mask, u32 match_value, void *read_addr,
|
||||
u32 bound);
|
||||
#endif // __ASSEMBLY__
|
||||
#endif /* SYSTEM_H_ */
|
56
src/arch/armv7/include/utils.h
Normal file
56
src/arch/armv7/include/utils.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
* Aneesh V <aneesh@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
|
||||
*/
|
||||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
static inline s32 log_2_n_round_up(u32 n)
|
||||
{
|
||||
s32 log2n = -1;
|
||||
u32 temp = n;
|
||||
|
||||
while (temp) {
|
||||
log2n++;
|
||||
temp >>= 1;
|
||||
}
|
||||
|
||||
if (n & (n - 1))
|
||||
return log2n + 1; /* not power of 2 - round up */
|
||||
else
|
||||
return log2n; /* power of 2 */
|
||||
}
|
||||
|
||||
static inline s32 log_2_n_round_down(u32 n)
|
||||
{
|
||||
s32 log2n = -1;
|
||||
u32 temp = n;
|
||||
|
||||
while (temp) {
|
||||
log2n++;
|
||||
temp >>= 1;
|
||||
}
|
||||
|
||||
return log2n;
|
||||
}
|
||||
|
||||
#endif
|
74
src/arch/armv7/ldscript_failover.lb
Normal file
74
src/arch/armv7/ldscript_failover.lb
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2006 Advanced Micro Devices, Inc.
|
||||
* Copyright (C) 2008-2010 coresystems GmbH
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* We use ELF as output format. So that we can debug the code in some form. */
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
MEMORY {
|
||||
rom : ORIGIN = 0xffff0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
TARGET(binary)
|
||||
SECTIONS
|
||||
{
|
||||
/* Symbol ap_sipi_vector must be aligned to 4kB to start AP CPUs
|
||||
* with Startup IPI message without RAM. Align .rom to next 4 byte
|
||||
* boundary anyway, so no pad byte appears between _rom and _start.
|
||||
*/
|
||||
.bogus ROMLOC_MIN : {
|
||||
. = CONFIG_SIPI_VECTOR_IN_ROM ? ALIGN(4096) : ALIGN(4);
|
||||
ROMLOC = .;
|
||||
} >rom = 0xff
|
||||
|
||||
/* This section might be better named .setup */
|
||||
.rom ROMLOC : {
|
||||
_rom = .;
|
||||
ap_sipi_vector = .;
|
||||
*(.rom.text);
|
||||
*(.rom.data);
|
||||
*(.rom.data.*);
|
||||
*(.rodata.*);
|
||||
_erom = .;
|
||||
} >rom = 0xff
|
||||
|
||||
/* Allocation reserves extra 16 bytes here. Alignment requirements
|
||||
* may cause the total size of a section to change when the start
|
||||
* address gets applied.
|
||||
*/
|
||||
ROMLOC_MIN = 0xffffff00 - (_erom - _rom + 16) -
|
||||
(CONFIG_SIPI_VECTOR_IN_ROM ? 4096 : 0);
|
||||
|
||||
/* Post-check proper SIPI vector. */
|
||||
_bogus = ASSERT(!CONFIG_SIPI_VECTOR_IN_ROM || ((ap_sipi_vector & 0x0fff) == 0x0),
|
||||
"Bad SIPI vector alignment");
|
||||
_bogus = ASSERT(!CONFIG_SIPI_VECTOR_IN_ROM || (ap_sipi_vector == CONFIG_AP_SIPI_VECTOR),
|
||||
"Address mismatch on AP_SIPI_VECTOR");
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment)
|
||||
*(.note)
|
||||
*(.comment.*)
|
||||
*(.note.*)
|
||||
*(.iplt)
|
||||
*(.rel.*)
|
||||
*(.igot.*)
|
||||
}
|
||||
}
|
51
src/arch/armv7/ldscript_fallback_cbfs.lb
Normal file
51
src/arch/armv7/ldscript_fallback_cbfs.lb
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Google Inc.
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* We use ELF as output format. So that we can debug the code in some form. */
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
TARGET(binary)
|
||||
SECTIONS
|
||||
{
|
||||
. = CONFIG_ROMBASE;
|
||||
|
||||
/* cut _start into last 64k*/
|
||||
_x = .;
|
||||
. = (_x < (CONFIG_ROMBASE - 0x10000 + CONFIG_ROM_IMAGE_SIZE)) ? (CONFIG_ROMBASE - 0x10000 + CONFIG_ROM_IMAGE_SIZE) : _x;
|
||||
|
||||
/* This section might be better named .setup */
|
||||
.rom . : {
|
||||
_rom = .;
|
||||
*(.text);
|
||||
*(.rodata);
|
||||
*(.rodata.*);
|
||||
*(.data.*);
|
||||
. = ALIGN(16);
|
||||
_erom = .;
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment)
|
||||
*(.note)
|
||||
*(.comment.*)
|
||||
*(.note.*)
|
||||
}
|
||||
_bogus = ASSERT((SIZEOF(.bss) + SIZEOF(.data)) == 0, "Do not use global variables in romstage");
|
||||
}
|
26
src/arch/armv7/lib/Makefile.inc
Normal file
26
src/arch/armv7/lib/Makefile.inc
Normal file
@ -0,0 +1,26 @@
|
||||
romstage-y += cache_v7.c
|
||||
romstage-y += cache-cp15.c
|
||||
romstage-y += div0.c
|
||||
romstage-y += div64.S
|
||||
romstage-y += hang_spl.c
|
||||
romstage-y += romstage_console.c
|
||||
romstage-y += syslib.c
|
||||
|
||||
#ramstage-y += printk_init.c
|
||||
#romstage-y += walkcbfs.S
|
||||
|
||||
ramstage-y += c_start.S
|
||||
|
||||
#ramstage-y += div.c
|
||||
ramstage-y += div0.c
|
||||
ramstage-y += div64.S
|
||||
ramstage-y += hang_spl.c
|
||||
#ramstage-y += interrupts.c
|
||||
#ramstage-y += memcpy.S
|
||||
#ramstage-y += memset.S
|
||||
#ramstage-y += reset.c
|
||||
ramstage-y += syslib.c
|
||||
|
||||
#FIXME(dhendrix): should this be a config option?
|
||||
romstage-y += eabi_compat.c
|
||||
ramstage-y += eabi_compat.c
|
95
src/arch/armv7/lib/Makefile.uboot
Normal file
95
src/arch/armv7/lib/Makefile.uboot
Normal file
@ -0,0 +1,95 @@
|
||||
#
|
||||
# (C) Copyright 2002-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)lib$(ARCH).o
|
||||
LIBGCC = $(obj)libgcc.o
|
||||
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
GLSOBJS += _ashldi3.o
|
||||
GLSOBJS += _ashrdi3.o
|
||||
GLSOBJS += _divsi3.o
|
||||
GLSOBJS += _lshrdi3.o
|
||||
GLSOBJS += _modsi3.o
|
||||
GLSOBJS += _udivsi3.o
|
||||
GLSOBJS += _umodsi3.o
|
||||
ifdef CONFIG_CHROMEOS
|
||||
GLSOBJS += _uldivmod.o
|
||||
endif
|
||||
|
||||
GLCOBJS += div0.o
|
||||
|
||||
ifeq ($(CONFIG_SYS_GENERIC_BOARD),)
|
||||
COBJS-y += board.o
|
||||
endif
|
||||
COBJS-y += bootm.o
|
||||
COBJS-y += cache.o
|
||||
COBJS-y += cache-cp15.o
|
||||
COBJS-$(CONFIG_SYS_L2_PL310) += cache-pl310.o
|
||||
SOBJS-$(CONFIG_USE_ARCH_MEMSET) += memset.o
|
||||
SOBJS-$(CONFIG_USE_ARCH_MEMCPY) += memcpy.o
|
||||
else # CONFIG_SPL_BUILD
|
||||
ifeq ($(CONFIG_SYS_GENERIC_BOARD),)
|
||||
COBJS-y += hang_spl.o
|
||||
endif
|
||||
endif # CONFIG_SPL_BUILD
|
||||
|
||||
COBJS-y += interrupts.o
|
||||
COBJS-y += reset.o
|
||||
|
||||
SRCS := $(GLSOBJS:.o=.S) $(GLCOBJS:.o=.c) \
|
||||
$(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
|
||||
LGOBJS := $(addprefix $(obj),$(GLSOBJS)) \
|
||||
$(addprefix $(obj),$(GLCOBJS))
|
||||
|
||||
# Always build libarm.o
|
||||
TARGETS := $(LIB)
|
||||
|
||||
# Build private libgcc only when asked for
|
||||
ifdef USE_PRIVATE_LIBGCC
|
||||
TARGETS += $(LIBGCC)
|
||||
endif
|
||||
|
||||
# For EABI conformant tool chains, provide eabi_compat()
|
||||
ifneq (,$(findstring -mabi=aapcs-linux,$(PLATFORM_CPPFLAGS)))
|
||||
TARGETS += $(obj)eabi_compat.o
|
||||
endif
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(call cmd_link_o_target, $(OBJS))
|
||||
|
||||
$(LIBGCC): $(obj).depend $(LGOBJS)
|
||||
$(call cmd_link_o_target, $(LGOBJS))
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
142
src/arch/armv7/lib/_divsi3.S
Normal file
142
src/arch/armv7/lib/_divsi3.S
Normal file
@ -0,0 +1,142 @@
|
||||
|
||||
.macro ARM_DIV_BODY dividend, divisor, result, curbit
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz \curbit, \divisor
|
||||
clz \result, \dividend
|
||||
sub \result, \curbit, \result
|
||||
mov \curbit, #1
|
||||
mov \divisor, \divisor, lsl \result
|
||||
mov \curbit, \curbit, lsl \result
|
||||
mov \result, #0
|
||||
|
||||
#else
|
||||
|
||||
@ Initially shift the divisor left 3 bits if possible,
|
||||
@ set curbit accordingly. This allows for curbit to be located
|
||||
@ at the left end of each 4 bit nibbles in the division loop
|
||||
@ to save one loop in most cases.
|
||||
tst \divisor, #0xe0000000
|
||||
moveq \divisor, \divisor, lsl #3
|
||||
moveq \curbit, #8
|
||||
movne \curbit, #1
|
||||
|
||||
@ Unless the divisor is very big, shift it up in multiples of
|
||||
@ four bits, since this is the amount of unwinding in the main
|
||||
@ division loop. Continue shifting until the divisor is
|
||||
@ larger than the dividend.
|
||||
1: cmp \divisor, #0x10000000
|
||||
cmplo \divisor, \dividend
|
||||
movlo \divisor, \divisor, lsl #4
|
||||
movlo \curbit, \curbit, lsl #4
|
||||
blo 1b
|
||||
|
||||
@ For very big divisors, we must shift it a bit at a time, or
|
||||
@ we will be in danger of overflowing.
|
||||
1: cmp \divisor, #0x80000000
|
||||
cmplo \divisor, \dividend
|
||||
movlo \divisor, \divisor, lsl #1
|
||||
movlo \curbit, \curbit, lsl #1
|
||||
blo 1b
|
||||
|
||||
mov \result, #0
|
||||
|
||||
#endif
|
||||
|
||||
@ Division loop
|
||||
1: cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
orrhs \result, \result, \curbit
|
||||
cmp \dividend, \divisor, lsr #1
|
||||
subhs \dividend, \dividend, \divisor, lsr #1
|
||||
orrhs \result, \result, \curbit, lsr #1
|
||||
cmp \dividend, \divisor, lsr #2
|
||||
subhs \dividend, \dividend, \divisor, lsr #2
|
||||
orrhs \result, \result, \curbit, lsr #2
|
||||
cmp \dividend, \divisor, lsr #3
|
||||
subhs \dividend, \dividend, \divisor, lsr #3
|
||||
orrhs \result, \result, \curbit, lsr #3
|
||||
cmp \dividend, #0 @ Early termination?
|
||||
movnes \curbit, \curbit, lsr #4 @ No, any more bits to do?
|
||||
movne \divisor, \divisor, lsr #4
|
||||
bne 1b
|
||||
|
||||
.endm
|
||||
|
||||
.macro ARM_DIV2_ORDER divisor, order
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz \order, \divisor
|
||||
rsb \order, \order, #31
|
||||
|
||||
#else
|
||||
|
||||
cmp \divisor, #(1 << 16)
|
||||
movhs \divisor, \divisor, lsr #16
|
||||
movhs \order, #16
|
||||
movlo \order, #0
|
||||
|
||||
cmp \divisor, #(1 << 8)
|
||||
movhs \divisor, \divisor, lsr #8
|
||||
addhs \order, \order, #8
|
||||
|
||||
cmp \divisor, #(1 << 4)
|
||||
movhs \divisor, \divisor, lsr #4
|
||||
addhs \order, \order, #4
|
||||
|
||||
cmp \divisor, #(1 << 2)
|
||||
addhi \order, \order, #3
|
||||
addls \order, \order, \divisor, lsr #1
|
||||
|
||||
#endif
|
||||
|
||||
.endm
|
||||
|
||||
.align 5
|
||||
.globl __divsi3
|
||||
.globl __aeabi_idiv
|
||||
__divsi3:
|
||||
__aeabi_idiv:
|
||||
cmp r1, #0
|
||||
eor ip, r0, r1 @ save the sign of the result.
|
||||
beq Ldiv0
|
||||
rsbmi r1, r1, #0 @ loops below use unsigned.
|
||||
subs r2, r1, #1 @ division by 1 or -1 ?
|
||||
beq 10f
|
||||
movs r3, r0
|
||||
rsbmi r3, r0, #0 @ positive dividend value
|
||||
cmp r3, r1
|
||||
bls 11f
|
||||
tst r1, r2 @ divisor is power of 2 ?
|
||||
beq 12f
|
||||
|
||||
ARM_DIV_BODY r3, r1, r0, r2
|
||||
|
||||
cmp ip, #0
|
||||
rsbmi r0, r0, #0
|
||||
mov pc, lr
|
||||
|
||||
10: teq ip, r0 @ same sign ?
|
||||
rsbmi r0, r0, #0
|
||||
mov pc, lr
|
||||
|
||||
11: movlo r0, #0
|
||||
moveq r0, ip, asr #31
|
||||
orreq r0, r0, #1
|
||||
mov pc, lr
|
||||
|
||||
12: ARM_DIV2_ORDER r1, r2
|
||||
|
||||
cmp ip, #0
|
||||
mov r0, r3, lsr r2
|
||||
rsbmi r0, r0, #0
|
||||
mov pc, lr
|
||||
|
||||
Ldiv0:
|
||||
|
||||
str lr, [sp, #-4]!
|
||||
bl __div0
|
||||
mov r0, #0 @ About as wrong as it could be.
|
||||
ldr pc, [sp], #4
|
93
src/arch/armv7/lib/_udivsi3.S
Normal file
93
src/arch/armv7/lib/_udivsi3.S
Normal file
@ -0,0 +1,93 @@
|
||||
/* # 1 "libgcc1.S" */
|
||||
@ libgcc1 routines for ARM cpu.
|
||||
@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk)
|
||||
dividend .req r0
|
||||
divisor .req r1
|
||||
result .req r2
|
||||
curbit .req r3
|
||||
/* ip .req r12 */
|
||||
/* sp .req r13 */
|
||||
/* lr .req r14 */
|
||||
/* pc .req r15 */
|
||||
.text
|
||||
.globl __udivsi3
|
||||
.type __udivsi3 ,function
|
||||
.globl __aeabi_uidiv
|
||||
.type __aeabi_uidiv ,function
|
||||
.align 0
|
||||
__udivsi3:
|
||||
__aeabi_uidiv:
|
||||
cmp divisor, #0
|
||||
beq Ldiv0
|
||||
mov curbit, #1
|
||||
mov result, #0
|
||||
cmp dividend, divisor
|
||||
bcc Lgot_result
|
||||
Loop1:
|
||||
@ Unless the divisor is very big, shift it up in multiples of
|
||||
@ four bits, since this is the amount of unwinding in the main
|
||||
@ division loop. Continue shifting until the divisor is
|
||||
@ larger than the dividend.
|
||||
cmp divisor, #0x10000000
|
||||
cmpcc divisor, dividend
|
||||
movcc divisor, divisor, lsl #4
|
||||
movcc curbit, curbit, lsl #4
|
||||
bcc Loop1
|
||||
Lbignum:
|
||||
@ For very big divisors, we must shift it a bit at a time, or
|
||||
@ we will be in danger of overflowing.
|
||||
cmp divisor, #0x80000000
|
||||
cmpcc divisor, dividend
|
||||
movcc divisor, divisor, lsl #1
|
||||
movcc curbit, curbit, lsl #1
|
||||
bcc Lbignum
|
||||
Loop3:
|
||||
@ Test for possible subtractions, and note which bits
|
||||
@ are done in the result. On the final pass, this may subtract
|
||||
@ too much from the dividend, but the result will be ok, since the
|
||||
@ "bit" will have been shifted out at the bottom.
|
||||
cmp dividend, divisor
|
||||
subcs dividend, dividend, divisor
|
||||
orrcs result, result, curbit
|
||||
cmp dividend, divisor, lsr #1
|
||||
subcs dividend, dividend, divisor, lsr #1
|
||||
orrcs result, result, curbit, lsr #1
|
||||
cmp dividend, divisor, lsr #2
|
||||
subcs dividend, dividend, divisor, lsr #2
|
||||
orrcs result, result, curbit, lsr #2
|
||||
cmp dividend, divisor, lsr #3
|
||||
subcs dividend, dividend, divisor, lsr #3
|
||||
orrcs result, result, curbit, lsr #3
|
||||
cmp dividend, #0 @ Early termination?
|
||||
movnes curbit, curbit, lsr #4 @ No, any more bits to do?
|
||||
movne divisor, divisor, lsr #4
|
||||
bne Loop3
|
||||
Lgot_result:
|
||||
mov r0, result
|
||||
mov pc, lr
|
||||
Ldiv0:
|
||||
str lr, [sp, #-4]!
|
||||
bl __div0 (PLT)
|
||||
mov r0, #0 @ about as wrong as it could be
|
||||
ldmia sp!, {pc}
|
||||
.size __udivsi3 , . - __udivsi3
|
||||
|
||||
.globl __aeabi_uidivmod
|
||||
__aeabi_uidivmod:
|
||||
|
||||
stmfd sp!, {r0, r1, ip, lr}
|
||||
bl __aeabi_uidiv
|
||||
ldmfd sp!, {r1, r2, ip, lr}
|
||||
mul r3, r0, r2
|
||||
sub r1, r1, r3
|
||||
mov pc, lr
|
||||
|
||||
.globl __aeabi_idivmod
|
||||
__aeabi_idivmod:
|
||||
|
||||
stmfd sp!, {r0, r1, ip, lr}
|
||||
bl __aeabi_idiv
|
||||
ldmfd sp!, {r1, r2, ip, lr}
|
||||
mul r3, r0, r2
|
||||
sub r1, r1, r3
|
||||
mov pc, lr
|
157
src/arch/armv7/lib/_uldivmod.S
Normal file
157
src/arch/armv7/lib/_uldivmod.S
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A, Q = r0 + (r1 << 32)
|
||||
* B, R = r2 + (r3 << 32)
|
||||
* A / B = Q ... R
|
||||
*/
|
||||
|
||||
.text
|
||||
.global __aeabi_uldivmod
|
||||
.type __aeabi_uldivmod, function
|
||||
.align 0
|
||||
|
||||
A_0 .req r0
|
||||
A_1 .req r1
|
||||
B_0 .req r2
|
||||
B_1 .req r3
|
||||
C_0 .req r4
|
||||
C_1 .req r5
|
||||
D_0 .req r6
|
||||
D_1 .req r7
|
||||
|
||||
Q_0 .req r0
|
||||
Q_1 .req r1
|
||||
R_0 .req r2
|
||||
R_1 .req r3
|
||||
|
||||
__aeabi_uldivmod:
|
||||
stmfd sp!, {r4, r5, r6, r7, lr}
|
||||
@ Test if B == 0
|
||||
orrs ip, B_0, B_1 @ Z set -> B == 0
|
||||
beq L_div_by_0
|
||||
@ Test if B is power of 2: (B & (B - 1)) == 0
|
||||
subs C_0, B_0, #1
|
||||
sbc C_1, B_1, #0
|
||||
tst C_0, B_0
|
||||
tsteq B_1, C_1
|
||||
beq L_pow2
|
||||
@ Test if A_1 == B_1 == 0
|
||||
orrs ip, A_1, B_1
|
||||
beq L_div_32_32
|
||||
|
||||
L_div_64_64:
|
||||
mov C_0, #1
|
||||
mov C_1, #0
|
||||
@ D_0 = clz A
|
||||
teq A_1, #0
|
||||
clz D_0, A_1
|
||||
clzeq ip, A_0
|
||||
addeq D_0, D_0, ip
|
||||
@ D_1 = clz B
|
||||
teq B_1, #0
|
||||
clz D_1, B_1
|
||||
clzeq ip, B_0
|
||||
addeq D_1, D_1, ip
|
||||
@ if clz B - clz A > 0
|
||||
subs D_0, D_1, D_0
|
||||
bls L_done_shift
|
||||
@ B <<= (clz B - clz A)
|
||||
subs D_1, D_0, #32
|
||||
rsb ip, D_0, #32
|
||||
movmi B_1, B_1, lsl D_0
|
||||
orrmi B_1, B_1, B_0, lsr ip
|
||||
movpl B_1, B_0, lsl D_1
|
||||
mov B_0, B_0, lsl D_0
|
||||
@ C = 1 << (clz B - clz A)
|
||||
movmi C_1, C_1, lsl D_0
|
||||
orrmi C_1, C_1, C_0, lsr ip
|
||||
movpl C_1, C_0, lsl D_1
|
||||
mov C_0, C_0, lsl D_0
|
||||
L_done_shift:
|
||||
mov D_0, #0
|
||||
mov D_1, #0
|
||||
@ C: current bit; D: result
|
||||
L_subtract:
|
||||
@ if A >= B
|
||||
cmp A_1, B_1
|
||||
cmpeq A_0, B_0
|
||||
bcc L_update
|
||||
@ A -= B
|
||||
subs A_0, A_0, B_0
|
||||
sbc A_1, A_1, B_1
|
||||
@ D |= C
|
||||
orr D_0, D_0, C_0
|
||||
orr D_1, D_1, C_1
|
||||
L_update:
|
||||
@ if A == 0: break
|
||||
orrs ip, A_1, A_0
|
||||
beq L_exit
|
||||
@ C >>= 1
|
||||
movs C_1, C_1, lsr #1
|
||||
movs C_0, C_0, rrx
|
||||
@ if C == 0: break
|
||||
orrs ip, C_1, C_0
|
||||
beq L_exit
|
||||
@ B >>= 1
|
||||
movs B_1, B_1, lsr #1
|
||||
mov B_0, B_0, rrx
|
||||
b L_subtract
|
||||
L_exit:
|
||||
@ Note: A, B & Q, R are aliases
|
||||
mov R_0, A_0
|
||||
mov R_1, A_1
|
||||
mov Q_0, D_0
|
||||
mov Q_1, D_1
|
||||
ldmfd sp!, {r4, r5, r6, r7, pc}
|
||||
|
||||
L_div_32_32:
|
||||
@ Note: A_0 & r0 are aliases
|
||||
@ Q_1 r1
|
||||
mov r1, B_0
|
||||
bl __aeabi_uidivmod
|
||||
mov R_0, r1
|
||||
mov R_1, #0
|
||||
mov Q_1, #0
|
||||
ldmfd sp!, {r4, r5, r6, r7, pc}
|
||||
|
||||
L_pow2:
|
||||
@ Note: A, B and Q, R are aliases
|
||||
@ R = A & (B - 1)
|
||||
and C_0, A_0, C_0
|
||||
and C_1, A_1, C_1
|
||||
@ Q = A >> log2(B)
|
||||
@ Note: B must not be 0 here!
|
||||
clz D_0, B_0
|
||||
add D_1, D_0, #1
|
||||
rsbs D_0, D_0, #31
|
||||
bpl L_1
|
||||
clz D_0, B_1
|
||||
rsb D_0, D_0, #31
|
||||
mov A_0, A_1, lsr D_0
|
||||
add D_0, D_0, #32
|
||||
L_1:
|
||||
movpl A_0, A_0, lsr D_0
|
||||
orrpl A_0, A_0, A_1, lsl D_1
|
||||
mov A_1, A_1, lsr D_0
|
||||
@ Mov back C to R
|
||||
mov R_0, C_0
|
||||
mov R_1, C_1
|
||||
ldmfd sp!, {r4, r5, r6, r7, pc}
|
||||
|
||||
L_div_by_0:
|
||||
bl __div0
|
||||
@ As wrong as it could be
|
||||
mov Q_0, #0
|
||||
mov Q_1, #0
|
||||
mov R_0, #0
|
||||
mov R_1, #0
|
||||
ldmfd sp!, {r4, r5, r6, r7, pc}
|
405
src/arch/armv7/lib/bootm.c
Normal file
405
src/arch/armv7/lib/bootm.c
Normal file
@ -0,0 +1,405 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
|
||||
*
|
||||
* 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 <command.h>
|
||||
#include <image.h>
|
||||
#include <u-boot/zlib.h>
|
||||
#include <arch/byteorder.h>
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
#include <fdt_support.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
|
||||
defined (CONFIG_CMDLINE_TAG) || \
|
||||
defined (CONFIG_INITRD_TAG) || \
|
||||
defined (CONFIG_SERIAL_TAG) || \
|
||||
defined (CONFIG_REVISION_TAG)
|
||||
static void setup_start_tag (bd_t *bd);
|
||||
|
||||
# ifdef CONFIG_SETUP_MEMORY_TAGS
|
||||
static void setup_memory_tags (bd_t *bd);
|
||||
# endif
|
||||
static void setup_commandline_tag (bd_t *bd, char *commandline);
|
||||
|
||||
# ifdef CONFIG_INITRD_TAG
|
||||
static void setup_initrd_tag (bd_t *bd, ulong initrd_start,
|
||||
ulong initrd_end);
|
||||
# endif
|
||||
static void setup_end_tag (bd_t *bd);
|
||||
|
||||
# if defined (CONFIG_VFD) || defined (CONFIG_LCD)
|
||||
# if !defined(CONFIG_VIDEOFLB_ATAG_NOT_SUPPORTED)
|
||||
static void setup_videolfb_tag (gd_t *gd);
|
||||
# endif
|
||||
# endif
|
||||
|
||||
static struct tag *params;
|
||||
#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
|
||||
|
||||
static ulong get_sp(void);
|
||||
#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
|
||||
static int bootm_linux_fdt(int machid, bootm_headers_t *images);
|
||||
#endif
|
||||
|
||||
void arch_lmb_reserve(struct lmb *lmb)
|
||||
{
|
||||
ulong sp;
|
||||
|
||||
/*
|
||||
* Booting a (Linux) kernel image
|
||||
*
|
||||
* Allocate space for command line and board info - the
|
||||
* address should be as high as possible within the reach of
|
||||
* the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused
|
||||
* memory, which means far enough below the current stack
|
||||
* pointer.
|
||||
*/
|
||||
sp = get_sp();
|
||||
debug("## Current stack ends at 0x%08lx ", sp);
|
||||
|
||||
/* adjust sp by 1K to be safe */
|
||||
sp -= 1024;
|
||||
lmb_reserve(lmb, sp,
|
||||
gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp);
|
||||
}
|
||||
|
||||
static void announce_and_cleanup(void)
|
||||
{
|
||||
printf("\nStarting kernel ...\n\n");
|
||||
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
|
||||
|
||||
#ifdef CONFIG_USB_DEVICE
|
||||
{
|
||||
extern void udc_disconnect(void);
|
||||
udc_disconnect();
|
||||
}
|
||||
#endif
|
||||
cleanup_before_linux();
|
||||
}
|
||||
|
||||
int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
char *s;
|
||||
int machid = bd->bi_arch_number;
|
||||
void (*kernel_entry)(int zero, int arch, uint params);
|
||||
|
||||
#ifdef CONFIG_CMDLINE_TAG
|
||||
char *commandline = getenv ("bootargs");
|
||||
#endif
|
||||
|
||||
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
|
||||
return 1;
|
||||
|
||||
s = getenv ("machid");
|
||||
if (s) {
|
||||
machid = simple_strtoul (s, NULL, 16);
|
||||
printf ("Using machid 0x%x from environment\n", machid);
|
||||
}
|
||||
|
||||
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
|
||||
|
||||
#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
|
||||
if (images->ft_len)
|
||||
return bootm_linux_fdt(machid, images);
|
||||
#endif
|
||||
|
||||
kernel_entry = (void (*)(int, int, uint))images->ep;
|
||||
|
||||
debug ("## Transferring control to Linux (at address %08lx) ...\n",
|
||||
(ulong) kernel_entry);
|
||||
|
||||
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
|
||||
defined (CONFIG_CMDLINE_TAG) || \
|
||||
defined (CONFIG_INITRD_TAG) || \
|
||||
defined (CONFIG_SERIAL_TAG) || \
|
||||
defined (CONFIG_REVISION_TAG)
|
||||
setup_start_tag (bd);
|
||||
#ifdef CONFIG_SERIAL_TAG
|
||||
setup_serial_tag (¶ms);
|
||||
#endif
|
||||
#ifdef CONFIG_REVISION_TAG
|
||||
setup_revision_tag (¶ms);
|
||||
#endif
|
||||
#ifdef CONFIG_SETUP_MEMORY_TAGS
|
||||
setup_memory_tags (bd);
|
||||
#endif
|
||||
#ifdef CONFIG_CMDLINE_TAG
|
||||
setup_commandline_tag (bd, commandline);
|
||||
#endif
|
||||
#ifdef CONFIG_INITRD_TAG
|
||||
if (images->rd_start && images->rd_end)
|
||||
setup_initrd_tag (bd, images->rd_start, images->rd_end);
|
||||
#endif
|
||||
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
|
||||
#if !defined(CONFIG_VIDEOFLB_ATAG_NOT_SUPPORTED)
|
||||
setup_videolfb_tag ((gd_t *) gd);
|
||||
#endif
|
||||
#endif
|
||||
setup_end_tag (bd);
|
||||
#endif
|
||||
|
||||
announce_and_cleanup();
|
||||
|
||||
kernel_entry(0, machid, bd->bi_boot_params);
|
||||
/* does not return */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
|
||||
static int fixup_memory_node(void *blob)
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
int bank;
|
||||
u64 start[CONFIG_NR_DRAM_BANKS];
|
||||
u64 size[CONFIG_NR_DRAM_BANKS];
|
||||
|
||||
for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
|
||||
start[bank] = bd->bi_dram[bank].start;
|
||||
size[bank] = bd->bi_dram[bank].size;
|
||||
}
|
||||
|
||||
return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
|
||||
}
|
||||
|
||||
static int bootm_linux_fdt(int machid, bootm_headers_t *images)
|
||||
{
|
||||
ulong rd_len;
|
||||
void (*kernel_entry)(int zero, int dt_machid, void *dtblob);
|
||||
ulong of_size = images->ft_len;
|
||||
char **of_flat_tree = &images->ft_addr;
|
||||
ulong *initrd_start = &images->initrd_start;
|
||||
ulong *initrd_end = &images->initrd_end;
|
||||
struct lmb *lmb = &images->lmb;
|
||||
int ret;
|
||||
|
||||
kernel_entry = (void (*)(int, int, void *))images->ep;
|
||||
|
||||
boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);
|
||||
|
||||
rd_len = images->rd_end - images->rd_start;
|
||||
ret = boot_ramdisk_high(lmb, images->rd_start, rd_len,
|
||||
initrd_start, initrd_end);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_OF_BOARD_SETUP
|
||||
/* Try to reserve 1024 bytes for board fixups */
|
||||
if (!fdt_open_into(*of_flat_tree, *of_flat_tree, of_size + 1024))
|
||||
of_size += 1024;
|
||||
/* Call the board-specific fixup routine */
|
||||
ft_board_setup(*of_flat_tree, gd->bd);
|
||||
#endif
|
||||
#ifdef CONFIG_OF_UPDATE_FDT_BEFORE_BOOT
|
||||
/* this must be earlier than boot_relocate_fdt */
|
||||
ret = fit_update_fdt_before_boot(*of_flat_tree, &of_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
debug("## Transferring control to Linux (at address %08lx) ...\n",
|
||||
(ulong) kernel_entry);
|
||||
|
||||
fdt_chosen(*of_flat_tree, 1);
|
||||
|
||||
fixup_memory_node(*of_flat_tree);
|
||||
|
||||
fdt_fixup_ethernet(*of_flat_tree);
|
||||
|
||||
fdt_initrd(*of_flat_tree, *initrd_start, *initrd_end, 1);
|
||||
|
||||
announce_and_cleanup();
|
||||
|
||||
kernel_entry(0, machid, *of_flat_tree);
|
||||
/* does not return */
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
|
||||
defined (CONFIG_CMDLINE_TAG) || \
|
||||
defined (CONFIG_INITRD_TAG) || \
|
||||
defined (CONFIG_SERIAL_TAG) || \
|
||||
defined (CONFIG_REVISION_TAG)
|
||||
static void setup_start_tag (bd_t *bd)
|
||||
{
|
||||
params = (struct tag *) bd->bi_boot_params;
|
||||
|
||||
params->hdr.tag = ATAG_CORE;
|
||||
params->hdr.size = tag_size (tag_core);
|
||||
|
||||
#if defined (ATAG_CORE_FLAGS) && \
|
||||
defined (ATAG_PAGE_SIZE) && \
|
||||
defined (ATAG_CORE_RDEV)
|
||||
params->u.core.flags = ATAG_CORE_FLAGS;
|
||||
params->u.core.pagesize = ATAG_PAGE_SIZE;
|
||||
params->u.core.rootdev = ATAG_CORE_RDEV;
|
||||
#else
|
||||
params->u.core.flags = 0;
|
||||
params->u.core.pagesize = 0;
|
||||
params->u.core.rootdev = 0;
|
||||
#endif
|
||||
|
||||
params = tag_next (params);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_SETUP_MEMORY_TAGS
|
||||
static void setup_memory_tags (bd_t *bd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
|
||||
params->hdr.tag = ATAG_MEM;
|
||||
params->hdr.size = tag_size (tag_mem32);
|
||||
|
||||
params->u.mem.start = bd->bi_dram[i].start;
|
||||
params->u.mem.size = bd->bi_dram[i].size;
|
||||
|
||||
params = tag_next (params);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SETUP_MEMORY_TAGS */
|
||||
|
||||
|
||||
static void setup_commandline_tag (bd_t *bd, char *commandline)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!commandline)
|
||||
return;
|
||||
|
||||
/* eat leading white space */
|
||||
for (p = commandline; *p == ' '; p++);
|
||||
|
||||
/* skip non-existent command lines so the kernel will still
|
||||
* use its default command line.
|
||||
*/
|
||||
if (*p == '\0')
|
||||
return;
|
||||
|
||||
params->hdr.tag = ATAG_CMDLINE;
|
||||
params->hdr.size =
|
||||
(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
|
||||
|
||||
strcpy (params->u.cmdline.cmdline, p);
|
||||
|
||||
params = tag_next (params);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_INITRD_TAG
|
||||
static void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end)
|
||||
{
|
||||
/* an ATAG_INITRD node tells the kernel where the compressed
|
||||
* ramdisk can be found. ATAG_RDIMG is a better name, actually.
|
||||
*/
|
||||
params->hdr.tag = ATAG_INITRD2;
|
||||
params->hdr.size = tag_size (tag_initrd);
|
||||
|
||||
params->u.initrd.start = initrd_start;
|
||||
params->u.initrd.size = initrd_end - initrd_start;
|
||||
|
||||
params = tag_next (params);
|
||||
}
|
||||
#endif /* CONFIG_INITRD_TAG */
|
||||
|
||||
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
|
||||
#if !defined(CONFIG_VIDEOFLB_ATAG_NOT_SUPPORTED)
|
||||
extern ulong calc_fbsize (void);
|
||||
static void setup_videolfb_tag (gd_t *gd)
|
||||
{
|
||||
/* An ATAG_VIDEOLFB node tells the kernel where and how large
|
||||
* the framebuffer for video was allocated (among other things).
|
||||
* Note that a _physical_ address is passed !
|
||||
*
|
||||
* We only use it to pass the address and size, the other entries
|
||||
* in the tag_videolfb are not of interest.
|
||||
*/
|
||||
params->hdr.tag = ATAG_VIDEOLFB;
|
||||
params->hdr.size = tag_size (tag_videolfb);
|
||||
|
||||
params->u.videolfb.lfb_base = (u32) gd->fb_base;
|
||||
/* Fb size is calculated according to parameters for our panel
|
||||
*/
|
||||
params->u.videolfb.lfb_size = calc_fbsize();
|
||||
|
||||
params = tag_next (params);
|
||||
}
|
||||
#endif /* CONFIG_VIDEOFLB_ATAG_NOT_SUPPORTED */
|
||||
#endif /* CONFIG_VFD || CONFIG_LCD */
|
||||
|
||||
#ifdef CONFIG_SERIAL_TAG
|
||||
void setup_serial_tag (struct tag **tmp)
|
||||
{
|
||||
struct tag *params = *tmp;
|
||||
struct tag_serialnr serialnr;
|
||||
void get_board_serial(struct tag_serialnr *serialnr);
|
||||
|
||||
get_board_serial(&serialnr);
|
||||
params->hdr.tag = ATAG_SERIAL;
|
||||
params->hdr.size = tag_size (tag_serialnr);
|
||||
params->u.serialnr.low = serialnr.low;
|
||||
params->u.serialnr.high= serialnr.high;
|
||||
params = tag_next (params);
|
||||
*tmp = params;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_REVISION_TAG
|
||||
void setup_revision_tag(struct tag **in_params)
|
||||
{
|
||||
u32 rev = 0;
|
||||
u32 get_board_rev(void);
|
||||
|
||||
rev = get_board_rev();
|
||||
params->hdr.tag = ATAG_REVISION;
|
||||
params->hdr.size = tag_size (tag_revision);
|
||||
params->u.revision.rev = rev;
|
||||
params = tag_next (params);
|
||||
}
|
||||
#endif /* CONFIG_REVISION_TAG */
|
||||
|
||||
static void setup_end_tag (bd_t *bd)
|
||||
{
|
||||
params->hdr.tag = ATAG_NONE;
|
||||
params->hdr.size = 0;
|
||||
}
|
||||
#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
|
||||
|
||||
static ulong get_sp(void)
|
||||
{
|
||||
ulong ret;
|
||||
|
||||
asm("mov %0, sp" : "=r"(ret) : );
|
||||
return ret;
|
||||
}
|
9
src/arch/armv7/lib/c_start.S
Normal file
9
src/arch/armv7/lib/c_start.S
Normal file
@ -0,0 +1,9 @@
|
||||
.section ".text"
|
||||
.globl _start
|
||||
_start:
|
||||
bl _hardwaremain
|
||||
|
||||
_hardwaremain: .word hardwaremain
|
||||
@ .word hardwaremain
|
||||
|
||||
|
304
src/arch/armv7/lib/cache-cp15.c
Normal file
304
src/arch/armv7/lib/cache-cp15.c
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* FIXME(dhendrix): clean-up weak symbols if it looks unlikely we'll
|
||||
want to override them with anything other than what's in cache_v7. */
|
||||
#include <common.h>
|
||||
#include <stdlib.h>
|
||||
#include <system.h>
|
||||
#include <global_data.h>
|
||||
|
||||
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if 0
|
||||
void __arm_init_before_mmu(void)
|
||||
{
|
||||
}
|
||||
void arm_init_before_mmu(void)
|
||||
__attribute__((weak, alias("__arm_init_before_mmu")));
|
||||
#endif
|
||||
|
||||
static void cp_delay (void)
|
||||
{
|
||||
volatile int i;
|
||||
|
||||
/* copro seems to need some delay between reading and writing */
|
||||
for (i = 0; i < 100; i++)
|
||||
nop();
|
||||
asm volatile("" : : : "memory");
|
||||
}
|
||||
|
||||
static void set_section_dcache(int section, enum dcache_option option)
|
||||
{
|
||||
u32 value = section << MMU_SECTION_SHIFT | (3 << 10);
|
||||
// u32 *page_table = (u32 *)gd->tlb_addr;
|
||||
u32 *page_table;
|
||||
unsigned int tlb_addr;
|
||||
unsigned int tlb_size = 4096 * 4;
|
||||
|
||||
/*
|
||||
* FIXME(dhendrix): This calculation is from arch/arm/lib/board.c
|
||||
* in u-boot. We may need to subtract more due to logging.
|
||||
*/
|
||||
tlb_addr = (CONFIG_SYS_SDRAM_BASE + (CONFIG_DRAM_SIZE_MB << 20UL));
|
||||
tlb_addr -= tlb_size;
|
||||
/* round down to next 64KB limit */
|
||||
tlb_addr &= ~(0x10000 - 1);
|
||||
page_table = (u32 *)tlb_addr;
|
||||
|
||||
switch (option) {
|
||||
case DCACHE_WRITETHROUGH:
|
||||
value |= 0x1a;
|
||||
break;
|
||||
|
||||
case DCACHE_WRITEBACK:
|
||||
value |= 0x1e;
|
||||
break;
|
||||
|
||||
case DCACHE_OFF:
|
||||
value |= 0x12;
|
||||
break;
|
||||
}
|
||||
|
||||
page_table[section] = value;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void __mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||
{
|
||||
debug("%s: Warning: not implemented\n", __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||
__attribute__((weak, alias("__mmu_page_table_flush")));
|
||||
#endif
|
||||
|
||||
void mmu_set_region_dcache(unsigned long start, int size, enum dcache_option option)
|
||||
{
|
||||
u32 *page_table = (u32 *)gd->tlb_addr;
|
||||
u32 upto, end;
|
||||
|
||||
end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT;
|
||||
start = start >> MMU_SECTION_SHIFT;
|
||||
debug("mmu_set_region_dcache start=%x, size=%x, option=%d\n",
|
||||
start, size, option);
|
||||
for (upto = start; upto < end; upto++)
|
||||
set_section_dcache(upto, option);
|
||||
mmu_page_table_flush((u32)&page_table[start], (u32)&page_table[end]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline void dram_bank_mmu_setup(int bank)
|
||||
{
|
||||
// bd_t *bd = gd->bd;
|
||||
int i;
|
||||
|
||||
debug("%s: bank: %d\n", __func__, bank);
|
||||
for (i = bd->bi_dram[bank].start >> 20;
|
||||
i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
|
||||
i++) {
|
||||
#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
|
||||
set_section_dcache(i, DCACHE_WRITETHROUGH);
|
||||
#else
|
||||
set_section_dcache(i, DCACHE_WRITEBACK);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* FIXME(dhendrix): modified to take arguments from the caller (mainboard's
|
||||
romstage.c) so it doesn't rely on global data struct */
|
||||
/**
|
||||
* dram_bank_mmu_set - set up the data cache policy for a given dram bank
|
||||
*
|
||||
* @start: virtual address start of bank
|
||||
* @size: size of bank (in bytes)
|
||||
*/
|
||||
inline void dram_bank_mmu_setup(unsigned long start, unsigned long size)
|
||||
{
|
||||
int i;
|
||||
|
||||
debug("%s: bank: %d\n", __func__, bank);
|
||||
for (i = start >> 20; i < (start + size) >> 20; i++) {
|
||||
#if defined(CONFIG_ARM_DCACHE_POLICY_WRITEBACK)
|
||||
set_section_dcache(i, DCACHE_WRITEBACK);
|
||||
#elif defined(CONFIG_ARM_DCACHE_POLICY_WRITETHROUGH)
|
||||
set_section_dcache(i, DCACHE_WRITETHROUGH);
|
||||
#else
|
||||
#error "Must define dcache policy."
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* to activate the MMU we need to set up virtual memory: use 1M areas */
|
||||
static inline void mmu_setup(void)
|
||||
{
|
||||
int i;
|
||||
u32 reg;
|
||||
|
||||
arm_init_before_mmu();
|
||||
/* Set up an identity-mapping for all 4GB, rw for everyone */
|
||||
for (i = 0; i < 4096; i++)
|
||||
set_section_dcache(i, DCACHE_OFF);
|
||||
|
||||
/* FIXME(dhendrix): u-boot's global data struct was used here... */
|
||||
#if 0
|
||||
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
|
||||
dram_bank_mmu_setup(i);
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
/* comes from board's romstage.c, since we need to know which
|
||||
ranges to setup */
|
||||
mainboard_setup_mmu();
|
||||
#endif
|
||||
dram_bank_mmu_setup(CONFIG_SYS_SDRAM_BASE, CONFIG_DRAM_SIZE_MB << 20);
|
||||
|
||||
/* Copy the page table address to cp15 */
|
||||
asm volatile("mcr p15, 0, %0, c2, c0, 0"
|
||||
: : "r" (gd->tlb_addr) : "memory");
|
||||
/* Set the access control to all-supervisor */
|
||||
asm volatile("mcr p15, 0, %0, c3, c0, 0"
|
||||
: : "r" (~0));
|
||||
/* and enable the mmu */
|
||||
reg = get_cr(); /* get control reg. */
|
||||
cp_delay();
|
||||
set_cr(reg | CR_M);
|
||||
}
|
||||
|
||||
static int mmu_enabled(void)
|
||||
{
|
||||
return get_cr() & CR_M;
|
||||
}
|
||||
|
||||
/* cache_bit must be either CR_I or CR_C */
|
||||
static void cache_enable(uint32_t cache_bit)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
/* The data cache is not active unless the mmu is enabled too */
|
||||
if ((cache_bit == CR_C) && !mmu_enabled())
|
||||
mmu_setup();
|
||||
reg = get_cr(); /* get control reg. */
|
||||
cp_delay();
|
||||
set_cr(reg | cache_bit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Big hack warning!
|
||||
*
|
||||
* Devs like to compile with -O0 to get a nice debugging illusion. But this
|
||||
* function does not survive that since -O0 causes the compiler to read the
|
||||
* PC back from the stack after the dcache flush. Might it be possible to fix
|
||||
* this by flushing the write buffer?
|
||||
*/
|
||||
static void cache_disable(uint32_t cache_bit) __attribute__ ((optimize(2)));
|
||||
|
||||
/* cache_bit must be either CR_I or CR_C */
|
||||
static void cache_disable(uint32_t cache_bit)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
if (cache_bit == CR_C) {
|
||||
/* if cache isn;t enabled no need to disable */
|
||||
reg = get_cr();
|
||||
if ((reg & CR_C) != CR_C)
|
||||
return;
|
||||
/* if disabling data cache, disable mmu too */
|
||||
cache_bit |= CR_M;
|
||||
}
|
||||
reg = get_cr();
|
||||
cp_delay();
|
||||
if (cache_bit == (CR_C | CR_M))
|
||||
flush_dcache_all();
|
||||
set_cr(reg & ~cache_bit);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_ICACHE_OFF
|
||||
void icache_enable (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void icache_disable (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int icache_status (void)
|
||||
{
|
||||
return 0; /* always off */
|
||||
}
|
||||
#else
|
||||
void icache_enable(void)
|
||||
{
|
||||
cache_enable(CR_I);
|
||||
}
|
||||
|
||||
void icache_disable(void)
|
||||
{
|
||||
cache_disable(CR_I);
|
||||
}
|
||||
|
||||
int icache_status(void)
|
||||
{
|
||||
return (get_cr() & CR_I) != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_DCACHE_OFF
|
||||
void dcache_enable (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void dcache_disable (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int dcache_status (void)
|
||||
{
|
||||
return 0; /* always off */
|
||||
}
|
||||
#else
|
||||
void dcache_enable(void)
|
||||
{
|
||||
cache_enable(CR_C);
|
||||
}
|
||||
|
||||
void dcache_disable(void)
|
||||
{
|
||||
cache_disable(CR_C);
|
||||
}
|
||||
|
||||
int dcache_status(void)
|
||||
{
|
||||
return (get_cr() & CR_C) != 0;
|
||||
}
|
||||
#endif
|
427
src/arch/armv7/lib/cache_v7.c
Normal file
427
src/arch/armv7/lib/cache_v7.c
Normal file
@ -0,0 +1,427 @@
|
||||
/*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
* Aneesh V <aneesh@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 <armv7.h>
|
||||
#include <common.h>
|
||||
#include <system.h>
|
||||
#include <utils.h>
|
||||
#include <console/console.h>
|
||||
|
||||
#define ARMV7_DCACHE_INVAL_ALL 1
|
||||
#define ARMV7_DCACHE_CLEAN_INVAL_ALL 2
|
||||
#define ARMV7_DCACHE_INVAL_RANGE 3
|
||||
#define ARMV7_DCACHE_CLEAN_INVAL_RANGE 4
|
||||
|
||||
#ifndef CONFIG_SYS_DCACHE_OFF
|
||||
/*
|
||||
* Write the level and type you want to Cache Size Selection Register(CSSELR)
|
||||
* to get size details from Current Cache Size ID Register(CCSIDR)
|
||||
*/
|
||||
static void set_csselr(u32 level, u32 type)
|
||||
{ u32 csselr = level << 1 | type;
|
||||
|
||||
/* Write to Cache Size Selection Register(CSSELR) */
|
||||
asm volatile ("mcr p15, 2, %0, c0, c0, 0" : : "r" (csselr));
|
||||
}
|
||||
|
||||
static u32 get_ccsidr(void)
|
||||
{
|
||||
u32 ccsidr;
|
||||
|
||||
/* Read current CP15 Cache Size ID Register */
|
||||
asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr));
|
||||
return ccsidr;
|
||||
}
|
||||
|
||||
static u32 get_clidr(void)
|
||||
{
|
||||
u32 clidr;
|
||||
|
||||
/* Read current CP15 Cache Level ID Register */
|
||||
asm volatile ("mrc p15,1,%0,c0,c0,1" : "=r" (clidr));
|
||||
return clidr;
|
||||
}
|
||||
|
||||
static void v7_inval_dcache_level_setway(u32 level, u32 num_sets,
|
||||
u32 num_ways, u32 way_shift,
|
||||
u32 log2_line_len)
|
||||
{
|
||||
int way, set, setway;
|
||||
|
||||
/*
|
||||
* For optimal assembly code:
|
||||
* a. count down
|
||||
* b. have bigger loop inside
|
||||
*/
|
||||
for (way = num_ways - 1; way >= 0 ; way--) {
|
||||
for (set = num_sets - 1; set >= 0; set--) {
|
||||
setway = (level << 1) | (set << log2_line_len) |
|
||||
(way << way_shift);
|
||||
/* Invalidate data/unified cache line by set/way */
|
||||
asm volatile (" mcr p15, 0, %0, c7, c6, 2"
|
||||
: : "r" (setway));
|
||||
}
|
||||
}
|
||||
/* DSB to make sure the operation is complete */
|
||||
CP15DSB;
|
||||
}
|
||||
|
||||
static void v7_clean_inval_dcache_level_setway(u32 level, u32 num_sets,
|
||||
u32 num_ways, u32 way_shift,
|
||||
u32 log2_line_len)
|
||||
{
|
||||
int way, set, setway;
|
||||
|
||||
/*
|
||||
* For optimal assembly code:
|
||||
* a. count down
|
||||
* b. have bigger loop inside
|
||||
*/
|
||||
for (way = num_ways - 1; way >= 0 ; way--) {
|
||||
for (set = num_sets - 1; set >= 0; set--) {
|
||||
setway = (level << 1) | (set << log2_line_len) |
|
||||
(way << way_shift);
|
||||
/*
|
||||
* Clean & Invalidate data/unified
|
||||
* cache line by set/way
|
||||
*/
|
||||
asm volatile (" mcr p15, 0, %0, c7, c14, 2"
|
||||
: : "r" (setway));
|
||||
}
|
||||
}
|
||||
/* DSB to make sure the operation is complete */
|
||||
CP15DSB;
|
||||
}
|
||||
|
||||
static void v7_maint_dcache_level_setway(u32 level, u32 operation)
|
||||
{
|
||||
u32 ccsidr;
|
||||
u32 num_sets, num_ways, log2_line_len, log2_num_ways;
|
||||
u32 way_shift;
|
||||
|
||||
set_csselr(level, ARMV7_CSSELR_IND_DATA_UNIFIED);
|
||||
|
||||
ccsidr = get_ccsidr();
|
||||
|
||||
log2_line_len = ((ccsidr & CCSIDR_LINE_SIZE_MASK) >>
|
||||
CCSIDR_LINE_SIZE_OFFSET) + 2;
|
||||
/* Converting from words to bytes */
|
||||
log2_line_len += 2;
|
||||
|
||||
num_ways = ((ccsidr & CCSIDR_ASSOCIATIVITY_MASK) >>
|
||||
CCSIDR_ASSOCIATIVITY_OFFSET) + 1;
|
||||
num_sets = ((ccsidr & CCSIDR_NUM_SETS_MASK) >>
|
||||
CCSIDR_NUM_SETS_OFFSET) + 1;
|
||||
/*
|
||||
* According to ARMv7 ARM number of sets and number of ways need
|
||||
* not be a power of 2
|
||||
*/
|
||||
log2_num_ways = log_2_n_round_up(num_ways);
|
||||
|
||||
way_shift = (32 - log2_num_ways);
|
||||
if (operation == ARMV7_DCACHE_INVAL_ALL) {
|
||||
v7_inval_dcache_level_setway(level, num_sets, num_ways,
|
||||
way_shift, log2_line_len);
|
||||
} else if (operation == ARMV7_DCACHE_CLEAN_INVAL_ALL) {
|
||||
v7_clean_inval_dcache_level_setway(level, num_sets, num_ways,
|
||||
way_shift, log2_line_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void v7_maint_dcache_all(u32 operation)
|
||||
{
|
||||
u32 level, cache_type, level_start_bit = 0;
|
||||
|
||||
u32 clidr = get_clidr();
|
||||
|
||||
for (level = 0; level < 7; level++) {
|
||||
cache_type = (clidr >> level_start_bit) & 0x7;
|
||||
if ((cache_type == ARMV7_CLIDR_CTYPE_DATA_ONLY) ||
|
||||
(cache_type == ARMV7_CLIDR_CTYPE_INSTRUCTION_DATA) ||
|
||||
(cache_type == ARMV7_CLIDR_CTYPE_UNIFIED))
|
||||
v7_maint_dcache_level_setway(level, operation);
|
||||
level_start_bit += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void v7_dcache_clean_inval_range(u32 start,
|
||||
u32 stop, u32 line_len)
|
||||
{
|
||||
u32 mva;
|
||||
|
||||
/* Align start to cache line boundary */
|
||||
start &= ~(line_len - 1);
|
||||
for (mva = start; mva < stop; mva = mva + line_len) {
|
||||
/* DCCIMVAC - Clean & Invalidate data cache by MVA to PoC */
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 1" : : "r" (mva));
|
||||
}
|
||||
}
|
||||
|
||||
static void v7_dcache_inval_range(u32 start, u32 stop, u32 line_len)
|
||||
{
|
||||
u32 mva;
|
||||
|
||||
/*
|
||||
* If start address is not aligned to cache-line do not
|
||||
* invalidate the first cache-line
|
||||
*/
|
||||
if (start & (line_len - 1)) {
|
||||
printk(BIOS_ERR, "%s - start address is not aligned - 0x%08x\n",
|
||||
__func__, start);
|
||||
/* move to next cache line */
|
||||
start = (start + line_len - 1) & ~(line_len - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* If stop address is not aligned to cache-line do not
|
||||
* invalidate the last cache-line
|
||||
*/
|
||||
if (stop & (line_len - 1)) {
|
||||
printk(BIOS_ERR, "%s - stop address is not aligned - 0x%08x\n",
|
||||
__func__, stop);
|
||||
/* align to the beginning of this cache line */
|
||||
stop &= ~(line_len - 1);
|
||||
}
|
||||
|
||||
for (mva = start; mva < stop; mva = mva + line_len) {
|
||||
/* DCIMVAC - Invalidate data cache by MVA to PoC */
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 1" : : "r" (mva));
|
||||
}
|
||||
}
|
||||
|
||||
static void v7_dcache_maint_range(u32 start, u32 stop, u32 range_op)
|
||||
{
|
||||
u32 line_len = dcache_get_line_size();
|
||||
|
||||
switch (range_op) {
|
||||
case ARMV7_DCACHE_CLEAN_INVAL_RANGE:
|
||||
v7_dcache_clean_inval_range(start, stop, line_len);
|
||||
break;
|
||||
case ARMV7_DCACHE_INVAL_RANGE:
|
||||
v7_dcache_inval_range(start, stop, line_len);
|
||||
break;
|
||||
}
|
||||
|
||||
/* DSB to make sure the operation is complete */
|
||||
CP15DSB;
|
||||
}
|
||||
|
||||
/* Invalidate TLB */
|
||||
static void v7_inval_tlb(void)
|
||||
{
|
||||
/* Invalidate entire unified TLB */
|
||||
asm volatile ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0));
|
||||
/* Invalidate entire data TLB */
|
||||
asm volatile ("mcr p15, 0, %0, c8, c6, 0" : : "r" (0));
|
||||
/* Invalidate entire instruction TLB */
|
||||
asm volatile ("mcr p15, 0, %0, c8, c5, 0" : : "r" (0));
|
||||
/* Full system DSB - make sure that the invalidation is complete */
|
||||
CP15DSB;
|
||||
/* Full system ISB - make sure the instruction stream sees it */
|
||||
CP15ISB;
|
||||
}
|
||||
|
||||
ulong dcache_get_line_size(void)
|
||||
{
|
||||
u32 line_len, ccsidr;
|
||||
|
||||
ccsidr = get_ccsidr();
|
||||
line_len = ((ccsidr & CCSIDR_LINE_SIZE_MASK) >>
|
||||
CCSIDR_LINE_SIZE_OFFSET) + 2;
|
||||
/* Converting from words to bytes */
|
||||
line_len += 2;
|
||||
/* converting from log2(linelen) to linelen */
|
||||
line_len = 1 << line_len;
|
||||
|
||||
return line_len;
|
||||
}
|
||||
|
||||
void invalidate_dcache_all(void)
|
||||
{
|
||||
v7_maint_dcache_all(ARMV7_DCACHE_INVAL_ALL);
|
||||
|
||||
v7_outer_cache_inval_all();
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a clean & invalidation of the entire data cache
|
||||
* at all levels
|
||||
*/
|
||||
void flush_dcache_all(void)
|
||||
{
|
||||
v7_maint_dcache_all(ARMV7_DCACHE_CLEAN_INVAL_ALL);
|
||||
|
||||
v7_outer_cache_flush_all();
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidates range in all levels of D-cache/unified cache used:
|
||||
* Affects the range [start, stop - 1]
|
||||
*/
|
||||
void invalidate_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
|
||||
v7_dcache_maint_range(start, stop, ARMV7_DCACHE_INVAL_RANGE);
|
||||
|
||||
v7_outer_cache_inval_range(start, stop);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush range(clean & invalidate) from all levels of D-cache/unified
|
||||
* cache used:
|
||||
* Affects the range [start, stop - 1]
|
||||
*/
|
||||
void flush_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
v7_dcache_maint_range(start, stop, ARMV7_DCACHE_CLEAN_INVAL_RANGE);
|
||||
|
||||
v7_outer_cache_flush_range(start, stop);
|
||||
}
|
||||
|
||||
void arm_init_before_mmu(void)
|
||||
{
|
||||
v7_outer_cache_enable();
|
||||
invalidate_dcache_all();
|
||||
v7_inval_tlb();
|
||||
}
|
||||
|
||||
void mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||
{
|
||||
flush_dcache_range(start, stop);
|
||||
v7_inval_tlb();
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush range from all levels of d-cache/unified-cache used:
|
||||
* Affects the range [start, start + size - 1]
|
||||
*/
|
||||
void flush_cache(unsigned long start, unsigned long size)
|
||||
{
|
||||
flush_dcache_range(start, start + size);
|
||||
}
|
||||
#else /* #ifndef CONFIG_SYS_DCACHE_OFF */
|
||||
ulong dcache_get_line_size(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void invalidate_dcache_all(void)
|
||||
{
|
||||
}
|
||||
|
||||
void flush_dcache_all(void)
|
||||
{
|
||||
}
|
||||
|
||||
void invalidate_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
|
||||
void flush_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
|
||||
void arm_init_before_mmu(void)
|
||||
{
|
||||
}
|
||||
|
||||
void flush_cache(unsigned long start, unsigned long size)
|
||||
{
|
||||
}
|
||||
|
||||
void mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* #ifndef CONFIG_SYS_DCACHE_OFF */
|
||||
|
||||
#ifndef CONFIG_SYS_ICACHE_OFF
|
||||
/* Invalidate entire I-cache and branch predictor array */
|
||||
void invalidate_icache_all(void)
|
||||
{
|
||||
/*
|
||||
* Invalidate all instruction caches to PoU.
|
||||
* Also flushes branch target cache.
|
||||
*/
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
|
||||
|
||||
/* Invalidate entire branch predictor array */
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 6" : : "r" (0));
|
||||
|
||||
/* Full system DSB - make sure that the invalidation is complete */
|
||||
CP15DSB;
|
||||
|
||||
/* ISB - make sure the instruction stream sees it */
|
||||
CP15ISB;
|
||||
}
|
||||
#else
|
||||
void invalidate_icache_all(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FIXME(dhendrix): had unexplainable compilation failure of weak symbols
|
||||
* (in spite of having prototypes and whatnot)... ron's advice is "death
|
||||
* to weak symbols!"
|
||||
*/
|
||||
#if 0
|
||||
/*
|
||||
* Stub implementations for outer cache operations
|
||||
*/
|
||||
void __v7_outer_cache_enable(void)
|
||||
{
|
||||
}
|
||||
void v7_outer_cache_enable(void)
|
||||
__attribute__((weak, alias("__v7_outer_cache_enable")));
|
||||
|
||||
void __v7_outer_cache_disable(void)
|
||||
{
|
||||
}
|
||||
void v7_outer_cache_disable(void)
|
||||
__attribute__((weak, alias("__v7_outer_cache_disable")));
|
||||
|
||||
void __v7_outer_cache_flush_all(void)
|
||||
{
|
||||
}
|
||||
void v7_outer_cache_flush_all(void)
|
||||
__attribute__((weak, alias("__v7_outer_cache_flush_all")));
|
||||
|
||||
void __v7_outer_cache_inval_all(void)
|
||||
{
|
||||
}
|
||||
void v7_outer_cache_inval_all(void)
|
||||
__attribute__((weak, alias("__v7_outer_cache_inval_all")));
|
||||
|
||||
void __v7_outer_cache_flush_range(u32 start, u32 end)
|
||||
{
|
||||
}
|
||||
void v7_outer_cache_flush_range(u32 start, u32 end)
|
||||
__attribute__((weak, alias("__v7_outer_cache_flush_range")));
|
||||
|
||||
void __v7_outer_cache_inval_range(u32 start, u32 end)
|
||||
{
|
||||
}
|
||||
void v7_outer_cache_inval_range(u32 start, u32 end)
|
||||
__attribute__((weak, alias("__v7_outer_cache_inval_range")));
|
||||
#endif
|
5
src/arch/armv7/lib/div.c
Normal file
5
src/arch/armv7/lib/div.c
Normal file
@ -0,0 +1,5 @@
|
||||
void __div0(void); // called from asm so no need for a prototype in a header
|
||||
void __div0(void)
|
||||
{
|
||||
// div by zero
|
||||
}
|
32
src/arch/armv7/lib/div0.c
Normal file
32
src/arch/armv7/lib/div0.c
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* 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
|
||||
*/
|
||||
|
||||
void __div0(void); // called from asm so no need for a prototype in a header
|
||||
|
||||
/* Replacement (=dummy) for GNU/Linux division-by zero handler */
|
||||
void __div0 (void)
|
||||
{
|
||||
extern void hang (void);
|
||||
|
||||
hang();
|
||||
}
|
208
src/arch/armv7/lib/div64.S
Normal file
208
src/arch/armv7/lib/div64.S
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* linux/arch/arm/lib/div64.S
|
||||
*
|
||||
* Optimized computation of 64-bit dividend / 32-bit divisor
|
||||
*
|
||||
* Author: Nicolas Pitre
|
||||
* Created: Oct 5, 2003
|
||||
* Copyright: Monta Vista Software, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// FIXME
|
||||
//#include <linux/linkage.h>
|
||||
#define __LINUX_ARM_ARCH__ 7
|
||||
|
||||
#ifdef __ARMEB__
|
||||
#define xh r0
|
||||
#define xl r1
|
||||
#define yh r2
|
||||
#define yl r3
|
||||
#else
|
||||
#define xl r0
|
||||
#define xh r1
|
||||
#define yl r2
|
||||
#define yh r3
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __do_div64: perform a division with 64-bit dividend and 32-bit divisor.
|
||||
*
|
||||
* Note: Calling convention is totally non standard for optimal code.
|
||||
* This is meant to be used by do_div() from include/asm/div64.h only.
|
||||
*
|
||||
* Input parameters:
|
||||
* xh-xl = dividend (clobbered)
|
||||
* r4 = divisor (preserved)
|
||||
*
|
||||
* Output values:
|
||||
* yh-yl = result
|
||||
* xh = remainder
|
||||
*
|
||||
* Clobbered regs: xl, ip
|
||||
*/
|
||||
|
||||
|
||||
.globl __do_div64;
|
||||
.align 4,0x90
|
||||
__do_div64:
|
||||
|
||||
@ Test for easy paths first.
|
||||
subs ip, r4, #1
|
||||
bls 9f @ divisor is 0 or 1
|
||||
tst ip, r4
|
||||
beq 8f @ divisor is power of 2
|
||||
|
||||
@ See if we need to handle upper 32-bit result.
|
||||
cmp xh, r4
|
||||
mov yh, #0
|
||||
blo 3f
|
||||
|
||||
@ Align divisor with upper part of dividend.
|
||||
@ The aligned divisor is stored in yl preserving the original.
|
||||
@ The bit position is stored in ip.
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz yl, r4
|
||||
clz ip, xh
|
||||
sub yl, yl, ip
|
||||
mov ip, #1
|
||||
mov ip, ip, lsl yl
|
||||
mov yl, r4, lsl yl
|
||||
|
||||
#else
|
||||
|
||||
mov yl, r4
|
||||
mov ip, #1
|
||||
1: cmp yl, #0x80000000
|
||||
cmpcc yl, xh
|
||||
movcc yl, yl, lsl #1
|
||||
movcc ip, ip, lsl #1
|
||||
bcc 1b
|
||||
|
||||
#endif
|
||||
|
||||
@ The division loop for needed upper bit positions.
|
||||
@ Break out early if dividend reaches 0.
|
||||
2: cmp xh, yl
|
||||
orrcs yh, yh, ip
|
||||
subcss xh, xh, yl
|
||||
movnes ip, ip, lsr #1
|
||||
mov yl, yl, lsr #1
|
||||
bne 2b
|
||||
|
||||
@ See if we need to handle lower 32-bit result.
|
||||
3: cmp xh, #0
|
||||
mov yl, #0
|
||||
cmpeq xl, r4
|
||||
movlo xh, xl
|
||||
movlo pc, lr
|
||||
|
||||
@ The division loop for lower bit positions.
|
||||
@ Here we shift remainer bits leftwards rather than moving the
|
||||
@ divisor for comparisons, considering the carry-out bit as well.
|
||||
mov ip, #0x80000000
|
||||
4: movs xl, xl, lsl #1
|
||||
adcs xh, xh, xh
|
||||
beq 6f
|
||||
cmpcc xh, r4
|
||||
5: orrcs yl, yl, ip
|
||||
subcs xh, xh, r4
|
||||
movs ip, ip, lsr #1
|
||||
bne 4b
|
||||
mov pc, lr
|
||||
|
||||
@ The top part of remainder became zero. If carry is set
|
||||
@ (the 33th bit) this is a false positive so resume the loop.
|
||||
@ Otherwise, if lower part is also null then we are done.
|
||||
6: bcs 5b
|
||||
cmp xl, #0
|
||||
moveq pc, lr
|
||||
|
||||
@ We still have remainer bits in the low part. Bring them up.
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz xh, xl @ we know xh is zero here so...
|
||||
add xh, xh, #1
|
||||
mov xl, xl, lsl xh
|
||||
mov ip, ip, lsr xh
|
||||
|
||||
#else
|
||||
|
||||
7: movs xl, xl, lsl #1
|
||||
mov ip, ip, lsr #1
|
||||
bcc 7b
|
||||
|
||||
#endif
|
||||
|
||||
@ Current remainder is now 1. It is worthless to compare with
|
||||
@ divisor at this point since divisor can not be smaller than 3 here.
|
||||
@ If possible, branch for another shift in the division loop.
|
||||
@ If no bit position left then we are done.
|
||||
movs ip, ip, lsr #1
|
||||
mov xh, #1
|
||||
bne 4b
|
||||
mov pc, lr
|
||||
|
||||
8: @ Division by a power of 2: determine what that divisor order is
|
||||
@ then simply shift values around
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz ip, r4
|
||||
rsb ip, ip, #31
|
||||
|
||||
#else
|
||||
|
||||
mov yl, r4
|
||||
cmp r4, #(1 << 16)
|
||||
mov ip, #0
|
||||
movhs yl, yl, lsr #16
|
||||
movhs ip, #16
|
||||
|
||||
cmp yl, #(1 << 8)
|
||||
movhs yl, yl, lsr #8
|
||||
addhs ip, ip, #8
|
||||
|
||||
cmp yl, #(1 << 4)
|
||||
movhs yl, yl, lsr #4
|
||||
addhs ip, ip, #4
|
||||
|
||||
cmp yl, #(1 << 2)
|
||||
addhi ip, ip, #3
|
||||
addls ip, ip, yl, lsr #1
|
||||
|
||||
#endif
|
||||
|
||||
mov yh, xh, lsr ip
|
||||
mov yl, xl, lsr ip
|
||||
rsb ip, ip, #32
|
||||
orr yl, yl, xh, lsl ip
|
||||
mov xh, xl, lsl ip
|
||||
mov xh, xh, lsr ip
|
||||
mov pc, lr
|
||||
|
||||
@ eq -> division by 1: obvious enough...
|
||||
9: moveq yl, xl
|
||||
moveq yh, xh
|
||||
moveq xh, #0
|
||||
moveq pc, lr
|
||||
|
||||
@ Division by 0:
|
||||
str lr, [sp, #-8]!
|
||||
bl __div0
|
||||
|
||||
@ as wrong as it could be...
|
||||
mov yl, #0
|
||||
mov yh, #0
|
||||
mov xh, #0
|
||||
ldr pc, [sp], #8
|
||||
|
||||
@.type __do_div64, @function;
|
||||
@.size __do_div64, .-__do_div64,
|
||||
|
33
src/arch/armv7/lib/eabi_compat.c
Normal file
33
src/arch/armv7/lib/eabi_compat.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Utility functions needed for (some) EABI conformant tool chains.
|
||||
*
|
||||
* (C) Copyright 2009 Wolfgang Denk <wd@denx.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
/* FIXME(dhendrix): prototypes added for assembler */
|
||||
int raise (int signum);
|
||||
int raise (int signum)
|
||||
{
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("raise: Signal # %d caught\n", signum);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dummy function to avoid linker complaints */
|
||||
void __aeabi_unwind_cpp_pr0(void);
|
||||
void __aeabi_unwind_cpp_pr0(void)
|
||||
{
|
||||
};
|
||||
|
||||
void __aeabi_unwind_cpp_pr1(void);
|
||||
void __aeabi_unwind_cpp_pr1(void)
|
||||
{
|
||||
};
|
16
src/arch/armv7/lib/hang_spl.c
Normal file
16
src/arch/armv7/lib/hang_spl.c
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*/
|
||||
|
||||
#include <hang.h>
|
||||
|
||||
void hang(void)
|
||||
{
|
||||
for (;;);
|
||||
}
|
18
src/arch/armv7/lib/id.inc
Normal file
18
src/arch/armv7/lib/id.inc
Normal file
@ -0,0 +1,18 @@
|
||||
.section ".id", "a", %progbits
|
||||
|
||||
.globl __id_start
|
||||
__id_start:
|
||||
ver:
|
||||
.asciz COREBOOT_VERSION
|
||||
vendor:
|
||||
.asciz CONFIG_MAINBOARD_VENDOR
|
||||
part:
|
||||
.asciz CONFIG_MAINBOARD_PART_NUMBER
|
||||
.long __id_end + CONFIG_ID_SECTION_OFFSET - ver /* Reverse offset to the vendor id */
|
||||
.long __id_end + CONFIG_ID_SECTION_OFFSET - vendor /* Reverse offset to the vendor id */
|
||||
.long __id_end + CONFIG_ID_SECTION_OFFSET - part /* Reverse offset to the part number */
|
||||
.long CONFIG_ROM_SIZE /* Size of this romimage */
|
||||
.globl __id_end
|
||||
|
||||
__id_end:
|
||||
.previous
|
6
src/arch/armv7/lib/id.lds
Normal file
6
src/arch/armv7/lib/id.lds
Normal file
@ -0,0 +1,6 @@
|
||||
SECTIONS {
|
||||
. = (0x100000000 - CONFIG_ID_SECTION_OFFSET) - (__id_end - __id_start);
|
||||
.id (.): {
|
||||
*(.id)
|
||||
}
|
||||
}
|
198
src/arch/armv7/lib/interrupts.c
Normal file
198
src/arch/armv7/lib/interrupts.c
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* (C) Copyright 2003
|
||||
* Texas Instruments <www.ti.com>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Alex Zuepke <azu@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002-2004
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* Philippe Robin, ARM Ltd. <philippe.robin@arm.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/proc-armv/ptrace.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifdef CONFIG_USE_IRQ
|
||||
int interrupt_init (void)
|
||||
{
|
||||
/*
|
||||
* setup up stacks if necessary
|
||||
*/
|
||||
IRQ_STACK_START = gd->irq_sp - 4;
|
||||
IRQ_STACK_START_IN = gd->irq_sp + 8;
|
||||
FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
|
||||
|
||||
return arch_interrupt_init();
|
||||
}
|
||||
|
||||
/* enable IRQ interrupts */
|
||||
void enable_interrupts (void)
|
||||
{
|
||||
unsigned long temp;
|
||||
__asm__ __volatile__("mrs %0, cpsr\n"
|
||||
"bic %0, %0, #0x80\n"
|
||||
"msr cpsr_c, %0"
|
||||
: "=r" (temp)
|
||||
:
|
||||
: "memory");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* disable IRQ/FIQ interrupts
|
||||
* returns true if interrupts had been enabled before we disabled them
|
||||
*/
|
||||
int disable_interrupts (void)
|
||||
{
|
||||
unsigned long old,temp;
|
||||
__asm__ __volatile__("mrs %0, cpsr\n"
|
||||
"orr %1, %0, #0xc0\n"
|
||||
"msr cpsr_c, %1"
|
||||
: "=r" (old), "=r" (temp)
|
||||
:
|
||||
: "memory");
|
||||
return (old & 0x80) == 0;
|
||||
}
|
||||
#else
|
||||
int interrupt_init (void)
|
||||
{
|
||||
/*
|
||||
* setup up stacks if necessary
|
||||
*/
|
||||
IRQ_STACK_START_IN = gd->irq_sp + 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enable_interrupts (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int disable_interrupts (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void bad_mode (void)
|
||||
{
|
||||
panic ("Resetting CPU ...\n");
|
||||
reset_cpu (0);
|
||||
}
|
||||
|
||||
void show_regs (struct pt_regs *regs)
|
||||
{
|
||||
unsigned long flags;
|
||||
const char *processor_modes[] = {
|
||||
"USER_26", "FIQ_26", "IRQ_26", "SVC_26",
|
||||
"UK4_26", "UK5_26", "UK6_26", "UK7_26",
|
||||
"UK8_26", "UK9_26", "UK10_26", "UK11_26",
|
||||
"UK12_26", "UK13_26", "UK14_26", "UK15_26",
|
||||
"USER_32", "FIQ_32", "IRQ_32", "SVC_32",
|
||||
"UK4_32", "UK5_32", "UK6_32", "ABT_32",
|
||||
"UK8_32", "UK9_32", "UK10_32", "UND_32",
|
||||
"UK12_32", "UK13_32", "UK14_32", "SYS_32",
|
||||
};
|
||||
|
||||
flags = condition_codes (regs);
|
||||
|
||||
printf ("pc : [<%08lx>] lr : [<%08lx>]\n"
|
||||
"sp : %08lx ip : %08lx fp : %08lx\n",
|
||||
instruction_pointer (regs),
|
||||
regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
|
||||
printf ("r10: %08lx r9 : %08lx r8 : %08lx\n",
|
||||
regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
|
||||
printf ("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
|
||||
regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
|
||||
printf ("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
|
||||
regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
|
||||
printf ("Flags: %c%c%c%c",
|
||||
flags & CC_N_BIT ? 'N' : 'n',
|
||||
flags & CC_Z_BIT ? 'Z' : 'z',
|
||||
flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v');
|
||||
printf (" IRQs %s FIQs %s Mode %s%s\n",
|
||||
interrupts_enabled (regs) ? "on" : "off",
|
||||
fast_interrupts_enabled (regs) ? "on" : "off",
|
||||
processor_modes[processor_mode (regs)],
|
||||
thumb_mode (regs) ? " (T)" : "");
|
||||
}
|
||||
|
||||
void do_undefined_instruction (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("undefined instruction\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_software_interrupt (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("software interrupt\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_prefetch_abort (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("prefetch abort\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_data_abort (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("data abort\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_not_used (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("not used\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_fiq (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("fast interrupt request\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USE_IRQ
|
||||
void do_irq (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("interrupt request\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
#endif
|
243
src/arch/armv7/lib/memcpy.S
Normal file
243
src/arch/armv7/lib/memcpy.S
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* linux/arch/arm/lib/memcpy.S
|
||||
*
|
||||
* Author: Nicolas Pitre
|
||||
* Created: Sep 28, 2005
|
||||
* Copyright: MontaVista Software, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#define W(instr) instr
|
||||
|
||||
#define LDR1W_SHIFT 0
|
||||
#define STR1W_SHIFT 0
|
||||
|
||||
.macro ldr1w ptr reg abort
|
||||
W(ldr) \reg, [\ptr], #4
|
||||
.endm
|
||||
|
||||
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
|
||||
ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
|
||||
.endm
|
||||
|
||||
.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
|
||||
ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
|
||||
.endm
|
||||
|
||||
.macro ldr1b ptr reg cond=al abort
|
||||
ldr\cond\()b \reg, [\ptr], #1
|
||||
.endm
|
||||
|
||||
.macro str1w ptr reg abort
|
||||
W(str) \reg, [\ptr], #4
|
||||
.endm
|
||||
|
||||
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
|
||||
stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
|
||||
.endm
|
||||
|
||||
.macro str1b ptr reg cond=al abort
|
||||
str\cond\()b \reg, [\ptr], #1
|
||||
.endm
|
||||
|
||||
.macro enter reg1 reg2
|
||||
stmdb sp!, {r0, \reg1, \reg2}
|
||||
.endm
|
||||
|
||||
.macro exit reg1 reg2
|
||||
ldmfd sp!, {r0, \reg1, \reg2}
|
||||
.endm
|
||||
|
||||
.text
|
||||
|
||||
/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
|
||||
|
||||
.globl memcpy
|
||||
memcpy:
|
||||
|
||||
cmp r0, r1
|
||||
moveq pc, lr
|
||||
|
||||
enter r4, lr
|
||||
|
||||
subs r2, r2, #4
|
||||
blt 8f
|
||||
ands ip, r0, #3
|
||||
PLD( pld [r1, #0] )
|
||||
bne 9f
|
||||
ands ip, r1, #3
|
||||
bne 10f
|
||||
|
||||
1: subs r2, r2, #(28)
|
||||
stmfd sp!, {r5 - r8}
|
||||
blt 5f
|
||||
|
||||
CALGN( ands ip, r0, #31 )
|
||||
CALGN( rsb r3, ip, #32 )
|
||||
CALGN( sbcnes r4, r3, r2 ) @ C is always set here
|
||||
CALGN( bcs 2f )
|
||||
CALGN( adr r4, 6f )
|
||||
CALGN( subs r2, r2, r3 ) @ C gets set
|
||||
CALGN( add pc, r4, ip )
|
||||
|
||||
PLD( pld [r1, #0] )
|
||||
2: PLD( subs r2, r2, #96 )
|
||||
PLD( pld [r1, #28] )
|
||||
PLD( blt 4f )
|
||||
PLD( pld [r1, #60] )
|
||||
PLD( pld [r1, #92] )
|
||||
|
||||
3: PLD( pld [r1, #124] )
|
||||
4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
|
||||
subs r2, r2, #32
|
||||
str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
|
||||
bge 3b
|
||||
PLD( cmn r2, #96 )
|
||||
PLD( bge 4b )
|
||||
|
||||
5: ands ip, r2, #28
|
||||
rsb ip, ip, #32
|
||||
#if LDR1W_SHIFT > 0
|
||||
lsl ip, ip, #LDR1W_SHIFT
|
||||
#endif
|
||||
addne pc, pc, ip @ C is always clear here
|
||||
b 7f
|
||||
6:
|
||||
.rept (1 << LDR1W_SHIFT)
|
||||
W(nop)
|
||||
.endr
|
||||
ldr1w r1, r3, abort=20f
|
||||
ldr1w r1, r4, abort=20f
|
||||
ldr1w r1, r5, abort=20f
|
||||
ldr1w r1, r6, abort=20f
|
||||
ldr1w r1, r7, abort=20f
|
||||
ldr1w r1, r8, abort=20f
|
||||
ldr1w r1, lr, abort=20f
|
||||
|
||||
#if LDR1W_SHIFT < STR1W_SHIFT
|
||||
lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT
|
||||
#elif LDR1W_SHIFT > STR1W_SHIFT
|
||||
lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT
|
||||
#endif
|
||||
add pc, pc, ip
|
||||
nop
|
||||
.rept (1 << STR1W_SHIFT)
|
||||
W(nop)
|
||||
.endr
|
||||
str1w r0, r3, abort=20f
|
||||
str1w r0, r4, abort=20f
|
||||
str1w r0, r5, abort=20f
|
||||
str1w r0, r6, abort=20f
|
||||
str1w r0, r7, abort=20f
|
||||
str1w r0, r8, abort=20f
|
||||
str1w r0, lr, abort=20f
|
||||
|
||||
CALGN( bcs 2b )
|
||||
|
||||
7: ldmfd sp!, {r5 - r8}
|
||||
|
||||
8: movs r2, r2, lsl #31
|
||||
ldr1b r1, r3, ne, abort=21f
|
||||
ldr1b r1, r4, cs, abort=21f
|
||||
ldr1b r1, ip, cs, abort=21f
|
||||
str1b r0, r3, ne, abort=21f
|
||||
str1b r0, r4, cs, abort=21f
|
||||
str1b r0, ip, cs, abort=21f
|
||||
|
||||
exit r4, pc
|
||||
|
||||
9: rsb ip, ip, #4
|
||||
cmp ip, #2
|
||||
ldr1b r1, r3, gt, abort=21f
|
||||
ldr1b r1, r4, ge, abort=21f
|
||||
ldr1b r1, lr, abort=21f
|
||||
str1b r0, r3, gt, abort=21f
|
||||
str1b r0, r4, ge, abort=21f
|
||||
subs r2, r2, ip
|
||||
str1b r0, lr, abort=21f
|
||||
blt 8b
|
||||
ands ip, r1, #3
|
||||
beq 1b
|
||||
|
||||
10: bic r1, r1, #3
|
||||
cmp ip, #2
|
||||
ldr1w r1, lr, abort=21f
|
||||
beq 17f
|
||||
bgt 18f
|
||||
|
||||
|
||||
.macro forward_copy_shift pull push
|
||||
|
||||
subs r2, r2, #28
|
||||
blt 14f
|
||||
|
||||
CALGN( ands ip, r0, #31 )
|
||||
CALGN( rsb ip, ip, #32 )
|
||||
CALGN( sbcnes r4, ip, r2 ) @ C is always set here
|
||||
CALGN( subcc r2, r2, ip )
|
||||
CALGN( bcc 15f )
|
||||
|
||||
11: stmfd sp!, {r5 - r9}
|
||||
|
||||
PLD( pld [r1, #0] )
|
||||
PLD( subs r2, r2, #96 )
|
||||
PLD( pld [r1, #28] )
|
||||
PLD( blt 13f )
|
||||
PLD( pld [r1, #60] )
|
||||
PLD( pld [r1, #92] )
|
||||
|
||||
12: PLD( pld [r1, #124] )
|
||||
13: ldr4w r1, r4, r5, r6, r7, abort=19f
|
||||
mov r3, lr, pull #\pull
|
||||
subs r2, r2, #32
|
||||
ldr4w r1, r8, r9, ip, lr, abort=19f
|
||||
orr r3, r3, r4, push #\push
|
||||
mov r4, r4, pull #\pull
|
||||
orr r4, r4, r5, push #\push
|
||||
mov r5, r5, pull #\pull
|
||||
orr r5, r5, r6, push #\push
|
||||
mov r6, r6, pull #\pull
|
||||
orr r6, r6, r7, push #\push
|
||||
mov r7, r7, pull #\pull
|
||||
orr r7, r7, r8, push #\push
|
||||
mov r8, r8, pull #\pull
|
||||
orr r8, r8, r9, push #\push
|
||||
mov r9, r9, pull #\pull
|
||||
orr r9, r9, ip, push #\push
|
||||
mov ip, ip, pull #\pull
|
||||
orr ip, ip, lr, push #\push
|
||||
str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
|
||||
bge 12b
|
||||
PLD( cmn r2, #96 )
|
||||
PLD( bge 13b )
|
||||
|
||||
ldmfd sp!, {r5 - r9}
|
||||
|
||||
14: ands ip, r2, #28
|
||||
beq 16f
|
||||
|
||||
15: mov r3, lr, pull #\pull
|
||||
ldr1w r1, lr, abort=21f
|
||||
subs ip, ip, #4
|
||||
orr r3, r3, lr, push #\push
|
||||
str1w r0, r3, abort=21f
|
||||
bgt 15b
|
||||
CALGN( cmp r2, #0 )
|
||||
CALGN( bge 11b )
|
||||
|
||||
16: sub r1, r1, #(\push / 8)
|
||||
b 8b
|
||||
|
||||
.endm
|
||||
|
||||
|
||||
forward_copy_shift pull=8 push=24
|
||||
|
||||
17: forward_copy_shift pull=16 push=16
|
||||
|
||||
18: forward_copy_shift pull=24 push=8
|
126
src/arch/armv7/lib/memset.S
Normal file
126
src/arch/armv7/lib/memset.S
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* linux/arch/arm/lib/memset.S
|
||||
*
|
||||
* Copyright (C) 1995-2000 Russell King
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ASM optimised string functions
|
||||
*/
|
||||
#include <asm/assembler.h>
|
||||
|
||||
.text
|
||||
.align 5
|
||||
.word 0
|
||||
|
||||
1: subs r2, r2, #4 @ 1 do we have enough
|
||||
blt 5f @ 1 bytes to align with?
|
||||
cmp r3, #2 @ 1
|
||||
strltb r1, [r0], #1 @ 1
|
||||
strleb r1, [r0], #1 @ 1
|
||||
strb r1, [r0], #1 @ 1
|
||||
add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
|
||||
/*
|
||||
* The pointer is now aligned and the length is adjusted. Try doing the
|
||||
* memset again.
|
||||
*/
|
||||
|
||||
.globl memset
|
||||
memset:
|
||||
ands r3, r0, #3 @ 1 unaligned?
|
||||
bne 1b @ 1
|
||||
/*
|
||||
* we know that the pointer in r0 is aligned to a word boundary.
|
||||
*/
|
||||
orr r1, r1, r1, lsl #8
|
||||
orr r1, r1, r1, lsl #16
|
||||
mov r3, r1
|
||||
cmp r2, #16
|
||||
blt 4f
|
||||
|
||||
#if ! CALGN(1)+0
|
||||
|
||||
/*
|
||||
* We need an extra register for this loop - save the return address and
|
||||
* use the LR
|
||||
*/
|
||||
str lr, [sp, #-4]!
|
||||
mov ip, r1
|
||||
mov lr, r1
|
||||
|
||||
2: subs r2, r2, #64
|
||||
stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
|
||||
stmgeia r0!, {r1, r3, ip, lr}
|
||||
stmgeia r0!, {r1, r3, ip, lr}
|
||||
stmgeia r0!, {r1, r3, ip, lr}
|
||||
bgt 2b
|
||||
ldmeqfd sp!, {pc} @ Now <64 bytes to go.
|
||||
/*
|
||||
* No need to correct the count; we're only testing bits from now on
|
||||
*/
|
||||
tst r2, #32
|
||||
stmneia r0!, {r1, r3, ip, lr}
|
||||
stmneia r0!, {r1, r3, ip, lr}
|
||||
tst r2, #16
|
||||
stmneia r0!, {r1, r3, ip, lr}
|
||||
ldr lr, [sp], #4
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* This version aligns the destination pointer in order to write
|
||||
* whole cache lines at once.
|
||||
*/
|
||||
|
||||
stmfd sp!, {r4-r7, lr}
|
||||
mov r4, r1
|
||||
mov r5, r1
|
||||
mov r6, r1
|
||||
mov r7, r1
|
||||
mov ip, r1
|
||||
mov lr, r1
|
||||
|
||||
cmp r2, #96
|
||||
tstgt r0, #31
|
||||
ble 3f
|
||||
|
||||
and ip, r0, #31
|
||||
rsb ip, ip, #32
|
||||
sub r2, r2, ip
|
||||
movs ip, ip, lsl #(32 - 4)
|
||||
stmcsia r0!, {r4, r5, r6, r7}
|
||||
stmmiia r0!, {r4, r5}
|
||||
tst ip, #(1 << 30)
|
||||
mov ip, r1
|
||||
strne r1, [r0], #4
|
||||
|
||||
3: subs r2, r2, #64
|
||||
stmgeia r0!, {r1, r3-r7, ip, lr}
|
||||
stmgeia r0!, {r1, r3-r7, ip, lr}
|
||||
bgt 3b
|
||||
ldmeqfd sp!, {r4-r7, pc}
|
||||
|
||||
tst r2, #32
|
||||
stmneia r0!, {r1, r3-r7, ip, lr}
|
||||
tst r2, #16
|
||||
stmneia r0!, {r4-r7}
|
||||
ldmfd sp!, {r4-r7, lr}
|
||||
|
||||
#endif
|
||||
|
||||
4: tst r2, #8
|
||||
stmneia r0!, {r1, r3}
|
||||
tst r2, #4
|
||||
strne r1, [r0], #4
|
||||
/*
|
||||
* When we get here, we've got less than 4 bytes to zero. We
|
||||
* may have an unaligned pointer as well.
|
||||
*/
|
||||
5: tst r2, #2
|
||||
strneb r1, [r0], #1
|
||||
strneb r1, [r0], #1
|
||||
tst r2, #1
|
||||
strneb r1, [r0], #1
|
||||
mov pc, lr
|
53
src/arch/armv7/lib/reset.c
Normal file
53
src/arch/armv7/lib/reset.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Alex Zuepke <azu@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* DAVE Srl
|
||||
* http://www.dave-tech.it
|
||||
* http://www.wawnet.biz
|
||||
* mailto:info@wawnet.biz
|
||||
*
|
||||
* (C) Copyright 2004 Texas Insturments
|
||||
*
|
||||
* 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>
|
||||
|
||||
int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
puts ("resetting ...\n");
|
||||
|
||||
udelay (50000); /* wait 50 ms */
|
||||
|
||||
disable_interrupts();
|
||||
reset_cpu(0);
|
||||
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
75
src/arch/armv7/lib/romstage_console.c
Normal file
75
src/arch/armv7/lib/romstage_console.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of the coreboot 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; version 2 of
|
||||
* the License.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <console/vtxprintf.h>
|
||||
#if CONFIG_SERIAL_CONSOLE
|
||||
#include <uart.h>
|
||||
#endif
|
||||
#if CONFIG_USBDEBUG
|
||||
#include <usbdebug.h>
|
||||
#endif
|
||||
|
||||
/* FIXME: need to make console driver more generic */
|
||||
void console_tx_byte(unsigned char byte)
|
||||
{
|
||||
if (byte == '\n')
|
||||
console_tx_byte('\r');
|
||||
|
||||
#if CONFIG_SERIAL_CONSOLE
|
||||
uart_tx_byte(byte);
|
||||
#endif
|
||||
#if CONFIG_USBDEBUG
|
||||
usbdebug_tx_byte(0, byte);
|
||||
#endif
|
||||
#if CONFIG_CONSOLE_CBMEM
|
||||
cbmemc_tx_byte(byte);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* FIXME(dhendrix): add this back in */
|
||||
#if 0
|
||||
static void console_tx_flush(void)
|
||||
{
|
||||
#if CONFIG_CONSOLE_SERIAL
|
||||
uart_tx_flush(CONFIG_CONSOLE_SERIAL_UART_ADDRESS);
|
||||
#endif
|
||||
#if CONFIG_USBDEBUG
|
||||
usbdebug_tx_flush(0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_printk(int msg_level, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
if (msg_level > console_loglevel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
i = vtxprintf(console_tx_byte, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// console_tx_flush();
|
||||
|
||||
return i;
|
||||
}
|
70
src/arch/armv7/lib/syslib.c
Normal file
70
src/arch/armv7/lib/syslib.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* (C) Copyright 2008
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* Richard Woodruff <r-woodruff2@ti.com>
|
||||
* Syed Mohammed Khasim <khasim@ti.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
|
||||
*/
|
||||
|
||||
//#include <common.h>
|
||||
#include <arch/io.h>
|
||||
#include <system.h> /* FIXME: dumping ground for prototypes */
|
||||
|
||||
/************************************************************
|
||||
* sdelay() - simple spin loop. Will be constant time as
|
||||
* its generally used in bypass conditions only. This
|
||||
* is necessary until timers are accessible.
|
||||
*
|
||||
* not inline to increase chances its in cache when called
|
||||
*************************************************************/
|
||||
void sdelay(unsigned long loops)
|
||||
{
|
||||
__asm__ volatile ("1:\n" "subs %0, %1, #1\n"
|
||||
"bne 1b":"=r" (loops):"0"(loops));
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* sr32 - clear & set a value in a bit range for a 32 bit address
|
||||
*****************************************************************/
|
||||
void sr32(void *addr, u32 start_bit, u32 num_bits, u32 value)
|
||||
{
|
||||
u32 tmp, msk = 0;
|
||||
msk = 1 << num_bits;
|
||||
--msk;
|
||||
tmp = readl((u32)addr) & ~(msk << start_bit);
|
||||
tmp |= value << start_bit;
|
||||
writel(tmp, (u32)addr);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* wait_on_value() - common routine to allow waiting for changes in
|
||||
* volatile regs.
|
||||
*********************************************************************/
|
||||
u32 wait_on_value(u32 read_bit_mask, u32 match_value, void *read_addr,
|
||||
u32 bound)
|
||||
{
|
||||
u32 i = 0, val;
|
||||
do {
|
||||
++i;
|
||||
val = readl((u32)read_addr) & read_bit_mask;
|
||||
if (val == match_value)
|
||||
return 1;
|
||||
if (i == bound)
|
||||
return 0;
|
||||
} while (1);
|
||||
}
|
119
src/arch/armv7/romstage.ld
Normal file
119
src/arch/armv7/romstage.ld
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Memory map:
|
||||
*
|
||||
* CONFIG_RAMBASE : text segment
|
||||
* : rodata segment
|
||||
* : data segment
|
||||
* : bss segment
|
||||
* : stack
|
||||
* : heap
|
||||
*/
|
||||
/*
|
||||
* Bootstrap code for the STPC Consumer
|
||||
* Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Written by Johan Rydberg, based on work by Daniel Kahlin.
|
||||
* Rewritten by Eric Biederman
|
||||
* 2005.12 yhlu add coreboot_ram cross the vga font buffer handling
|
||||
*/
|
||||
|
||||
/* We use ELF as output format. So that we can debug the code in some form. */
|
||||
/*
|
||||
INCLUDE ldoptions
|
||||
*/
|
||||
|
||||
/*
|
||||
* FIXME: what exactly should these be? maybe defined on a per-CPU basis?
|
||||
* FIXME 2: Somehow linker didn't like CONFIG_SPL_MAX_SIZE and CONFIG_SPL_TEXT_BASE...
|
||||
*/
|
||||
/* MEMORY { .sram : ORIGIN = 0x02023400, LENGTH = 0x3800 } */
|
||||
MEMORY { .sram : ORIGIN = 0x02023400, LENGTH = 0x10000 }
|
||||
|
||||
/* We use ELF as output format. So that we can debug the code in some form. */
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = ROMSTAGE_BASE;
|
||||
|
||||
/*
|
||||
.rom . : {
|
||||
_rom = .;
|
||||
*(.rom.text);
|
||||
*(.rom.data);
|
||||
*(.rodata);
|
||||
*(.rodata.*);
|
||||
*(.rom.data.*);
|
||||
. = ALIGN(16);
|
||||
_erom = .;
|
||||
}
|
||||
*/
|
||||
|
||||
/* First we place the code and read only data (typically const declared).
|
||||
* This could theoretically be placed in rom.
|
||||
*/
|
||||
.text : {
|
||||
_text = .;
|
||||
*(.text);
|
||||
*(.text.*);
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
} >.sram
|
||||
|
||||
.rodata : {
|
||||
_rodata = .;
|
||||
. = ALIGN(4);
|
||||
cpu_drivers = . ;
|
||||
*(.rodata.cpu_driver)
|
||||
ecpu_drivers = . ;
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
/* kevinh/Ispiri - Added an align, because the objcopy tool
|
||||
* incorrectly converts sections that are not long word aligned.
|
||||
*/
|
||||
. = ALIGN(4);
|
||||
|
||||
_erodata = .;
|
||||
} >.sram
|
||||
/* After the code we place initialized data (typically initialized
|
||||
* global variables). This gets copied into ram by startup code.
|
||||
* __data_start and __data_end shows where in ram this should be placed,
|
||||
* whereas __data_loadstart and __data_loadend shows where in rom to
|
||||
* copy from.
|
||||
*/
|
||||
.data : {
|
||||
_data = .;
|
||||
*(.data)
|
||||
_edata = .;
|
||||
} >.sram
|
||||
|
||||
__image_copy_end = .;
|
||||
|
||||
/* bss does not contain data, it is just a space that should be zero
|
||||
* initialized on startup. (typically uninitialized global variables)
|
||||
* crt0.S fills between _bss and _ebss with zeroes.
|
||||
*/
|
||||
.bss . : {
|
||||
. = ALIGN(4);
|
||||
_bss = .;
|
||||
*(.bss)
|
||||
*(.sbss)
|
||||
*(COMMON)
|
||||
} >.sram
|
||||
_ebss = .;
|
||||
_end = .;
|
||||
|
||||
/* Discard the sections we don't need/want */
|
||||
/DISCARD/ : {
|
||||
*(.comment)
|
||||
*(.note)
|
||||
*(.comment.*)
|
||||
*(.note.*)
|
||||
*(.eh_frame);
|
||||
}
|
||||
}
|
543
src/arch/armv7/start.S
Normal file
543
src/arch/armv7/start.S
Normal file
@ -0,0 +1,543 @@
|
||||
/*
|
||||
* armboot - Startup Code for OMAP3530/ARM Cortex CPU-core
|
||||
*
|
||||
* Copyright (c) 2004 Texas Instruments <r-woodruff2@ti.com>
|
||||
*
|
||||
* Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
|
||||
* Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
|
||||
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
|
||||
* Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
|
||||
* Copyright (c) 2003 Kshitij <kshitij@ti.com>
|
||||
* Copyright (c) 2006-2008 Syed Mohammed Khasim <x0khasim@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
|
||||
*/
|
||||
|
||||
#define __ASSEMBLY__
|
||||
#include <system.h>
|
||||
|
||||
.globl _start
|
||||
_start: b reset
|
||||
ldr pc, _undefined_instruction
|
||||
ldr pc, _software_interrupt
|
||||
ldr pc, _prefetch_abort
|
||||
ldr pc, _data_abort
|
||||
ldr pc, _not_used
|
||||
ldr pc, _irq
|
||||
ldr pc, _fiq
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
_undefined_instruction: .word _undefined_instruction
|
||||
_software_interrupt: .word _software_interrupt
|
||||
_prefetch_abort: .word _prefetch_abort
|
||||
_data_abort: .word _data_abort
|
||||
_not_used: .word _not_used
|
||||
_irq: .word _irq
|
||||
_fiq: .word _fiq
|
||||
_pad: .word 0x12345678 /* now 16*4=64 */
|
||||
#else
|
||||
_undefined_instruction: .word undefined_instruction
|
||||
_software_interrupt: .word software_interrupt
|
||||
_prefetch_abort: .word prefetch_abort
|
||||
_data_abort: .word data_abort
|
||||
_not_used: .word not_used
|
||||
_irq: .word irq
|
||||
_fiq: .word fiq
|
||||
_pad: .word 0x12345678 /* now 16*4=64 */
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
|
||||
.global _end_vect
|
||||
_end_vect:
|
||||
|
||||
.balignl 16,0xdeadbeef
|
||||
/*************************************************************************
|
||||
*
|
||||
* Startup Code (reset vector)
|
||||
*
|
||||
* do important init only if we don't start from memory!
|
||||
* setup Memory and board specific bits prior to relocation.
|
||||
* relocate armboot to ram
|
||||
* setup stack
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
.globl _TEXT_BASE
|
||||
_TEXT_BASE:
|
||||
.word CONFIG_SYS_TEXT_BASE
|
||||
|
||||
/*
|
||||
* These are defined in the board-specific linker script.
|
||||
*/
|
||||
.globl _bss_start_ofs
|
||||
_bss_start_ofs:
|
||||
.word _bss - _start
|
||||
|
||||
.global _image_copy_end_ofs
|
||||
_image_copy_end_ofs:
|
||||
.word __image_copy_end - _start
|
||||
|
||||
.globl _bss_end_ofs
|
||||
_bss_end_ofs:
|
||||
.word _ebss - _start
|
||||
# .word __bss_end__ - _start
|
||||
|
||||
.globl _end_ofs
|
||||
_end_ofs:
|
||||
.word _end - _start
|
||||
|
||||
#ifdef CONFIG_USE_IRQ
|
||||
/* IRQ stack memory (calculated at run-time) */
|
||||
.globl IRQ_STACK_START
|
||||
IRQ_STACK_START:
|
||||
.word 0x0badc0de
|
||||
|
||||
/* IRQ stack memory (calculated at run-time) */
|
||||
.globl FIQ_STACK_START
|
||||
FIQ_STACK_START:
|
||||
.word 0x0badc0de
|
||||
#endif
|
||||
|
||||
/* IRQ stack memory (calculated at run-time) + 8 bytes */
|
||||
.globl IRQ_STACK_START_IN
|
||||
IRQ_STACK_START_IN:
|
||||
.word 0x0badc0de
|
||||
|
||||
/*
|
||||
* the actual reset code
|
||||
*/
|
||||
|
||||
reset:
|
||||
/* bl save_boot_params */
|
||||
/*
|
||||
* set the cpu to SVC32 mode
|
||||
*/
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #0x1f
|
||||
orr r0, r0, #0xd3
|
||||
msr cpsr,r0
|
||||
|
||||
#if !defined(CONFIG_TEGRA2)
|
||||
/*
|
||||
* Setup vector:
|
||||
* (OMAP4 spl TEXT_BASE is not 32 byte aligned.
|
||||
* Continue to use ROM code vector only in OMAP4 spl)
|
||||
*/
|
||||
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
|
||||
/* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
|
||||
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTRL Register
|
||||
bic r0, #CR_V @ V = 0
|
||||
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTRL Register
|
||||
|
||||
/* Set vector address in CP15 VBAR register */
|
||||
ldr r0, =_start
|
||||
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
|
||||
#endif
|
||||
#endif /* !Tegra2 */
|
||||
|
||||
/* the mask ROM code should have PLL and others stable */
|
||||
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
|
||||
/*
|
||||
* FIXME(dhendrix): Do we need to explicitly disable icache/dcache
|
||||
* first? See example 15-3 in Cortex-A programmers guide...
|
||||
*/
|
||||
bl cpu_init_cp15
|
||||
bl cpu_init_crit
|
||||
#endif
|
||||
|
||||
/* Set stackpointer in internal RAM to call board_init_f */
|
||||
call_board_init_f:
|
||||
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
|
||||
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
|
||||
ldr r0,=0x00000000
|
||||
bl board_init_f
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* void relocate_code (addr_sp, gd, addr_moni)
|
||||
*
|
||||
* This "function" does not return, instead it continues in RAM
|
||||
* after relocating the monitor code.
|
||||
*
|
||||
*/
|
||||
.globl relocate_code
|
||||
relocate_code:
|
||||
mov r4, r0 /* save addr_sp */
|
||||
mov r5, r1 /* save addr of gd */
|
||||
mov r6, r2 /* save addr of destination */
|
||||
|
||||
/* Set up the stack */
|
||||
stack_setup:
|
||||
mov sp, r4
|
||||
|
||||
adr r0, _start
|
||||
subs r9, r6, r0 /* r9 <- relocation offset */
|
||||
beq clear_bss /* skip relocation */
|
||||
mov r1, r6 /* r1 <- scratch for copy_loop */
|
||||
ldr r3, _image_copy_end_ofs
|
||||
add r2, r0, r3 /* r2 <- source end address */
|
||||
|
||||
copy_loop:
|
||||
ldmia r0!, {r9-r10} /* copy from source address [r0] */
|
||||
stmia r1!, {r9-r10} /* copy to target address [r1] */
|
||||
cmp r0, r2 /* until source end address [r2] */
|
||||
blo copy_loop
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
/*
|
||||
* fix .rel.dyn relocations
|
||||
*/
|
||||
ldr r0, _TEXT_BASE /* r0 <- Text base */
|
||||
sub r9, r6, r0 /* r9 <- relocation offset */
|
||||
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
|
||||
add r10, r10, r0 /* r10 <- sym table in FLASH */
|
||||
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
|
||||
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
|
||||
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
|
||||
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
|
||||
fixloop:
|
||||
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
|
||||
add r0, r0, r9 /* r0 <- location to fix up in RAM */
|
||||
ldr r1, [r2, #4]
|
||||
and r7, r1, #0xff
|
||||
cmp r7, #23 /* relative fixup? */
|
||||
beq fixrel
|
||||
cmp r7, #2 /* absolute fixup? */
|
||||
beq fixabs
|
||||
/* ignore unknown type of fixup */
|
||||
b fixnext
|
||||
fixabs:
|
||||
/* absolute fix: set location to (offset) symbol value */
|
||||
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
|
||||
add r1, r10, r1 /* r1 <- address of symbol in table */
|
||||
ldr r1, [r1, #4] /* r1 <- symbol value */
|
||||
add r1, r1, r9 /* r1 <- relocated sym addr */
|
||||
b fixnext
|
||||
fixrel:
|
||||
/* relative fix: increase location by offset */
|
||||
ldr r1, [r0]
|
||||
add r1, r1, r9
|
||||
fixnext:
|
||||
str r1, [r0]
|
||||
add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
|
||||
cmp r2, r3
|
||||
blo fixloop
|
||||
b clear_bss
|
||||
_rel_dyn_start_ofs:
|
||||
.word __rel_dyn_start - _start
|
||||
_rel_dyn_end_ofs:
|
||||
.word __rel_dyn_end - _start
|
||||
_dynsym_start_ofs:
|
||||
.word __dynsym_start - _start
|
||||
|
||||
#endif /* #ifndef CONFIG_SPL_BUILD */
|
||||
|
||||
clear_bss:
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
/* No relocation for SPL */
|
||||
ldr r0, =_bss
|
||||
ldr r1, =_ebss
|
||||
#else
|
||||
ldr r0, _bss_start_ofs
|
||||
ldr r1, _bss_end_ofs
|
||||
mov r4, r6 /* reloc addr */
|
||||
add r0, r0, r4
|
||||
add r1, r1, r4
|
||||
#endif
|
||||
mov r2, #0x00000000 /* clear */
|
||||
|
||||
clbss_l:str r2, [r0] /* clear loop... */
|
||||
add r0, r0, #4
|
||||
cmp r0, r1
|
||||
bne clbss_l
|
||||
|
||||
/*
|
||||
* We are done. Do not return, instead branch to second part of board
|
||||
* initialization, now running from RAM.
|
||||
*/
|
||||
jump_2_ram:
|
||||
/*
|
||||
* If I-cache is enabled invalidate it
|
||||
*/
|
||||
#ifndef CONFIG_SYS_ICACHE_OFF
|
||||
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
|
||||
mcr p15, 0, r0, c7, c10, 4 @ DSB
|
||||
mcr p15, 0, r0, c7, c5, 4 @ ISB
|
||||
#endif
|
||||
ldr r0, _board_init_r_ofs
|
||||
adr r1, _start
|
||||
add lr, r0, r1
|
||||
add lr, lr, r9
|
||||
/* setup parameters for board_init_r */
|
||||
mov r0, r5 /* gd_t */
|
||||
mov r1, r6 /* dest_addr */
|
||||
/* jump to it ... */
|
||||
mov pc, lr
|
||||
|
||||
_board_init_r_ofs:
|
||||
.word board_init_r - _start
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* cpu_init_cp15
|
||||
*
|
||||
* Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on unless
|
||||
* CONFIG_SYS_ICACHE_OFF is defined.
|
||||
*
|
||||
*************************************************************************/
|
||||
.globl cpu_init_cp15
|
||||
cpu_init_cp15:
|
||||
/*
|
||||
* Invalidate L1 I/D
|
||||
*/
|
||||
mov r0, #0 @ set up for MCR
|
||||
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
|
||||
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
|
||||
mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array
|
||||
mcr p15, 0, r0, c7, c10, 4 @ DSB
|
||||
mcr p15, 0, r0, c7, c5, 4 @ ISB
|
||||
|
||||
/*
|
||||
* disable MMU stuff and caches
|
||||
*/
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
|
||||
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
|
||||
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
|
||||
orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
|
||||
#ifdef CONFIG_SYS_ICACHE_OFF
|
||||
bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache
|
||||
#else
|
||||
orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache
|
||||
#endif
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
mov pc, lr @ back to my caller
|
||||
|
||||
|
||||
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
|
||||
/*************************************************************************
|
||||
*
|
||||
* CPU_init_critical registers
|
||||
*
|
||||
* setup important registers
|
||||
* setup memory timing
|
||||
*
|
||||
*************************************************************************/
|
||||
cpu_init_crit:
|
||||
/*
|
||||
* Jump to board specific initialization...
|
||||
* The Mask ROM will have already initialized
|
||||
* basic memory. Go here to bump up clock rate and handle
|
||||
* wake up conditions.
|
||||
*/
|
||||
mov ip, lr @ persevere link reg across call
|
||||
bl lowlevel_init @ go setup pll,mux,memory
|
||||
mov lr, ip @ restore link
|
||||
mov pc, lr @ back to my caller
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
/*
|
||||
*************************************************************************
|
||||
*
|
||||
* Interrupt handling
|
||||
*
|
||||
*************************************************************************
|
||||
*/
|
||||
@
|
||||
@ IRQ stack frame.
|
||||
@
|
||||
#define S_FRAME_SIZE 72
|
||||
|
||||
#define S_OLD_R0 68
|
||||
#define S_PSR 64
|
||||
#define S_PC 60
|
||||
#define S_LR 56
|
||||
#define S_SP 52
|
||||
|
||||
#define S_IP 48
|
||||
#define S_FP 44
|
||||
#define S_R10 40
|
||||
#define S_R9 36
|
||||
#define S_R8 32
|
||||
#define S_R7 28
|
||||
#define S_R6 24
|
||||
#define S_R5 20
|
||||
#define S_R4 16
|
||||
#define S_R3 12
|
||||
#define S_R2 8
|
||||
#define S_R1 4
|
||||
#define S_R0 0
|
||||
|
||||
#define MODE_SVC 0x13
|
||||
#define I_BIT 0x80
|
||||
|
||||
/*
|
||||
* use bad_save_user_regs for abort/prefetch/undef/swi ...
|
||||
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
|
||||
*/
|
||||
|
||||
.macro bad_save_user_regs
|
||||
sub sp, sp, #S_FRAME_SIZE @ carve out a frame on current
|
||||
@ user stack
|
||||
stmia sp, {r0 - r12} @ Save user registers (now in
|
||||
@ svc mode) r0-r12
|
||||
ldr r2, IRQ_STACK_START_IN @ set base 2 words into abort
|
||||
@ stack
|
||||
ldmia r2, {r2 - r3} @ get values for "aborted" pc
|
||||
@ and cpsr (into parm regs)
|
||||
add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack
|
||||
|
||||
add r5, sp, #S_SP
|
||||
mov r1, lr
|
||||
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
|
||||
mov r0, sp @ save current stack into r0
|
||||
@ (param register)
|
||||
.endm
|
||||
|
||||
.macro irq_save_user_regs
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
stmia sp, {r0 - r12} @ Calling r0-r12
|
||||
add r8, sp, #S_PC @ !! R8 NEEDS to be saved !!
|
||||
@ a reserved stack spot would
|
||||
@ be good.
|
||||
stmdb r8, {sp, lr}^ @ Calling SP, LR
|
||||
str lr, [r8, #0] @ Save calling PC
|
||||
mrs r6, spsr
|
||||
str r6, [r8, #4] @ Save CPSR
|
||||
str r0, [r8, #8] @ Save OLD_R0
|
||||
mov r0, sp
|
||||
.endm
|
||||
|
||||
.macro irq_restore_user_regs
|
||||
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
|
||||
mov r0, r0
|
||||
ldr lr, [sp, #S_PC] @ Get PC
|
||||
add sp, sp, #S_FRAME_SIZE
|
||||
subs pc, lr, #4 @ return & move spsr_svc into
|
||||
@ cpsr
|
||||
.endm
|
||||
|
||||
.macro get_bad_stack
|
||||
ldr r13, IRQ_STACK_START_IN @ setup our mode stack (enter
|
||||
@ in banked mode)
|
||||
|
||||
str lr, [r13] @ save caller lr in position 0
|
||||
@ of saved stack
|
||||
mrs lr, spsr @ get the spsr
|
||||
str lr, [r13, #4] @ save spsr in position 1 of
|
||||
@ saved stack
|
||||
|
||||
mov r13, #MODE_SVC @ prepare SVC-Mode
|
||||
@ msr spsr_c, r13
|
||||
msr spsr, r13 @ switch modes, make sure
|
||||
@ moves will execute
|
||||
mov lr, pc @ capture return pc
|
||||
movs pc, lr @ jump to next instruction &
|
||||
@ switch modes.
|
||||
.endm
|
||||
|
||||
.macro get_bad_stack_swi
|
||||
sub r13, r13, #4 @ space on current stack for
|
||||
@ scratch reg.
|
||||
str r0, [r13] @ save R0's value.
|
||||
ldr r0, IRQ_STACK_START_IN @ get data regions start
|
||||
@ spots for abort stack
|
||||
str lr, [r0] @ save caller lr in position 0
|
||||
@ of saved stack
|
||||
mrs r0, spsr @ get the spsr
|
||||
str lr, [r0, #4] @ save spsr in position 1 of
|
||||
@ saved stack
|
||||
ldr r0, [r13] @ restore r0
|
||||
add r13, r13, #4 @ pop stack entry
|
||||
.endm
|
||||
|
||||
.macro get_irq_stack @ setup IRQ stack
|
||||
ldr sp, IRQ_STACK_START
|
||||
.endm
|
||||
|
||||
.macro get_fiq_stack @ setup FIQ stack
|
||||
ldr sp, FIQ_STACK_START
|
||||
.endm
|
||||
|
||||
/*
|
||||
* exception handlers
|
||||
*/
|
||||
.align 5
|
||||
undefined_instruction:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_undefined_instruction
|
||||
|
||||
.align 5
|
||||
software_interrupt:
|
||||
get_bad_stack_swi
|
||||
bad_save_user_regs
|
||||
bl do_software_interrupt
|
||||
|
||||
.align 5
|
||||
prefetch_abort:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_prefetch_abort
|
||||
|
||||
.align 5
|
||||
data_abort:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_data_abort
|
||||
|
||||
.align 5
|
||||
not_used:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_not_used
|
||||
|
||||
#ifdef CONFIG_USE_IRQ
|
||||
|
||||
.align 5
|
||||
irq:
|
||||
get_irq_stack
|
||||
irq_save_user_regs
|
||||
bl do_irq
|
||||
irq_restore_user_regs
|
||||
|
||||
.align 5
|
||||
fiq:
|
||||
get_fiq_stack
|
||||
/* someone ought to write a more effective fiq_save_user_regs */
|
||||
irq_save_user_regs
|
||||
bl do_fiq
|
||||
irq_restore_user_regs
|
||||
|
||||
#else
|
||||
|
||||
.align 5
|
||||
irq:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_irq
|
||||
|
||||
.align 5
|
||||
fiq:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_fiq
|
||||
|
||||
#endif /* CONFIG_USE_IRQ */
|
||||
#endif /* CONFIG_SPL_BUILD */
|
Reference in New Issue
Block a user