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
						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